[
  {
    "path": ".github/workflows/docs_build_deploy.yaml",
    "content": "name: Docs - build and deploy\n\non:\n  push:\n    branches:\n    - master\n    paths:\n    - \"doc/**\"\n\n  workflow_dispatch:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    outputs:\n      artifact_name: ${{ steps.artifact_name.outputs.artifact_name }}\n    permissions:\n      contents: read\n\n    steps:\n    - name: Checkout project\n      uses: actions/checkout@v4\n\n    - name: Set up Python 3.11\n      uses: actions/setup-python@v5\n      with:\n        python-version: \"3.11\"\n        cache: \"pip\"\n\n    - name: Install dependencies\n      working-directory: ./doc\n      run: python3 -m pip install -r requirements.txt\n\n    - name: Build documentation with sphinx-build\n      working-directory: ./doc\n      run: sphinx-build -b html -d build/doctrees source build/html\n\n    - name: Generate artifact name\n      id: artifact_name\n      run: |\n        export AN=docs_html_$(date +'%Y%m%dT%H%M%S')\n        echo Generated artifact name: ${AN}\n        echo \"ARTIFACT_NAME=${AN}\" >> $GITHUB_ENV\n        echo \"artifact_name=${AN}\" >> $GITHUB_OUTPUT\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v4\n      with:\n        name: ${{ env.ARTIFACT_NAME }}\n        path: ./doc/build/html\n        retention-days: 1\n        if-no-files-found: error\n\n  deploy:\n    needs: build\n    runs-on: ubuntu-latest\n    env:\n      ARTIFACT_NAME: ${{ needs.build.outputs.artifact_name }}\n    permissions:\n      actions: read\n\n    steps:\n    - name: Download artifact\n      uses: actions/download-artifact@v4\n      with:\n        name: ${{ env.ARTIFACT_NAME }}\n        path: ./doc\n\n    - name: Configure AWS Credentials\n      uses: aws-actions/configure-aws-credentials@v4\n      with:\n        aws-access-key-id: ${{ secrets.DOC_KEYID }}\n        aws-secret-access-key: ${{ secrets.DOC_SECRET }}\n        aws-region: eu-west-1\n\n    - name: Update target\n      run: |\n        aws s3 sync ./doc s3://quirrel.io/doc\n        aws cloudfront create-invalidation --distribution-id ${{ secrets.DOC_DISTID }} --paths \"/*\"\n"
  },
  {
    "path": ".gitignore",
    "content": "# Folders created at compilation\nbin/\nlib/\n\n# CMake output\nbuild*/\n\n# Folders created at documentation generation\ndoc/build/\n\nRelease/\n.vs/\n*.vcxproj\n*.vcxproj.filters\n*.vcxproj.user\n\n.vscode/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\ncompiler:\n  - gcc\n  - clang\n\n# Travis VMs are 64-bit but we compile both for 32 and 64 bit. To enable the\n# 32-bit builds to work, we need gcc-multilib.\naddons:\n  apt:\n    packages:\n    - gcc-multilib\n    - g++-multilib\n\n# Enable container-based builds.\nsudo: false\n\nscript: mkdir build && cd build && cmake .. && make -j2\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5)\nproject(squirrel VERSION 4.0 LANGUAGES C CXX)\n\noption(ENABLE_VAR_TRACE \"Enable variable change tracing feature.\")\n\nif (NOT CMAKE_BUILD_TYPE)\n  set(CMAKE_BUILD_TYPE \"Release\")\nendif ()\n\ninclude(GNUInstallDirs)\n\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}\")\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY \"${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}\")\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}\")\nset(CMAKE_CXX_STANDARD 17)\n\nif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\n  add_compile_options(\n    \"$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti;-fno-exceptions>\"\n    -fno-strict-aliasing\n    -Wall\n    -Wextra\n    -pedantic\n    -Wcast-qual\n    -Wno-unused-parameter\n    -Wno-missing-field-initializers\n    \"$<$<CONFIG:Release>:-O3>\"\n    \"$<$<CONFIG:RelWithDebInfo>:-O3;-g>\"\n    \"$<$<CONFIG:MinSizeRel>:-Os>\"\n  )\n  # Debug flags\n  if(CMAKE_COMPILER_IS_GNUCXX)\n    add_compile_options(\"$<$<CONFIG:Debug>:-g3;-Og>\")\n  else()\n    # Clang debug flags\n    add_compile_options(\"$<$<CONFIG:Debug>:-g;-Og>\")\n  endif()\nelseif(MSVC)\n  set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)\n  add_definitions(-D_CRT_SECURE_NO_WARNINGS)\n  add_compile_options(/wd4244 /wd4018 /wd4267) # disable type conversion warnings\nendif()\n\nif(CMAKE_SIZEOF_VOID_P EQUAL 8)\n  add_compile_definitions(_SQ64)\nendif()\n\nadd_subdirectory(squirrel)\nadd_subdirectory(squirrel/compiler)\nadd_subdirectory(sqstdlib)\nadd_subdirectory(sqmodules)\nadd_subdirectory(sq)\n\n\ninclude(CMakePackageConfigHelpers)\n\nwrite_basic_package_version_file(\n  \"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-config-version.cmake\"\n  VERSION \"${squirrel_VERSION}\"\n  COMPATIBILITY AnyNewerVersion\n  )\n\nconfigure_package_config_file(\n  \"${CMAKE_CURRENT_SOURCE_DIR}/squirrel-config.cmake.in\"\n  \"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/squirrel/squirrel-config.cmake\"\n  INSTALL_DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/squirrel\"\n  )\n"
  },
  {
    "path": "COPYRIGHT",
    "content": "Copyright (c) 2003-2017 Alberto Demichelis\nCopyright (c) 2016-2024 Gaijin Games KFT\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n-----------------------------------------------------\nEND OF COPYRIGHT\n"
  },
  {
    "path": "HISTORY",
    "content": "***version 4.5.0***\n* add 'let' keyword and unsassignable named bindings\n\n***version 4.4.0***\n* base lib: container methods check object immutability\n* more meaningful error for wrong enum field\n* put 'stream' class into target table instead of root\n  Also expose expicit sqstd_init_streamclass() to allow placing\n  stream class into specific table\n* register base lib as compile-time bindings\n* remove setroottable()/setconsttable() script functions\n* base lib: add println() and errorln() functions\n\n***version 4.3.0 stable***\n* baselib: move some global constants to getbuildinfo() method\n* always use modules in commandline interpreter\n* use compile-time bindings for reference modules implementation\n* check thread-safety during code execution\n* str.indexof and str.contains now throws error on empty substring.\n* (bugfix) don't add object to ref table in GetRefCount()\n* (experimental) new operator ':=' for assignment inside if, for, while, switch\n\n***version 4.2.0 stable***\n* make commas in destructuring assignment optional\n* change constant tables handling by compiler\n  Earlier only enums could be found in compile-time constants. But now we have immutable objects\n\n***version 4.1.0 stable***\n-introduced immutable objects\n-switched to semantic versioning\n-changed SQUIRREL_VERSION_NUMBER to SQUIRREL_VERSION_NUMBER_MAJOR, SQUIRREL_VERSION_NUMBER_MINOR\n  and SQUIRREL_VERSION_PATCH and removed sq_getversion() because of ambiguity of encoding\n  semantic version into single integer number\n\n***version 4.0.0 stable***\n-renamed to Quirrel\n-bumped version\n-lots of changes - see diff_from_original_squirrel\n\n***version 3.2 stable***\n-added sq_tailcall\n-added rawcall keyword\n-added post call initializer syntax\n-added table.keys() and table.values()\n-added table.filter()\n-additional parameters in array.map() and array.apply()\n-additional optional initializer in array.reduce()\n-closure.call() is now a \"native tailcall\" and the invoked function can now be suspended\n-fixed sq_newmember and sq_rawnewmember properly pop parameters\n-fixed capturing free variable on for loop counter before a break statement\n-fixed \\u in lexer\n-various bugfixes\n\n***version 3.1.1 stable***\n-sq_gettypetag doesn't set last error(it's treated as SQBool function but keeps a SQRESULT for backward compatibility)\n-fixed _set method in userdata delegates\n-fixed some warnings\n\n***version 3.1 stable***\n-added slice range for tolower and toupper\n-added startswith() and endswith() in string lib\n-added SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS to exclude default mem fuction from compilation\n-added sq_getreleasehook\n-added thread.wakeupthrow()\n-added sq_pushthread\n-added \\u and \\U escape sequence for UTF8,UTF16 or UCS4 characters\n-added CMake scripts(thx Fabian Wolff)\n-the escape character \\x is based on sizeof(SQChar)\n-fixed several warnings(thx Markus Oberhumer)\n-fixed optimizer bug in compound arith oprators(+=,-= etc...)\n-fixed sq_getrefvmcount() (thx Gerrit)\n-fixed sq_getrefcount() when no references were added with sq_addref() (thx Gerrit)\n-fixed bug in string.tointeger() (thx Domingo)\n-fixed weakref comparison in 32bit builds using doubles(thx Domingo)\n-fixed compiler bug(thx Peter)\n-fixed some error in the documentation(thx Alexander)\n-fixed some error reporting in compiler(thx Alexander)\n-fixed incorrect optional semicolon after \"if block\"(thx Alexander)\n-fixed crash bug in compiler related to compound arith operators(+=,-= etc...) (thx Jeff1)\n\n***2015-01-10      ***\n***version 3.1 RC 1***\n-added new header sqconfig.h for all optional type declarations(unicode, 64bits etc..)\n-added sq_setsharedforeignptr sq_getsharedforeignptr\n-added sq_setsharedreleasehook sq_getsharedreleasehook\n-added escape() in sqstd string library\n-added __LINE__ and __FILE__ (thx mingodad)\n-widechar support on gcc builds\n-now boolean can be used in constants\n-reduced dependencies on C runtime library\n-newthread and sq_newthread() no longer reinitialize the root table on friend VMs(thx Lucas Cardellini)\n-exceptions in the _inherited metamethod are propagated(thx Lucas Cardellini)\n-'in' operator performance improvement(thx unagipai and mingodad)\n-fixes crash in compiler when trying to write 'base'\n-fixed bug in switch statement when using locals as case values (thx mingodad)\n-fixed bug in print()(thx Lucas Cardellini)\n\n***2013-08-30          ***\n***version 3.1 beta 1***\n-added new scoping rule(root attached to closures)\n-added closure.setroot() closure.getroot()\n-added sq_setclosureroot() and sq_getclosureroot()\n-added sq_setvmreleasehook() and sq_getvmreleasehook()\n-added documentaion for sq_getbase()\n-now string.tointeger() accepts an optional parameter 'base'\n-now format accepts zeroes in the format string (thx mingodad)\n-fixed bug in sqstd_createfile() (thx mingodad)\n-minor buxfixes\n\n***2012-11-10          ***\n***version 3.0.4 stable***\n-sq_deleteslot slot now pops the key in case of failure\n-fixed bug when _get metamethod throws null\n-fixed a bug in rstrip\n-added some error handling\n-minor bugfixes\n\n***2012-06-19          ***\n***version 3.1.0 alpha 1***\n-changed in and instanceof operator precendence\n-root object in closures\n-added closure.setroot closure.getroot\n-added sq_setclosureroot and sq_getclosureroot\n\n***version 3.0.3 stable***\n-improved error messages for _cmp(when a non integer value is returned) (thx Yexo)\n-added class.newmember() built in method (thx Nam)\n-added class.rawnewmember()  built in method (thx Nam)\n-added sq_rawnewmember() (thx Nam)\n-added sq_getversion()\n-added sq_typeof()\n-added sq_getclosurename()\n-added file.close() in stdlib\n-documented closure.getinfos() built-in method\n-fixed string iteration doesn't return negative numbers for characters > 127\n-fixed bug in tofloat() when converting a string with scientific notation without a decimal point (thx wr2)\n-fixed potential infinite loop in array.sort() when the _cmp function is inconsistent (thx Yexo)\n-fixed obscure bug in the compiler(thx yishin)\n-fixed some minor bug\n\n***2011-11-28          ***\n***version 3.0.2 stable***\n-added sq_gethash API\n-now array.sort() is implemented with heapsort\n-now floats in scientific notation also accept numbers with no '.' (eg. 1e+6 or 1e6)\n-fixed some warning\n-fixed some documentation\n-fixed bug in GC\n\n***2011-09-08          ***\n***version 3.0.1 stable***\n-added # as alternative symbol for \"line comment\"(mostly useful for shell scripts)\n-added sq_throwobject() to throw an arbitrary object from the C API\n-added alignement flag for userdata types, SQ_ALIGNMENT (thx Shigemasa)\n-added rawset() and rawget() to class and instance default delegate\n-changed bytecode format now ensures matching integer size and float size\n-now inherited classes also inherit userdatasize\n-added SQUIRREL_VERSION_NUMBER in squirrel.h and _versionnumber_ global symbol\n-fixed sq_getmemberhandle\n-fixed sq_getrefcount\n-refactored some sqstdio code\n-refactored some clone code\n-refactored some stuff in the string lib\n-added -s and -fno-exceptions in GCC makefile(better performance when using GCC)\n\n***2011-03-13        ***\n***version 3.0 stable***\n-added sq_getcallee()\n-sq_getfreevariable() also works for native closures\n-minior optimizations\n-removed several warning when compiling with GCC 4.x\n-fixed some errors in the documentation\n-fixed bug when using SQUSEDOUBLE and 32bits intengers\n-fixed bug when invoking generators with closure.call() (thx huntercool)\n\n***2010-12-19                           ***\n***version 3.0 release candidate 1(RC 1)***\n-improved metamethods error handling\n-added parameter 'isstatic' to _newmember metamethod(thx G.Meyer)\n-added sq_getrefcount() to return number of refences from C++(thx G.Meyer)\n\n***2010-11-07        ***\n***version 3.0 beta 3***\n-license changed to \"MIT license\"\n-added sq_resurrectunreachable() and resurrectunreachable()\n-added callee() built in function, returns the current running closure\n-added thread.getstackinfos()\n-added sq_objtouserpointer()\n-added sq_newtableex()\n-various refactoring and optimizations\n-fixed several 64bits issues regarding integer to string conversions\n-fixed some bugs when SQUSEDOUBLE is used in 32bits systems\n\n***2010-08-18          ***\n***version 3.0 beta 2.1***\n-fixed bug in class constructor\n-fixed bug in compound arith\n\n***2010-08-12        ***\n***version 3.0 beta 2***\n-class methods can be added or replaced after the class as been instantiated\n-JSON compliant table syntax, this is currently an experimental feature (thx atai)\n-sq_getsize() now returns userdatasize for classes and instances\n-now setroottable() and setconsttable() return the previous value of the respective table\n-fixed bug in compound arith operators when used on a free variable (thx ellon)\n-fixed some x64 minor bugs\n-fixed minor bug in the compiler\n-refactored some VM internals\n-documented sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes\n\n***2009-11-15        ***\n***version 3.0 beta 1***\n-various refactoring and optimizations\n-fixed bug in free variables (thx mokehehe)\n-fixed bug in functions with default parameters (thx ara & Yexo)\n-fixed bug in exception handling\n-improved error propagation in _set and _get metamethods ( and 'throw null' for clean failure)\n-added sq_getmemberhandle, sq_getbyhandle, sq_setbyhandle to set and get value from classes\n\n***2009-06-30         ***\n***version 3.0 alpha 2***\n-added real free variables(thx Paul Ruizendaal)\n-added refactored function call implementation and compiler(thx Paul Ruizendaal)\n-added sq_getfunctioninfo\n-added compile time flag SQUSEDOUBLE to use double precision floats\n-added global slot _floatsize_ int the base lib to recognize single precision and double precision builds\n-sq_wakeupvm can now resume the vm with an exception\n-added sqstd_format\n-now blobs can be cloned\n-generators can now be instantiated by calling sq_call() or closure.call()\n-fixed debughook bug\n-fixed cooroutine error propagation\n\n***2008-07-23         ***\n***version 3.0 alpha 1***\n-first branch from 2.x source tree\n-added 'base' keyword\n-removed 'delegate' keyword\n-now compiled scripts are vararg functions\n-added setdelegate() and getdelegate() table builtin methods\n-added <=> 3 ways compare operator\n-added lambda expression @(a,b) a + b\n-added local function statement\n-added array built-in map(),reduce(),apply(),filter() and find()\n-generators hold only a weak reference of the enviroment object\n-removed 'vargv' and 'vargc' keywords\n-now var args are passed as an array called vargv(as a paramter)\n-removed 'parent' keyword\n-added class getbase() built in method\n-instanceof doesn't throw an exception if the left expression is not a class\n-lexical scoping for free variables(free variables are no longer in the second parameter list)\n-sq_setprintfunc accept error func\n-sq_geterrorfunc()\n-added sq_arrayremove() and sq_arrayinsert()\n-error() built in function(works like print but prints using the errorfunc)\n-added native debug hook\n\n***2008-02-17        ***\n***version 2.2 stable***\n-added _newslot metamethod in classes\n-added enums added constants\n-added sq_pushconsttable, sq_setconsttable\n-added default param\n-added octal literals(thx Dinosaur)\n-fixed debug hook, 'calls' and 'returns' are properly notified in the same number.\n-fixed a coroutine bug\n\n***2007-07-29          ***\n***version 2.1.2 stable***\n-new behaviour for generators iteration using foreach\nnow when a generator is iterated by foreach the value returned by a 'return val' statement\nwill terminate the iteration but will not be returned as foreach iteration\n-added sq_setclassudsize()\n-added sq_clear()\n-added table.clear(), array.clear()\n-fixed sq_cmp() (thx jyuill)\n-fixed minor bugs\n\n***2006-08-21          ***\n***version 2.1.1 stable***\n-vm refactoring\n-optimized internal function memory layout\n-new global symbol _version_ (is the version string)\n-code size optimization for float literals(on 32bits float builts)\n-now the raw ref API(sq_addref etc...) is fully reentrant.\n-fixed a bug in sq_getdelegate() now pushes null if the object doesn't have a delegate(thx MatzeB)\n-improved C reference performances in NO_GARBAGE_COLLECTOR builds\n-sq_getlocal() now enumerates also outer values.\n-fixed regexp library for GCC users.\n\n***2006-03-19        ***\n***version 2.1 stable***\n-added static class fields, new keyword static\n-added 64bits architecture support\n-added global slot _intsize_ int the base lib to recognize 32bits and 64bits builds\n-added functions with fixed environment, closure.bindenv() built-in function\n-all types except userdata and null implement the tostring() method\n-string concatenation now invokes metamethod _tostring\n-new metamethods for class objects _newmember and _inherited\n-sq_call() sq_resume() sq_wakeupvm() have a new signature\n-new C referencing implementation(scales more with the amount of references)\n-refactored hash table\n-new api functions sq_newslot(),sq_tobool(),sq_getbase(), sq_instanceof(), sq_bindenv()\n-the api func sq_createslot was deprecated but still supported in form of C macro on top of sq_newslot\n-sq_setreleasehook() now also works for classes\n-stream.readstr() and stream.writestr() have been deprecated(this affects file and blob)\n-fixed squirrel.h undeclared api calls\n-fixed few minor bugs\n-SQChar is now defined as wchar_t\n-removed warning when building with -Wall -pedantic for GCC users\n-added new std io function writeclosuretofile()\n-added new std string functions strip(),rstrip(),lstrip() and split()\n-regular expressions operators (+,*) now have more POSIX greedyness behaviour\n-class constructors are now invoked as normal functions\n\n***2005-10-02          ***\n***version 2.0.5 stable***\n-fixed some 64bits incompatibilities (thx sarge)\n-fixed minor bug in the stdlib format() function (thx Rick)\n-fixed a bug in dofile() that was preventing to compile empty files\n-added new API sq_poptop() & sq_getfreevariable()\n-some performance improvements\n\n***2005-08-14          ***\n***version 2.0.4 stable***\n-weak references and related API calls\n-added sq_objtobool()\n-class instances memory policies improved(1 mem allocation for the whole instance)\n-typetags are now declared as SQUserPointer instead of unsigned int\n-first pass for 64bits compatibility\n-fixed minor bug in the stdio stream\n-fixed a bug in format()\n-fixed bug in string.tointeger() and string.tofloat()\n\n***2005-06-24          ***\n***version 2.0.3 stable***\n-dofile() and loadfile() in the iolib now can decode ASCII, UTF8 files UCS2 big-endian and little-endian\n-sq_setparamscheck() : now typemesk can check for null\n-added string escape sequence \\xhhhh\n-fixed some C++ standard incompatibilities\n\n***2005-05-15          ***\n***version 2.0.2 stable***\n-performances improvements (expecially for GCC users)\n-removed all dependencies from C++ exception handling\n-various bugfixes\n\n***2005-04-12        ***\n***version 2.0.1 stable***\n-various bugfixes\n-sq_setparamscheck() now allows spaces in the typemask\n\n***2005-04-03        ***\n***version 2.0 stable***\n-added API sq_gettypetag()\n-added built-in function to the bool type(tointeger, tostring etc...)\n\n***2005-02-27                           ***\n***version 2.0 release candidate 1(RC 1)***\n-added API sq_reseterror()\n-modified sq_release()\n-now class instances can be cloned\n-various bufixes\n\n***2005-01-26        ***\n***version 2.0 beta 1***\n-added bool type\n-class properties can be redefined in a derived class\n-added ops *= /= and %=\n-new syntax for class attributes declaration </ and /> instead of ( and )\n-increased the max number of literals per function from 65535 to 16777215\n-now free variables have proper lexical scoping\n-added API sq_createinstance(), sq_pushbool(), sq_getbool()\n-added built-in function type()\n-added built-in function obj.rawin(key) in table,class and instance\n-sq_rawget() and sq_rawset() now work also on classes and instances\n-the VM no longer uses C++ exception handling (more suitable for embedded devices)\n-various bufixes\n\n***2004-12-21         ***\n***version 2.0 alpha 2***\n-globals scoping changed, now if :: is omitted the VM automatically falls back on the root table\n-various bufixes\n-added class level attributes\n\n***2004-12-12         ***\n***version 2.0 alpha 1***\n-codebase branch from version 1.x\n-added classes\n-added functions with variable number of parameters(vargc & vargv and the ...)\n-0 and 0.0 are now considered 'false' by all conditional statements(if,while,for,?,do-while)\n-added new api functions sq_newclass() sq_setinstanceup() sq_getinstanceup() sq_getattributes() sq_setattributes()\n-modified api sq_settypetag()\n\n***2004-11-01        ***\n***version 1.0 stable***\n-fixed some minor bug\n-improved operator 'delete' performances\n-added scientific notation for float numbers( eg. 2.e16 or 2.e-2)\n\n***2004-08-30        ***\n***version 1.0 release candidate 2(RC 2)***\n-fixed bug in the vm(thx Pierre Renaux)\n-fixed bug in the optimizer(thx Pierre Renaux)\n-fixed some bug in the documentation(thx JD)\n-added new api functions for raw object handling\n-removed nested multiline comments\n-reduced memory footprint in C references\n\n***2004-08-23        ***\n***version 1.0 release candidate 1(RC 1)***\n-fixed division by zero\n-the 'in' operator and obj.rawget() do not query the default delegate anymore\n-added function sq_getprintfunc()\n-added new standard library 'auxlib'(implements default error handlers)\n\n***2004-07-12        ***\n***version 1.0 beta 4***\n-fixed a bug in the integer.tochar() built-in method\n-fixed unary minus operator\n-fixed bug in dofile()\n-fixed inconsistency between != and == operators(on float/integer comparison)\n-added javascript style unsigned right shift operator '>>>'\n-added array(size) constructor built-in function\n-array.resize(size,[fill]) built-in function accepts an optional 'fill' value\n-improved debug API, added sq_getclosureinfo() and sq_setnativeclosurename()\n\n***2004-05-23        ***\n***version 1.0 beta 3***\n-minor vm bug fixes\n-string allocation is now faster\n-tables and array memory usage is now less conservative(they shrink)\n-added regular expression routines in the standard library\n-The 'c' expression now accepts only 1 character(thx irbrian)\n-multiline strings <[ ]> have been substituted with C# style verbatim strings (eg. @\"string\")\n-added new keyword 'parent' for accessing the delegate of tables and unserdata\n-The metamethod '_clone' has been renamed '_cloned'\n-the _delslot metamethod's behaviour and prototype have been changed\n-new default function in the integer and float object 'tochar()'\n-the built-in function chcode2string has been removed\n-the default method [table].getdelegate() has been removed\n-new api sq_rawdeleteslot()\n-new table built-in method rawdelete(key)\n-the dynamic mudule loading has been removed from the standard distribution\n-some optimizations in the VM\n\n***2004-04-21        ***\n***version 1.0 beta 2***\n-minor compiler/parser bug fixes\n-sq_newclosure has a different prototype, the \"paramscheck\" of paramter has been moved to the new function sq_setparamscheck()\n-sq_setparamscheck allows to add automatic parameters type checking in native closures\n-sq_compile() lost the lineinfo parameter\n-new api sq_enabledebuginfo() globally sets compiler's debug info generation\n-added consistency check on bytecode serialization\n-fixed += operator, now works on strings like +\n-added global slot in the base lib _charsize_ to recognize unicode builds from ascii builds runtime\n-added registry table\n-new api call sq_pushregistrytable()\n-added type tag to the userdata type sq_settypetag()\n-sq_getuserdata now queries the userdata typetag\n-the built in function collect_garbage() as been renamed collectgarbage() for consistency reasons\n-new standard libraries(sqlibs are now obsolete)\n\n***2004-02-20        ***\n***version 1.0 beta 1***\n-fixed a bug in the compiler (thanks Martin Kofler)\n-fixed bug in the switch case statement\n-fixed the _unm metamethod\n-fixed minor bugs in the API\n-fixed automatic stack resizing\n-first beta version\n    first pass code clean up in the VM and base lib\n    first pass code coverege test has been done on VM and built-in lib\n-new VM creation API sq_open() sq_close() (sq_newvm and sq_releasevm are now obsolete)\n-new api allows to specifiy a \"print\" function to output text(sq_printfunc)\n-added some small optimizations\n-new cooperative multi-threading capabilities in the base library(coroutines), VMs are now a built in type(\"thread\")\n-new built in functions have been added for manipulating the new \"thread\" type\n-friend virtual machines share the same root table, error handler and debug hook by default\n-new compile time options\n\n***2004-01-19       ***\n***version 0.9 alpha***\n-fixed a garbage collection bug\n-fixed some API bugs(thanks to Joshua Jensen)\n-fixed tail calls (in the version 0.8 the tail call optimization was erroneously disabled)\n-new function parameters semantic, now passing a wrong number of parameters generates an exception\n-native closures have now a built in parameter number checking\n-sq_rawget and sq_rawset now work also on arrays\n-sq_getsize now woks also on userdata\n-the userdata release hook prototype is changed(now passes the size of the userdata)\n-the lexer reader function now returns an integer instead of a char that allows better error checking on the input(thx Joshua Jensen)\n-faster compiler\n-try/catch blocks do not cause any runtime memory allocation anymore\n\n***2003-12-06       ***\n***version 0.8 alpha***\n-fixed a bug that was preventing to have callable userdata throught the metamethod _call\n-fixed a garbage collection bug\n-fixed == operator now can compare correctly different types\n-new built in method getstackinfos(level)\n-improved line informations precision for the debug hook\n-new api call sq_compilebuffer()\n-new built-in api function compilestring()\n-new syntactic sugar for function declarations inside tables\n-the debug API has been finalized\n\n***2003-11-17       ***\n***version 0.7 alpha***\n-fixed critical bug SQInteger the tail call system\n-fixed bug in the continue statement code generation\n-fixed func call param issue(thanks to Rewoonenco Andrew)\n-added _delslot metamethod(thanks to Rewoonenco Andrew)\n-new multiline string expression ( delimited by <[ and ]> )\n-normal strings (\"\") do not allow embedded new line anymore\n-reduced vm memory footprint(C refs are shared between friend VMs)\n-new api method sq_deleteslot()\n-new debug hook event 'r' is triggered when a function returns\n\n***2003-11-04       ***\n***version 0.6 alpha***\n-fixed switch statement(was executing the default case after a break)\n-sq_call() doesn't pop the closure (just the params)\n-the vm execution can be suspended from the C API anytime (micro-threads)\n-new api calls sq_suspendvm() sq_wakeupvm() sq_getvmstate() and sq_reservestack()\n\n***2003-10-13       ***\n***version 0.5 alpha***\n-fixed some minor bug\n-tested with non ASCII identifiers in unicode mode(I've tried chinese chars)\n-added built-in function string.find()\n-the built-in function array.sort() optionally accepts a cmp(a,b) function\n-the debug hook function now has a new prototype debug_hook(event_type,sourcefile,line,functionname)\n-fixed some debug info imprecision\n\n***2003-10-01       ***\n***version 0.4 alpha***\n-faster VM\n-sq_call will pop arguments and closure also in case of failure\n-fixed a bug in sq_remove\n-now the VM detects delegation cycles(and throws an exception)\n-new operators ++ and --\n-new operator ',' comma operator\n-fixed some expression precedence issue\n-fixed bug in sq_arraypop\n\n***2003-09-15       ***\n***version 0.3 alpha***\n-fixed a bug in array::insert()\n-optional Unicode core(define SQUNICODE or _UNICODE on Win32)\n-sq_compiler uses a new reader function SQLEXREADFUNC\n-the debug hook passes 'l' instead of 'line' for line callbacks\n    and 'c' instead of 'call' for call callbacks\n-new array.extend() bulit-in function\n-new API sq_clone()\n\n***2003-09-10           ***\n***version 0.2 pre-alpha***\n-new completely reentrant VM (sq_open and sq_close are now obsolete)\n-sq_newvm() has a new prototype\n-allocators are now global and linked in the VM\n-_newslot meta method added\n-rawset creates a slot if doesn't exists\n-the compiler error callback pass the vm handle(thanks Pierre Renaux)\n-sq_setforeignptr() sq_getforeingptr() are now public\n-sq_resume() now is possible to resume generators from C\n-sq_getlasterror() retrieve the last thrown error\n-improved docs\n\n***2003-09-06           ***\n***version 0.1 pre-alpha***\nfirst release\n"
  },
  {
    "path": "README.md",
    "content": "# Quirrel\n\nQuirrel is a fast, high-level imperative programming language, designed to be a lightweight but powerful\nscripting tool that fits within the size, memory bandwidth, and real-time requirements of\napplications like games.\n\nIt is a mature scripting language used in dozens of games and other apps\n(including web servers and embeddable platforms)\nwith hundreds of millions of installations.\nMillions of devices are running Quirrel VMs daily.\n\nQuirrel has simple integration and bindings into any C++ application.\n\nQuirrel has C/Java/C++-like syntax with a clear, rich and simple type system,\nbut the language has a very dynamic nature like Python/Lua/JavaScript.\nEasy to start while being much safer than Lua and JS, with equal performance to Lua.\nThe whole [syntax and documentation](http://quirrel.io/doc/reference/language.html) can be read in approximately an hour.\n\nIt is based on the [Squirrel scripting language](http://www.squirrel-lang.org/), but modified to be safer, stricter and faster.\nIt branched off as a separate language in 2019.\nGaijin Entertainment has used Squirrel with modifications since 2006, transitioning to Quirrel since 2019,\nacross all its projects and platforms (X360, PS3, PS4, XBoxOne, Switch, iOS, Android, Windows/Mac/Linux PC).\n\nQuirrel offers a wide range of features like dynamic typing, higher order functions, generators,\ntail recursion, exception handling, coroutines, automatic memory management,\nmodules with hot reload, static code analysis.\n\nFeedback, PRs and suggestions are appreciated!\n\n[Documentation project page](http://quirrel.io)\n\n[GitHub page](https://github.com/GaijinEntertainment/quirrel)\n"
  },
  {
    "path": "appveyor.yml",
    "content": "version: 0.0.{build}\n\nplatform:\n - x86\n - x64\n\nconfiguration:\n - Debug\n - Release\n\nclone_folder: c:\\sq\n\nbefore_build:\n - mkdir build\n - cd build\n - call \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" %platform%\n - echo %platform%\n - if %platform%==X64 (cmake .. -G \"Visual Studio 14 2015 Win64\")\n - if %platform%==x86 (cmake .. -G \"Visual Studio 14 2015\")\n\nbuild_script:\n - cmake --build . --config %configuration% -- /logger:\"C:\\Program Files\\AppVeyor\\BuildAgent\\Appveyor.MSBuildLogger.dll\"\n\nartifacts:\n - path: build\\*\\%configuration%\\*.exe\n - path: build\\*\\%configuration%\\*.dll\n\ntest: off\n"
  },
  {
    "path": "doc/.gitignore",
    "content": "build\n*.pyc\n"
  },
  {
    "path": "doc/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nPAPER         =\nBUILDDIR      = build\n\n# User-friendly check for sphinx-build\nifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)\n$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)\nendif\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source\n# the i18n builder cannot share the environment and doctrees with the others\nI18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source\n\n.PHONY: help\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  html       to make standalone HTML files\"\n\t@echo \"  dirhtml    to make HTML files named index.html in directories\"\n\t@echo \"  singlehtml to make a single large HTML file\"\n\t@echo \"  pickle     to make pickle files\"\n\t@echo \"  json       to make JSON files\"\n\t@echo \"  htmlhelp   to make HTML files and a HTML help project\"\n\t@echo \"  qthelp     to make HTML files and a qthelp project\"\n\t@echo \"  applehelp  to make an Apple Help Book\"\n\t@echo \"  devhelp    to make HTML files and a Devhelp project\"\n\t@echo \"  epub       to make an epub\"\n\t@echo \"  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  latexpdf   to make LaTeX files and run them through pdflatex\"\n\t@echo \"  latexpdfja to make LaTeX files and run them through platex/dvipdfmx\"\n\t@echo \"  text       to make text files\"\n\t@echo \"  man        to make manual pages\"\n\t@echo \"  texinfo    to make Texinfo files\"\n\t@echo \"  info       to make Texinfo files and run them through makeinfo\"\n\t@echo \"  gettext    to make PO message catalogs\"\n\t@echo \"  changes    to make an overview of all changed/added/deprecated items\"\n\t@echo \"  xml        to make Docutils-native XML files\"\n\t@echo \"  pseudoxml  to make pseudoxml-XML files for display purposes\"\n\t@echo \"  linkcheck  to check all external links for integrity\"\n\t@echo \"  doctest    to run all doctests embedded in the documentation (if enabled)\"\n\t@echo \"  coverage   to run coverage check of the documentation (if enabled)\"\n\n.PHONY: clean\nclean:\n\trm -rf $(BUILDDIR)/*\n\n.PHONY: html\nhtml:\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/html.\"\n\n.PHONY: dirhtml\ndirhtml:\n\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/dirhtml.\"\n\n.PHONY: singlehtml\nsinglehtml:\n\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml\n\t@echo\n\t@echo \"Build finished. The HTML page is in $(BUILDDIR)/singlehtml.\"\n\n.PHONY: pickle\npickle:\n\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle\n\t@echo\n\t@echo \"Build finished; now you can process the pickle files.\"\n\n.PHONY: json\njson:\n\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json\n\t@echo\n\t@echo \"Build finished; now you can process the JSON files.\"\n\n.PHONY: htmlhelp\nhtmlhelp:\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in $(BUILDDIR)/htmlhelp.\"\n\n.PHONY: qthelp\nqthelp:\n\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp\n\t@echo\n\t@echo \"Build finished; now you can run \"qcollectiongenerator\" with the\" \\\n\t      \".qhcp project file in $(BUILDDIR)/qthelp, like this:\"\n\t@echo \"# qcollectiongenerator $(BUILDDIR)/qthelp/testy_sphinxy.qhcp\"\n\t@echo \"To view the help file:\"\n\t@echo \"# assistant -collectionFile $(BUILDDIR)/qthelp/testy_sphinxy.qhc\"\n\n.PHONY: applehelp\napplehelp:\n\t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp\n\t@echo\n\t@echo \"Build finished. The help book is in $(BUILDDIR)/applehelp.\"\n\t@echo \"N.B. You won't be able to view it unless you put it in\" \\\n\t      \"~/Library/Documentation/Help or install it in your application\" \\\n\t      \"bundle.\"\n\n.PHONY: devhelp\ndevhelp:\n\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp\n\t@echo\n\t@echo \"Build finished.\"\n\t@echo \"To view the help file:\"\n\t@echo \"# mkdir -p $$HOME/.local/share/devhelp/testy_sphinxy\"\n\t@echo \"# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/testy_sphinxy\"\n\t@echo \"# devhelp\"\n\n.PHONY: epub\nepub:\n\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub\n\t@echo\n\t@echo \"Build finished. The epub file is in $(BUILDDIR)/epub.\"\n\n.PHONY: latex\nlatex:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in $(BUILDDIR)/latex.\"\n\t@echo \"Run \\`make' in that directory to run these through (pdf)latex\" \\\n\t      \"(use \\`make latexpdf' here to do that automatically).\"\n\n.PHONY: latexpdf\nlatexpdf:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through pdflatex...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\n.PHONY: latexpdfja\nlatexpdfja:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through platex and dvipdfmx...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\n.PHONY: text\ntext:\n\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text\n\t@echo\n\t@echo \"Build finished. The text files are in $(BUILDDIR)/text.\"\n\n.PHONY: man\nman:\n\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man\n\t@echo\n\t@echo \"Build finished. The manual pages are in $(BUILDDIR)/man.\"\n\n.PHONY: texinfo\ntexinfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo\n\t@echo \"Build finished. The Texinfo files are in $(BUILDDIR)/texinfo.\"\n\t@echo \"Run \\`make' in that directory to run these through makeinfo\" \\\n\t      \"(use \\`make info' here to do that automatically).\"\n\n.PHONY: info\ninfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo \"Running Texinfo files through makeinfo...\"\n\tmake -C $(BUILDDIR)/texinfo info\n\t@echo \"makeinfo finished; the Info files are in $(BUILDDIR)/texinfo.\"\n\n.PHONY: gettext\ngettext:\n\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale\n\t@echo\n\t@echo \"Build finished. The message catalogs are in $(BUILDDIR)/locale.\"\n\n.PHONY: changes\nchanges:\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes\n\t@echo\n\t@echo \"The overview file is in $(BUILDDIR)/changes.\"\n\n.PHONY: linkcheck\nlinkcheck:\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in $(BUILDDIR)/linkcheck/output.txt.\"\n\n.PHONY: doctest\ndoctest:\n\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest\n\t@echo \"Testing of doctests in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/doctest/output.txt.\"\n\n.PHONY: coverage\ncoverage:\n\t$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage\n\t@echo \"Testing of coverage in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/coverage/python.txt.\"\n\n.PHONY: xml\nxml:\n\t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml\n\t@echo\n\t@echo \"Build finished. The XML files are in $(BUILDDIR)/xml.\"\n\n.PHONY: pseudoxml\npseudoxml:\n\t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml\n\t@echo\n\t@echo \"Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml.\"\n"
  },
  {
    "path": "doc/make.bat",
    "content": "@ECHO OFF\r\n\r\nREM Command file for Sphinx documentation\r\n\r\nif \"%SPHINXBUILD%\" == \"\" (\r\n    set SPHINXBUILD=sphinx-build\r\n)\r\nset BUILDDIR=build\r\nset ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source\r\nset I18NSPHINXOPTS=%SPHINXOPTS% source\r\nif NOT \"%PAPER%\" == \"\" (\r\n    set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%\r\n    set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%\r\n)\r\n\r\nif \"%1\" == \"\" goto help\r\n\r\nif \"%1\" == \"help\" (\r\n    :help\r\n    echo.Please use `make ^<target^>` where ^<target^> is one of\r\n    echo.  html       to make standalone HTML files\r\n    echo.  dirhtml    to make HTML files named index.html in directories\r\n    echo.  singlehtml to make a single large HTML file\r\n    echo.  pickle     to make pickle files\r\n    echo.  json       to make JSON files\r\n    echo.  htmlhelp   to make HTML files and a HTML help project\r\n    echo.  qthelp     to make HTML files and a qthelp project\r\n    echo.  devhelp    to make HTML files and a Devhelp project\r\n    echo.  epub       to make an epub\r\n    echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\r\n    echo.  text       to make text files\r\n    echo.  man        to make manual pages\r\n    echo.  texinfo    to make Texinfo files\r\n    echo.  gettext    to make PO message catalogs\r\n    echo.  changes    to make an overview over all changed/added/deprecated items\r\n    echo.  xml        to make Docutils-native XML files\r\n    echo.  pseudoxml  to make pseudoxml-XML files for display purposes\r\n    echo.  linkcheck  to check all external links for integrity\r\n    echo.  doctest    to run all doctests embedded in the documentation if enabled\r\n    echo.  coverage   to run coverage check of the documentation if enabled\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"clean\" (\r\n    for /d %%i in (%BUILDDIR%\\*) do rmdir /q /s %%i\r\n    del /q /s %BUILDDIR%\\*\r\n    goto end\r\n)\r\n\r\n\r\nREM Check if sphinx-build is available and fallback to Python version if any\r\n%SPHINXBUILD% 1>NUL 2>NUL\r\nif errorlevel 9009 goto sphinx_python\r\ngoto sphinx_ok\r\n\r\n:sphinx_python\r\n\r\nset SPHINXBUILD=call python3 -m sphinx.__init__\r\n%SPHINXBUILD% 2> nul\r\nif errorlevel 9009 (\r\n    echo.\r\n    echo.The 'sphinx-build' command was not found. Make sure you have Sphinx\r\n    echo.installed, then set the SPHINXBUILD environment variable to point\r\n    echo.to the full path of the 'sphinx-build' executable. Alternatively you\r\n    echo.may add the Sphinx directory to PATH.\r\n    echo.\r\n    echo.If you don't have Sphinx installed, grab it from\r\n    echo.http://sphinx-doc.org/\r\n    exit /b 1\r\n)\r\n\r\n:sphinx_ok\r\n\r\n\r\nif \"%1\" == \"html\" (\r\n    %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The HTML pages are in %BUILDDIR%/html.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"dirhtml\" (\r\n    %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"singlehtml\" (\r\n    %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"pickle\" (\r\n    %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished; now you can process the pickle files.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"json\" (\r\n    %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished; now you can process the JSON files.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"htmlhelp\" (\r\n    %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished; now you can run HTML Help Workshop with the ^\r\n.hhp project file in %BUILDDIR%/htmlhelp.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"qthelp\" (\r\n    %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished; now you can run \"qcollectiongenerator\" with the ^\r\n.qhcp project file in %BUILDDIR%/qthelp, like this:\r\n    echo.^> qcollectiongenerator %BUILDDIR%\\qthelp\\testy_sphinxy.qhcp\r\n    echo.To view the help file:\r\n    echo.^> assistant -collectionFile %BUILDDIR%\\qthelp\\testy_sphinxy.ghc\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"devhelp\" (\r\n    %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"epub\" (\r\n    %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The epub file is in %BUILDDIR%/epub.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"latex\" (\r\n    %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"latexpdf\" (\r\n    %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r\n    cd %BUILDDIR%/latex\r\n    make all-pdf\r\n    cd %~dp0\r\n    echo.\r\n    echo.Build finished; the PDF files are in %BUILDDIR%/latex.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"latexpdfja\" (\r\n    %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r\n    cd %BUILDDIR%/latex\r\n    make all-pdf-ja\r\n    cd %~dp0\r\n    echo.\r\n    echo.Build finished; the PDF files are in %BUILDDIR%/latex.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"text\" (\r\n    %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The text files are in %BUILDDIR%/text.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"man\" (\r\n    %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The manual pages are in %BUILDDIR%/man.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"texinfo\" (\r\n    %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"gettext\" (\r\n    %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The message catalogs are in %BUILDDIR%/locale.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"changes\" (\r\n    %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.The overview file is in %BUILDDIR%/changes.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"linkcheck\" (\r\n    %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Link check complete; look for any errors in the above output ^\r\nor in %BUILDDIR%/linkcheck/output.txt.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"doctest\" (\r\n    %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Testing of doctests in the sources finished, look at the ^\r\nresults in %BUILDDIR%/doctest/output.txt.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"coverage\" (\r\n    %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Testing of coverage in the sources finished, look at the ^\r\nresults in %BUILDDIR%/coverage/python.txt.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"xml\" (\r\n    %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The XML files are in %BUILDDIR%/xml.\r\n    goto end\r\n)\r\n\r\nif \"%1\" == \"pseudoxml\" (\r\n    %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml\r\n    if errorlevel 1 exit /b 1\r\n    echo.\r\n    echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.\r\n    goto end\r\n)\r\n\r\n:end\r\n"
  },
  {
    "path": "doc/repl/.gitignore",
    "content": "build\n"
  },
  {
    "path": "doc/repl/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5)\nproject(sqjsrepl VERSION 4.0 LANGUAGES C CXX)\n\noption(ENABLE_VAR_TRACE \"Enable variable change tracing feature.\" OFF)\n\nadd_subdirectory(../../squirrel \"${PROJECT_BINARY_DIR}/squirrel\")\nadd_subdirectory(../../squirrel/compiler \"${PROJECT_BINARY_DIR}/quirrel-compiler\")\nadd_subdirectory(../../sqstdlib \"${PROJECT_BINARY_DIR}/sqstdlib\")\nadd_subdirectory(../../sqmodules \"${PROJECT_BINARY_DIR}/sqmodules\")\n\n#add_library(sqjsrepl native.cpp)\nadd_executable(sqjsrepl native.cpp)\ntarget_link_libraries(sqjsrepl squirrel sqstdlib sqmodules quirrel-compiler)\n\ntarget_include_directories(squirrel PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../internal>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../helpers>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../squirrel>\"\n)\n\ntarget_include_directories(quirrel-compiler PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../squirrel>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../squirrel/compiler>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../helpers>\"\n)\n\ntarget_include_directories(sqstdlib PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../internal>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../squirrel>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../..>\"\n)\n\ntarget_include_directories(sqmodules PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../sqrat/include>\"\n)\n\ntarget_include_directories(sqjsrepl PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/../../sqmodules>\"\n)\n\nset_target_properties(sqjsrepl PROPERTIES LINK_FLAGS \"--bind -sFILESYSTEM=0 -sNO_DISABLE_EXCEPTION_CATCHING\")\n\nset_target_properties(sqjsrepl PROPERTIES\n  RUNTIME_OUTPUT_DIRECTORY \"${PROJECT_SOURCE_DIR}/static\"\n)\n"
  },
  {
    "path": "doc/repl/build.txt",
    "content": "Build instructions:\n\n* Install Emscripten SDK\n* mkdir build\n* cd build\n* emcmake cmake ..\n* emmake make\n"
  },
  {
    "path": "doc/repl/native.cpp",
    "content": "#include \"../../include/squirrel.h\"\n#include \"../../include/sqstdaux.h\"\n#include \"../../sqmodules/sqmodules.h\"\n#include <emscripten/bind.h>\n#include <cstdio>\n#include <cstdarg>\n\n\n// Not using file system\nstatic struct WasmSqModulesFileAccess : public ISqModulesFileAccess\n{\n  virtual void destroy() override {}\n\n  virtual void getSearchTargets(const char * /*fn*/, bool &search_native, bool &search_script) override {\n    search_native = true;\n    search_script = false; // No file system in Wasm build\n  }\n\n  virtual void resolveFileName(const char *requested_fn, const char *running_script, string &res) override {\n    // No relative paths because there's no file systems\n    res = requested_fn;\n  }\n\n  virtual bool readFile(const string &resolved_fn, const char *requested_fn, vector<char> &buf, string &out_err_msg) override {\n    // Should not get here, but just in case\n    out_err_msg = std::string(\"Cannot read '\") + resolved_fn.c_str() + \"' module from file\";\n    return false;\n  }\n} wasm_file_access;\n\n\nstatic std::string output;\n\n\nstatic const std::string vlformat(const char * const fmt, va_list va)\n{\n  va_list vaCopy;\n  va_copy(vaCopy, va);\n  const int iLen = std::vsnprintf(nullptr, 0, fmt, vaCopy);\n  va_end(vaCopy);\n\n  std::vector<char> zc(iLen + 1);\n  std::vsnprintf(zc.data(), zc.size(), fmt, va);\n\n  return std::string(zc.data(), iLen);\n}\n\nstatic const std::string vaformat(const char * const fmt, ...)\n{\n  va_list vl;\n  va_start(vl, fmt);\n  std::string res = vlformat(fmt, vl);\n  va_end(vl);\n  return res;\n}\n\nstatic void script_print_func(HSQUIRRELVM /*v*/, const char* s,...)\n{\n  va_list vl;\n  va_start(vl, s);\n  output += vlformat(s, vl);\n  va_end(vl);\n}\n\n\nstatic void script_err_print_func(HSQUIRRELVM /*v*/, const char* s,...)\n{\n  va_list vl;\n  va_start(vl, s);\n  output += vlformat(s, vl);\n  va_end(vl);\n}\n\n\nstatic void compile_error_handler(HSQUIRRELVM /*v*/, SQMessageSeverity sev, const char *desc, const char *source,\n                        SQInteger line, SQInteger column, const char *extra_info)\n{\n  const char *sevName = \"error\";\n  if (sev == SEV_HINT) sevName = \"hint\";\n  else if (sev == SEV_WARNING) sevName = \"warning\";\n  output += vaformat(\"Squirrel compile %s: %s (%d:%d): %s\", sevName, source, int(line), int(column), desc);\n  if (extra_info)\n  {\n    output += \"\\n\";\n    output += extra_info;\n  }\n}\n\n\nstatic SQInteger runtime_error_handler(HSQUIRRELVM v)\n{\n  assert(sq_gettop(v) == 2);\n\n  const char *errMsg = nullptr;\n  if (SQ_FAILED(sq_getstring(v, 2, &errMsg)))\n    errMsg = \"Unknown error\";\n\n  output.append(errMsg);\n\n  if (SQ_SUCCEEDED(sqstd_formatcallstackstring(v)))\n  {\n    const char* callstack = nullptr;\n    sq_getstring(v, -1, &callstack);\n\n    output.append(\"\\n\");\n    output.append(callstack);\n\n    sq_pop(v, 1);\n  }\n  else\n    output += \"No stack\";\n\n  return 0;\n}\n\n\nstatic std::string runScript(const std::string &source_text)\n{\n  output.clear();\n\n  HSQUIRRELVM vm = sq_open(1024);\n  assert(vm);\n\n  std::unique_ptr<SqModules> moduleMgr;\n  moduleMgr.reset(new SqModules(vm, &wasm_file_access));\n\n  sq_setprintfunc(vm, script_print_func, script_err_print_func);\n  sq_setcompilererrorhandler(vm, compile_error_handler);\n\n  sq_newclosure(vm, runtime_error_handler, 0);\n  sq_seterrorhandler(vm);\n\n  sq_enablevartrace(vm, false);\n\n  moduleMgr->registerMathLib();\n  moduleMgr->registerStringLib();\n  moduleMgr->registerSystemLib();\n  moduleMgr->registerDebugLib();\n  moduleMgr->registerIoStreamLib();\n  //moduleMgr->registerIoLib(); // not needed in browser version\n  moduleMgr->registerDateTimeLib();\n\n  sq_newtable(vm);\n  HSQOBJECT hBindings;\n  sq_getstackobj(vm, -1, &hBindings);\n  moduleMgr->bindBaseLib(hBindings);\n  moduleMgr->bindRequireApi(hBindings);\n\n  if (SQ_SUCCEEDED(sq_compile(vm, source_text.c_str(), source_text.length(), \"console\", true, &hBindings)))\n  {\n    sq_pushnull(vm); //environment\n\n    if (SQ_FAILED(sq_call(vm, 1, SQTrue, SQTrue)))\n      output += \"\\nScript execution failed\";\n    else\n    {\n      if (sq_gettype(vm, -1) != OT_NULL)\n      {\n        if (SQ_SUCCEEDED(sq_tostring(vm, -1)))\n        {\n          const char *resStr = nullptr;\n          sq_getstring(vm, -1, &resStr);\n          output += \"\\n\";\n          output += resStr;\n          sq_pop(vm, 1);\n        }\n      }\n    }\n\n    sq_pop(vm, 1); // script closure\n  }\n\n  sq_pop(vm, 1); // bindings table\n\n  std::string result = output;\n\n  output.clear();\n\n  moduleMgr.reset();\n  sq_close(vm);\n\n  return result;\n}\n\nEMSCRIPTEN_BINDINGS(native) { emscripten::function(\"runScript\", &runScript); }\n"
  },
  {
    "path": "doc/repl/static/repl-rst.css",
    "content": "#repl-root {\n  display: none; /* shown by script after initialization */\n}\n\n.editor-container {\n  flex: 1;\n  width: 100%;\n  display: flex;\n  flex-direction: column;\n  margin: 8px;\n}\n\n.container-source {\n  height:32rem;\n}\n\n.container-output {\n  height:16rem;\n}\n\n.editor-container:first-child {\n  margin-right: 0;\n}\n.editor-header {\n  margin: 0;\n  padding: 0;\n  display: flex;\n  list-style: none;\n}\n\n.editor-header > li {\n  list-style: none;\n}\n\n.editor-header > li:last-child {\n  margin-left: auto;\n}\n.editor-header > li > span {\n  height: 38px;\n  line-height: 38px;\n}\n.editor-header > li > a {\n  height: 38px;\n  line-height: 38px;\n  padding: .3em .5em;\n  border: 1px solid red;\n}\n.editor-area {\n  flex: 1;\n  border: 1px solid lightgray;\n}\n.editor-info {\n  margin-top: 6px;\n  height: 160px;\n  border: 1px solid lightgray;\n  padding: 8px;\n  overflow-y: auto;\n}\n.editor-info li {\n  cursor: pointer;\n}\n.editor-sub-header {\n  padding: 4px 8px;\n}\n\n.output {\n  border: 1px solid lightgray;\n  padding: 8px;\n  overflow-y: auto;\n  flex: 1;\n}\n\nbutton#btn-run {\n  margin-left:auto;\n}\n"
  },
  {
    "path": "doc/repl/static/repl.css",
    "content": "#repl-root {\n  display: none; /* shown by script after initialization */\n  height: 100vh;\n}\n\n.editor-container {\n  flex: 1;\n  width: 100%;\n  display: flex;\n  flex-direction: column;\n  margin: 8px;\n}\n.editor-container:first-child {\n  margin-right: 0;\n}\n.editor-header {\n  margin: 0;\n  padding: 0;\n  display: flex;\n  list-style: none;\n}\n\n.editor-header > li {\n  list-style: none;\n}\n\n.editor-header > li:last-child {\n  margin-left: auto;\n}\n.editor-header > li > span {\n  height: 38px;\n  line-height: 38px;\n}\n.editor-header > li > a {\n  height: 38px;\n  line-height: 38px;\n  padding: .3em .5em;\n  border: 1px solid red;\n}\n.editor-area {\n  flex: 1;\n  border: 1px solid lightgray;\n}\n.editor-info {\n  margin-top: 6px;\n  height: 160px;\n  border: 1px solid lightgray;\n  padding: 8px;\n  overflow-y: auto;\n}\n.editor-info li {\n  cursor: pointer;\n}\n.editor-sub-header {\n  padding: 4px 8px;\n}\n\n.output {\n  border: 1px solid lightgray;\n  padding: 8px;\n  overflow-y: auto;\n  flex: 1;\n}\n\nbutton#btn-run {\n  padding: 0.25rem 1rem;\n}\n"
  },
  {
    "path": "doc/repl/static/repl.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <title>Quirrel REPL</title>\n  <link rel=\"stylesheet\" href=\"repl.css\" media=\"all\">\n  <link rel=\"icon\" type=\"image/x-icon\" href=\"repl.ico\">\n</head>\n\n<body>\n\n<div id=\"repl-root\">\n  <div class=\"editor-container\">\n    <ul class=\"editor-header\">\n      <li><span>Source code</span></li>\n      <li><span><button id=\"btn-run\">Run (F9)</button></span></li>\n    </ul>\n    <pre id=\"source-editor\" class=\"editor-area\"></pre>\n  </div>\n  <div class=\"editor-container\">\n    <ul class=\"editor-header\">\n      <li><span>Result</span></li>\n      <li></li>\n    </ul>\n    <pre id=\"output\" class=\"output\"></pre>\n  </div>\n</div>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.14/ace.js\"></script>\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js\"></script>\n<script src=\"replmain.js\"></script>\n<script src=\"sqjsrepl.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "doc/repl/static/replmain.js",
    "content": "// Setup editor\nconst sourceEditor = ace.edit(\"source-editor\")\nsourceEditor.setShowPrintMargin(false)\nsourceEditor.setValue(localStorage.getItem('sourceCode') || 'println(\"Hello, Quirrel!\")')\nsourceEditor.moveCursorTo(0, 0)\n\n\nfunction execute() {\n  const sourceCode = sourceEditor.getValue()\n  localStorage.setItem('sourceCode', sourceCode)\n  const result = Module.runScript(sourceCode)\n  $('#output').text(result)\n}\n\n$('#btn-run').on('click', execute)\n\ndocument.addEventListener('keyup', (e)=>{\n  if (e.key === 'F9')\n    execute()\n}, false)\n\n// Show page\n$('#repl-root').css({'display': 'flex'})\n\n// WebAssembly\nvar Module = {\n  onRuntimeInitialized: function() {\n    // Initialize here\n  }\n}\n"
  },
  {
    "path": "doc/requirements.txt",
    "content": "Sphinx==8.2.3\nmyst-parser==4.0.1\nsphinx-rtd-theme==3.0.2\n"
  },
  {
    "path": "doc/source/_static/custom.css",
    "content": "﻿.toggle .header {\n    display: block;\n    clear: both;\n}\n\n.toggle .header:after {\n    content: \" ▶\";\n}\n\n.toggle .header.open:after {\n    content: \" ▼\";\n}\n\n/* Bar charts on the performance page.*/\n/* Licensed with MIT license from https://github.com/wren-lang/wren */\n\ntable.chart {\n  margin: 4px 0 0 0;\n  padding: 0 0 0 25px;\n}\n\ntable.chart td, th {\n  line-height: 15px;\n  margin: 0;\n  padding: 1px 0;\n}\n\ntable.chart th {\n  font-size: 14px;\n  width: 200px;\n}\n\ntable.chart .chart-bar {\n  display: inline-block;\n  padding: 2px 0 0 0;\n  color: #eeeeee;\n  background: hsl(200, 60%, 50%);\n  border-bottom: solid 1px hsl(210, 60%, 20%);\n  text-align: right;\n  border-radius: 2px;\n}\n\ntable.chart .chart-bar.featured {\n  background: hsl(200, 60%, 25%);\n  border-bottom: solid 1px hsl(210, 60%, 20%);\n}\n\n/* End of wren style */\n"
  },
  {
    "path": "doc/source/_templates/page.html",
    "content": "{% extends \"!page.html\" %}\n\n{% block footer %}\n <script type=\"text/javascript\">\n    $(document).ready(function() {\n        $(\".toggle > *\").hide();\n        $(\".toggle .header\").show();\n        $(\".toggle .header\").click(function() {\n            $(this).parent().children().not(\".header\").toggle(400);\n            $(this).parent().children(\".header\").toggleClass(\"open\");\n        })\n    });\n</script>\n{% endblock %}"
  },
  {
    "path": "doc/source/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Quirrel documentation build configuration file, created by\n# sphinx-quickstart on Sun Jan 31 00:26:52 2016.\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport sys\nimport os\nimport time\nimport re\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#sys.path.insert(0, os.path.abspath('.'))\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nsys.path.insert(0, os.path.abspath('.'))\nextensions = [\n  'quirrel',\n  'myst_parser',\n  'quirrel_pygment_lexer'\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix(es) of source filenames.\n# You can specify multiple suffix as a list of string:\nsource_suffix = ['.rst', '.md']\n\n# The encoding of source files.\n#source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = u'Quirrel documentation'\ncopyright = '2003-2016, Alberto Demichelis; 2016-%s, Gaijin Entertainment' % time.strftime('%Y')\nauthor = u'Alberto Demichelis; Vasiliy Ryabtsev; Gaijin Entertainment'\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\ndef read_version_from_source():\n      \"\"\"Extract version from squirrel.h\"\"\"\n      header_path = os.path.join(os.path.dirname(__file__), '..', '..', 'include', 'squirrel.h')\n      header_path = os.path.abspath(header_path)\n\n      with open(header_path, 'r') as f:\n          content = f.read()\n\n      major = re.search(r'#define\\s+SQUIRREL_VERSION_NUMBER_MAJOR\\s+(\\d+)', content).group(1)\n      minor = re.search(r'#define\\s+SQUIRREL_VERSION_NUMBER_MINOR\\s+(\\d+)', content).group(1)\n      patch = re.search(r'#define\\s+SQUIRREL_VERSION_NUMBER_PATCH\\s+(\\d+)', content).group(1)\n\n      return f'{major}.{minor}.{patch}'\n\nversion = read_version_from_source()\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = 'en'\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = []\n\n# The reST default role (used for this markup: `text`) to use for all\n# documents.\n#default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = 'sphinx'\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\n# If true, keep warnings as \"system message\" paragraphs in the built documents.\n#keep_warnings = False\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = False\n\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = 'sphinx_rtd_theme'\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#html_theme_options = {}\n\n# Add any paths that contain custom themes here, relative to this directory.\n#html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\nhtml_logo = 'simple_nut.png'\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\nhtml_favicon = 'nut.ico'\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static', '../repl/static']\n\n# Add any extra paths that contain custom files (such as robots.txt or\n# .htaccess) here, relative to this directory. These files are copied\n# directly to the root of the documentation.\n#html_extra_path = []\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\n#html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_domain_indices = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\n#html_show_sourcelink = True\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\n#html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\n#html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = None\n\n# Language to be used for generating the HTML full-text search index.\n# Sphinx supports the following languages:\n#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'\n#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'\n#html_search_language = 'en'\n\n# A dictionary with options for the search language support, empty by default.\n# Now only 'ja' uses this config value\n#html_search_options = {'type': 'default'}\n\n# The name of a javascript file (relative to the configuration directory) that\n# implements a search results scorer. If empty, the default will be used.\n#html_search_scorer = 'scorer.js'\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'squirrel_doc'\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n# The paper size ('letterpaper' or 'a4paper').\n#'papersize': 'letterpaper',\n\n# The font size ('10pt', '11pt' or '12pt').\n#'pointsize': '10pt',\n\n# Additional stuff for the LaTeX preamble.\n#'preamble': '',\n\n# Latex figure (float) alignment\n#'figure_align': 'htbp',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\n_stdauthor = r'Alberto Demichelis; Vasiliy Ryabtsev; Gaijin Entertainment'\nlatex_documents = [\n    ('reference/index', 'reference.tex',\n     'Quirrel Reference Manual', _stdauthor, 'manual'),\n     ('stdlib/index', 'stdlib.tex',\n     'Quirrel Standard Library', _stdauthor, 'manual'),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n#latex_use_parts = False\n\n# If true, show page references after internal links.\n#latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n#latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_domain_indices = True\n\n\n# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    (master_doc, 'Quirrel', u'Quirrel Documentation',\n     [author], 1)\n]\n\n# If true, show URL addresses after external links.\n#man_show_urls = False\n\n\n# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (master_doc, 'Quirrel', u'Quirrel Documentation',\n     author, 'Quirrel', 'The Programming Language.',\n     'Miscellaneous'),\n]\n\ndef setup(app):\n    app.add_css_file('custom.css')\n\n# Documents to append as an appendix to all manuals.\n#texinfo_appendices = []\n\n# If false, no module index is generated.\n#texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n#texinfo_show_urls = 'footnote'\n\n# If true, do not generate a @detailmenu in the \"Top\" node's menu.\n#texinfo_no_detailmenu = False\n"
  },
  {
    "path": "doc/source/diff_from_squirrel.rst",
    "content": ".. _diff_from_squirrel:\n\n*******************************************\nDifferences from Squirrel language\n*******************************************\n\n.. index::\n    single: diff_from_squirrel\n\n\nSquirrel language was used a lot in all Gaijin projects since 2006.\nGaijin used Lua before but found Lua too unsafe and hard to debug, and also hard sometimes to bind with native code due to lack of types.\nIt is well known and there are lot info on this in the Internet.\nSquirrel has not only C++ like syntax (which is helpful for C++ programmers sometimes), but also has type system much closer to C/C++ code.\nIt also has safer syntax and semantic.\nHowever during heavy usage we found that some features of language are not used in our real codebase of millions of LoC in 20+ projects on 10+ platforms.\nSome language features were also not very safe, or inconsistent. We needed stricter language with tools for easier refactor and support.\nAnd of course in game-development any extra performance is always welcome.\nBasically in any doubt we used 'Zen of Python'.\n\nWe renamed language from Squirrel to Quirrel to avoid ambiguity.\n\n------------\nNew features\n------------\n\nLanguage syntax\n===============\n\n* Template strings: ``$\"Hello {name}\"`` for string interpolation\n* Documentation strings: ``@@\"docstring\"`` for inline documentation\n* Compiler directives: ``#pragma`` for configuring compiler options\n* Type method access: ``obj.$method`` and ``obj?.$method``\n* Numeric literal separators: ``1_000_000`` for better readability\n* Supports destructuring assignment to unpack values from arrays and objects (e.g., ``let {a, b} = table``), including destructuring in function parameters with default values and type annotations\n* ES2015-style shorthand table initialization: ``{x, y}`` instead of ``{x=x, y=y}``\n* Named functions in expressions: ``let foo = function foo() {}``\n* Null-safety operators:\n\n  * ``?.`` - Null-conditional member access: ``obj?.property``\n  * ``?[`` - Null-conditional indexing: ``arr?[index]``\n  * ``?(`` - Null-conditional function call: ``func?(args)``\n  * ``??`` - Null-coalescing operator: ``value ?? default``\n\n* New keywords:\n\n  * ``let`` - Immutable binding declaration (alternative to ``local``)\n  * ``global`` - Explicit global variable declaration\n  * ``not in`` - For membership testing, alternative to ``!(x in y)``\n  * ``static`` - For evaluating expressions once on first access and memoizing the result\n  * ``const`` can also be used for inline declaration inside expressions\n\nStatic analysis\n===============\n\n* Comprehensive static analyzer 90+ diagnostic checks\n  (including reporting unused variables, functions, imports, parameters,\n  unreachable code detection, type mismatches and null safety violations,\n  data flow analysis, scope and visibility checks and more)\n\nCompiler architecture\n=====================\n\n* AST-based multi-pass compilation (vs. Squirrel's single-pass direct compilation)\n\nVM architecture\n====================\n\n* Class method hinting for performance optimization (approaching LuaJIT non-JIT performance)\n* Added tracking of changing values of container fields (saving the stack of code that modifies the values)\n\nType system & immutability\n===========================\n\n* Immutability support:\n\n  * ``freeze()`` function for protecting references to instances, tables, arrays from modification\n  * ``let`` keyword for non-assignable bindings\n\n* Pure function marking for optimization hints and use in constants\n\nStandard library\n================\n\n* Base library additions:\n\n  * ``println()``, ``errorln()`` - print/error with newline variants\n  * ``print()``, ``println()``, ``error()``, ``errorln()`` accept arbitrary number of parameters to print\n  * ``freeze(obj)`` - return an immutable reference to an object\n    (also ``getobjflags(obj)`` to get object flags (e.g., SQOBJ_FLAG_IMMUTABLE) and\n    ``is_frozen()`` for container types.\n  * ``deduplicate_object(obj)`` - deduplicate table/array contents for memory efficiency\n  * Enhanced ``assert()`` - accepts closures for lazy message evaluation\n  * Support for ``call()``/``acall()`` type methods for classes\n  * Support negative indexes in ``array.slice()`` and ``string.slice()``\n\n* String type methods:\n\n  * Added: ``.hash()``, ``.contains()``, ``.hasindex()``, ``.subst()``, ``.replace()``, ``.join()``, ``.concat()``,\n    ``.clone()``, plus moved from stdlib: ``.strip()``, ``.lstrip()``, ``.rstrip()``, ``.split()``,\n    ``.split_by_chars()``, ``.escape()``, ``.startswith()``, ``.endswith()`` (some are shared with the string stardard library)\n  * Changed: ``.find()`` renamed to ``.indexof()`` to reduce ambiguity\n\n* Table type methods:\n\n  * Added:** ``.each()``, ``.reduce()``, ``.findindex()``, ``.findvalue()``, ``.topairs()``, ``.swap()``,\n    ``.__merge()``, ``.__update()``, ``.replace_with()``, ``.hasindex()``, ``.hasvalue()``, ``.clone()``,\n    ``.is_frozen()``, ``.getfuncinfos()``\n  * Removed: ``.setdelegate()``, ``.getdelegate()``\n\n* Array type methods:\n\n  * Added: ``.each()``, ``.findindex()``, ``.findvalue()``, ``.contains()``, ``.hasindex()``, ``.hasvalue()``,\n    ``.totable()``, ``.replace_with()``, ``.swap()``, ``.clone()``, ``.is_frozen()``\n  * Changed:\n    * ``.find()`` renamed to ``.indexof()``\n    * ``.append()`` and ``.extend()`` now accept multiple arguments\n  * Removed: ``.push()`` (use ``.append()`` instead)\n\n* Standard library modules:\n\n  * Added: datetime, debug, and serialization modules\n  * String module: Functions moved to string type methods for convenience (still available as module functions)\n\nModule system\n=============\n\nSupport for modules. Two APIs - runtime (``require()`` function) and compile-time (``import`` statement)\n\n----------------\nRemoved features\n----------------\n\nLanguage features\n=================\n\n* Octal number literals - was error-prone, ``0123`` syntax now produces an error\n* Comma operator - removed from expressions (was never used, but error-prone)\n* Class and member attributes - ``</`` and ``/>`` XML-style attribute syntax removed (were never used in real code)\n* ``#`` single line comments - only ``//`` comments supported now (consistency - \"one obvious way\")\n* ``rawcall`` keyword\n* Post-initializer syntax - removed due to ambiguity (especially with optional commas)\n* ``class::method`` syntax sugar - adding table/class methods this way disallowed\n  (as There should be one -- and preferably only one -- obvious way to do it).\n  Declare methods in-place or explicitly add slots with ``<-`` operator.\n\nBase library functions\n======================\n\nThe following functions were removed for security, simplicity, or architectural reasons:\n``setroottable()``, ``setconsttable()``, ``seterrorhandler()``\n\n----------------\nChanges\n----------------\n\nScoping and declarations\n=========================\n\n* Functions and classes are locally scoped\n* Constants and enums are locally scoped by default - use ``global`` keyword for global declarations\n* ``global`` keyword required for declaring global constants and enums explicitly\n* Referencing the closure environment object (``this``) is explicit - no implicit ``this`` lookup\n* Usage of the root table is deprecated\n* No fallback to global root table for undeclared variables - must use ``::`` operator to access globals (if root table is enabled at all)\n\nCompilation Model\n=================\n\n* AST-based compiler (vs. Squirrel's single-pass direct bytecode generation):\n\n  * Multi-pass compilation with intermediate AST representation\n  * AST optimizations (closure hoisting, constant folding)\n  * Static analyzer operates on AST\n\nC/C++ Binding API\n=================\n\n* Human-readable function type declarations:\n\n  * Replaces cryptic type masks (``\"ac.\"``) with readable syntax\n  * Example: ``split_by_chars(str: string, separators: string, [skip_empty: bool]): array``\n\n* Non-stack-based C APIs for better performance\n\nClass declaration syntax\n========================\n\n* Python-style class inheritance: ``class Baz(Bar)`` instead of ``class Baz extends Bar``\n* Class ``extends`` keyword removed in favor of parentheses-based syntax\n\nOperators\n=========\n\n* ``delete`` is deprecated:\n  * Now configurable via pragmas: ``#forbid-delete-operator`` / ``#allow-delete-operator``\n  * Recommended to use ``table.$rawdelete()`` or ``table.rawdelete()`` instead\n\nType methods\n=================\n\n* ``.find()`` renamed to ``.indexof()`` for arrays and strings\n* ``array.append()`` and ``array.extend()`` now accept multiple arguments\n* ``array.filter()`` argument order changed to match map/reduce conventions\n  (and in certain degree the one of ``foreach`` by making key argument optional)\n* ``array.filter()``, ``array.map()`` and ``array.reduce()`` callbacks optionally accept the reference\n  to the container being processed (instead of passing it via ``this``)\n* ``getinfos()`` renamed to ``getfuncinfos()`` and now works on callable objects (instances, tables)\n\n\nError handling\n==============\n\n* Structured diagnostics with severity levels\n* Error callback with source location, diagnostic ID, and extra information\n* Configurable static analyzer warnings\n\n\n--------------------------------\nPossible future changes\n--------------------------------\n\nSee RFCs page\n\n"
  },
  {
    "path": "doc/source/index.rst",
    "content": ".. Quirrel documentation master file, created by\n   sphinx-quickstart on Sun Jan 31 00:26:52 2016.\n   You can adapt this file completely to your liking, but it should at least\n   contain the root `toctree` directive.\n\nQuirrel documentation\n=========================================\n\n.. toctree::\n   :maxdepth: 1\n   \n   introduction.rst\n   diff_from_squirrel.rst\n   reference/index.rst\n   stdlib/index.rst\n   modules/index.rst\n   modules/bindings.rst\n   repl/index.rst\n   rfcs/STATUS.md\n   rfcs/README.md\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`search`\n\n\n"
  },
  {
    "path": "doc/source/introduction.rst",
    "content": ".. _introduction:\n\n************\nIntroduction\n************\n\n.. index::\n    single: introduction\n\nQuirrel is a fast, high-level imperative, OO programming language, designed to be a lightweight but powerful\nscripting tool that fits within the size, memory bandwidth, and real-time requirements of\napplications like games.\n\nQuirrel has simple integration and bindings in any C++ application.\n\nQuirrel has C/Java/C++ like syntax with clear, rich and simple type system, \nbut the language has a very dynamic nature like Python/Lua/JavaScript.\nEasy to start while being much safer than Lua and JS, having the equal performance with Lua.\n\nIt is based on Squirrel Script language (http://www.squirrel-lang.org/), but modified to be safer, stricter and faster.\nQuirrel is not compatible with the original Squirrel (see :ref:`Diff from Squirrel <diff_from_squirrel>`),\nbut conversion usually can be done easily.\n\nQuirrel offers a wide range of features like dynamic typing, higher\norder functions, generators, tail recursion, exception handling, coroutines, automatic memory\nmanagement.\n\nRepository is available on https://github.com/GaijinEntertainment/quirrel and your PR's and feedback are welcome!\n\n\n\n.. _more_details_on_quirrel:\n\n----------------------------\nMore details on Quirrel\n----------------------------\n\n.. index::\n    single: more details on quirrel\n\n- Quirrel is a mature scripting language used in tens of games and other apps (including web servers and embeddable platforms)\n  with hundreds of millions installations.\n  It was created to be embeddable language to C/C++ applications with easy bindings and clear mental model.\n- Quirrel is familiar and convenient for those who have experience with C, C++, JavaScript or Python.\n  It has a small and simple but sufficient :ref:`types system <datatypes_and_values>`:\n  float and integer types (not just 'numeric'), built-in tables, classes and arrays,\n  functions, closures, generators and coroutines (as well as null, string and boolean types).\n  In most cases it is completely obvious how to bind native code, class or function, how to call native code and work with native types.\n  And of course, arrays indices start with 0.\n  To be obvious for C++ programmer in both programming and binding is one of the main ideas Quirrel Language\n  Python and JavaScript are not lightweight nor easily embeddable; JS has also an infamous type system with all its implicitness.\n  Lua on the other hand is as small as Quirrel, but because of many differences from C/C++\n  it often confuses even experienced programmers.\n- Quirrel has a robust and predictable :ref:`memory model <embedding_memory_management>`.\n  In most cases with reference count you never have unexpected freezes in runtime as well as predictable memory consumption.\n  However, we are planning to add GC memory management without reference count,\n  as it can be more beneficial in some ways of using language\n  (when you always have enough computational time in separate thread to manage memory it allows you to have less latency)  \n- Quirrel supports concurrency with :ref:`coroutines <threads>`.\n- Quirrel wants to be safe. The main intent to evolve Squirrel into Quirrel was to make it safer.\n  Being a dynamic language by its nature doesn't mean that you can be more safe.\n  Safety comes from different small syntactic and semantic changes, allowing more compile time validations and explicitly,\n  making code less ambiguous and clear to reader and writer.\n  Things like 'let' :ref:`Named bindings declaration <statements>`, :ref:`freezing <builtin_functions>` of tables and arrays,\n  :ref:`Destructuring assignment <destructuring_assignment>` and imports, deprecation of modifying classes,\n  redefine table keys and several others, as well as implementing static analyzer, helps to prevent many errors and allow code to be stricter.\n- Quirrel is fast.\n  It is at least as fast as Lua (on compilation and runtime),\n  with some tweaks to be sometimes closer to LuaJit with no JIT.\n  We are also going to implement AST-based compiler with optimizations on AST,\n  allowing code to become even faster in real-time (that will also allow making code safer and to add power of macros).\n  Class hinting allows classes to be as fast as in `Wren <https://wren.io>`_ or LuaJIT.\n\n\n"
  },
  {
    "path": "doc/source/modules/bindings.rst",
    "content": "Quirrel bindings\n-----------------------------------\n\nGuide in bindings\n=================\n\nNot full guide but some brief introduction.\nTo get deeper into bindings you need to study samples or read the code of SqRat\n\nSqrat is a C++ binding library designed for the Quirrel scripting language.\nSqrat simplifies the process of exposing C++ functions and classes to Quirrel scripts.\nIt automates type conversion between C++ and Quirrel, making it easier to register functions, methods,\nand classes without needing to manually handle the Quirrel stack in every case.\n\nExample\n^^^^^^^^^^^^^^^^^^\n\nBasic Includes\n^^^^^^^^^^^^^^^^^^\n\n.. code-block:: cpp\n\n    #include <sqrat.h>\n    #include <sqModules.h>\n\n\nCreate a module\n^^^^^^^^^^^^^^^^^^^^^\n\nSqModules allows to export Quirrel objects (usually tables and classes) as script modules.\nExample of module creation:\n\n::\n\n  Sqrat::Table exports(vm); // Create a table to hold the exported functions and classes\n  exports\n    .Func(\"function_name\", function) // Export a C++ function with automatic handling of arguments and return values\n    .SquirrelFuncDeclString(add, \"add(a: int, b: int): int\", \"Returns the sum of two integers, optional string\")// Export a C++ function that works with the Quirrel stack, fully documented\n    .SquirrelFunc(\"function_name\", low_level_function) // Export a C++ function that works with the Quirrel stack\n    .SetValue(\"SOME_ID\", value) // Exports is a table, so it can hold any Quirrel value\n  ;\n  module_manager->addNativeModule(\"module_name\", exports); // Expose the table as a module to the Quirrel scripts\n\n\nSimple bind of cpp function\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou can use Sqrat::Table::Func() or Sqrat::Class::Func() to register a C++ function for use in a Quirrel script.\nSqrat automatically handles argument and return value conversions between Quirrel and C++ types.\n\nC++:\n\n::\n\n  Sqrat::Table exports(vm);\n  exports.Func(\"pow\", &std::pow);  // Register pow function in the script\n  module_manager->addNativeModule(\"math_demo\", exports);\n\n\nUsage in Quirrel:\n::\n\n  from \"math_demo\" import pow\n  // or\n  let { pow } = require(\"math_demo\")\n\n  local result = pow(2, 3)  // Calls the C++ std::pow(2, 3)\n  print(result)  // Output: 8\n\n\n\nBind function that works with Quirrel stack\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nFor more control, you can manually handle the Quirrel stack by using SquirrelFunc.\nThis allows you to specify custom logic for processing function arguments and returning values.\nFor instance, you may need this for variadic functions, arguments of varying types, or functions with complex logic that can't be automatically bound.\n\n::\n\n  SQInteger sum_all_args(HSQUIRRELVM v) {\n      SQInteger n = sq_gettop(v); // Number of arguments\n      SQFloat sum = 0;\n      for (SQInteger i = 2; i <= n; ++i) { // Sum all arguments, starting from 2 (#1 is `this`)\n          SQFloat val;\n          if (SQ_SUCCEEDED(sq_getfloat(v, i, &val))) // For demo purposes, we only handle numbers and ignore other types\n              sum += val;\n      }\n      sq_pushfloat(v, sum); // Push the result\n      return 1; // Number of return values (0 for void, 1 for return value, SQ_ERROR for error)\n  }\n\n  exports.SquirrelFunc(\"sum_all_args\", sum_all_args, -2);  // -2: variable arguments, at least 2 (`this` and a number\n\nIn script:\n::\n\n  local result = sum_all_args(1, 2, 3, 4)  // Calls the C++ function\n  print(result)  // Output: 10\n\n\nFull signature of SquirrelFunc:\n\n.. cpp:function:: TableBase& Table::SquirrelFunc(const char* name, SQFUNCTION func, SQInteger nparamscheck, const char *typemask=nullptr, const char *docstring=nullptr, SQInteger nfreevars=0, const Object *freevars=nullptr)\n\n  :param name: should be string, func should be function that works with Quirrel\n  :param nparamscheck: number of arguments of function. If negative - function can have at least this number of arguments but can accept more.\n  :param typemask: optional typemask (see sq_setparamscheck in :ref:`API <api_ref_object_creation_and_handling>`)\n  :param docstring: optional docstring, nfreevars and freevars - free variables of function.\n  :param nfreevars: number of free variables\n  :param freevars: free variables to capture\n\n\n  :remarks: The typemask is a string that represent the expected parameter type. The types are expressed as follows: 'o' null, 'i' integer, 'f' float, 'n' integer or float, 's' string, 't' table, 'a' array, 'u' userdata, 'c' closure and nativeclosure, 'g' generator, 'p' userpointer, 'v' thread, 'x' instance(class instance), 'y' class, 'b' bool. and '.' any type. The symbol '|' can be used as 'or' to accept multiple types on the same parameter. There isn't any limit on the number of 'or' that can be used. Spaces are ignored so can be inserted between types to increase readability. For instance to check a function that expect a table as 'this' a string as first parameter and a number or a userpointer as second parameter, the string would be \"tsn|p\" (table,string,number or userpointer). If the parameters mask is contains fewer parameters than 'nparamscheck', the remaining parameters will not be typechecked.\n\n\n\nThe preferred method for binding C++ functions that work with the Quirrel stack is to use `.SquirrelFuncDeclString`.\nThis declarative method allows you to specify the function signature, argument types (including optional/default values), return type, and documentation string all in one place.\n\n**Example:**\n\n.. code-block:: cpp\n\n    .SquirrelFuncDeclString(\n        do_math,\n        \"pure do_math(a: int, [b: number = 2]): float\",\n        \"Performs math operation. Optional argument 'b' defaults to 2.\"\n    )\n\nThis approach allows the engine to:\n- Parse argument types and generate typemasks for type checking\n- Reflect metadata for documentation and scripting tools\n- Recognize pure functions for optimization\n\n**Why use SquirrelFuncDeclString?**\n\n- **Declarative:** Full signature, types, defaults, and docstring in a single place.\n- **Robust:** More accurate binding and automatic validation.\n- **Documentation-friendly:** Signature and docs are automatically extracted.\n\n**Deprecation Notice:**\n\nThe older `.SquirrelFunc` macro is now **deprecated**.  \nIt required manually handling arguments from the Quirrel VM stack, which is more error-prone and lacks reflection support.\n**Always prefer `.SquirrelFuncDeclString` for new bindings.**\n\n\nBind classes, constants and values\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nSqrat allows to register C++ classes with member variables and methods that can be accessed from Quirrel scripts.\n\nToy example:\n::\n\n  class Rect {\n    public:\n      float width, height;\n      Rect(float w, float h) : width(w), height(h) {}\n      float area() const {\n          return width * height;\n      }\n      float perimeter() const {\n          return 2 * (width + height);\n      }\n  };\n\n  Sqrat::Class<Rect> rectClass(table.GetVM(), \"Rect\");\n  rectClass\n    .Ctor()\n    .Var(\"width\", &Rect::width)\n    .Var(\"height\", &Rect::height)\n    .Func(\"area\", &Rect::area)\n    .Prop(\"perimeter\", &Rect::perimeter)\n  ;\n\n  exports.Bind(\"Rect\", rectClass);  // Bind the class to the table\n  module_manager->addNativeModule(\"geometry\", exports);\n\nIn script:\n::\n\n  from \"geometry\" import Rect\n  local r = Rect(1, 3)\n  r.width = 2\n  print(r.area())  // Output: 6\n  print(r.perimeter)  // Output: 10\n\nSquirrelCtor() may be used for a constructor with a flexible behavior.\nIt has to implement an actual native instance creation.\n\nExample:\n::\n\n  static SQInteger rect_ctor(HSQUIRRELVM v) {\n      SQInteger n = sq_gettop(v);\n      if (n == 2) { // copy constructor\n        if (!Sqrat::check_signature<Rect *>(vm, 2))\n          return sq_throwerror(vm, \"Invalid type passed to copy ctor\");\n      }\n      else if (n != 1 && n != 3)\n        return sqstd_throwerrorf(vm, \"Invalid arguments count %d\", n);\n\n      Rect *instance = new Rect(0, 0);\n      if (n == 1) // no arguments\n        ; // already initialized with default 0, 0\n      else if (n == 3) { // instance and 2 numbers\n        SQFloat w, h;\n        sq_getfloat(v, 2, &w); // Should always succeed, because types are specified in type mask (see SquirrelCtor)\n        sq_getfloat(v, 3, &h);\n        instance->width = w;\n        instance->height = h;\n      }\n      else if (n == 2) { // copy constructor (self instance and another instance)\n        Rect *other = Sqrat::Var<Rect *>(vm, 2).value;\n        instance->width = other->width;\n        instance->height = other->height;\n      }\n      Sqrat::ClassType<Rect>::SetManagedInstance(vm, 1, instance); // Link with script instance\n      return 1;\n  }\n\n  Sqrat::Class<Rect> rectClass(table.GetVM(), \"Rect\");\n  rectClass\n    .SquirrelCtor(rect_ctor, 0, \"x y|n n\") // 0 - no argument count check, \"x y|n n\" - type mask (instance('this') and instance or 2 numbers)\n    .Var(\"width\", &Rect::width)\n    .Var(\"height\", &Rect::height)\n    .Func(\"area\", &Rect::area)\n    .Prop(\"perimeter\", &Rect::perimeter)\n  ;\n\nIn script:\n::\n\n  from \"geometry\" import Rect\n  local r1 = Rect(1, 3)\n  local r2 = Rect(r1)\n  local r3 = Rect()\n\n\nConsttable - not documented\n\nClass property (setter) - not documented\n\nStatic functions - not documented\n"
  },
  {
    "path": "doc/source/modules/index.rst",
    "content": ".. _index:\n\n************\nModules\n************\n\nProject source code is available at https://github.com/GaijinEntertainment/quirrel\n\nQuirrel provides modules functionality via separate library.\nModules are useful to encapsulate code (only explicitly exported data/methods become\navailable outside), to make the code reusable and to prevent contaminating global namespace\n(root table).\nThe provided reference implementation also allows reloading of script code while keeping\ndata intact.\n\n==================\nScript API\n==================\n\n.. index::\n    single: Script API\n\nModule code is executed with a special table as context ('this').\nIt has the following functions bound:\n\n.. sq:function:: require(filename)\n\nIf given module was not loaded yet, reads the file, executes it and returns module exports.\nModule exports are data returned by module body code.\nIf module was loaded before, just returns its exports.\nIf file was not found, throws an error.\n\n.. sq:function:: require_optional(filename)\n\nThe same as require(), but for missing file it returns null instead of throwing an error.\n\n.. sq:function:: persist(key, initializer)\n\nUsed to keep data between sequential execution of the same file for hot reloading.\nFor the first run of the module calls provided initializer function and returns the result.\nAlso it stores a reference to the result in a special table that is later reused when\nthe file with the same name is executed.\nThe 'key' parameter is the unique-per-module identifier of the variable.\n\nExample: ::\n  \n  let counter = persist(\"counter\", @() {value=0})\n\n\n.. sq:function:: keepref(var)\n\nAn utility function that keeps a reference to the given object.\nMight be useful to keep an object from deleting itself if it is not exported outside the module.\n\n\nAlso module 'this' table contains field __name__ which is set to file name for module loaded\nby script require() function or parameter __name__ passed to C++ requireModule() function (defaults\nto \"__main__\" for entry point script).\n\n\n.. quirrel.native_modules\n\nModule that allow to list all registered native modules. \n\nExample: ::\n\n  require(\"quirrel.native_modules\").each(println)\n\n\nWill print all currently registered native modules.\n\n==================\nNative API\n==================\n\n.. index::\n    single: Native API\n\nModule functionality is implemented in SqModules C++ class with the following public methods:\n\n.. cpp:function:: SqModules::SqModules(HSQUIRRELVM vm)\n\nConstructs a module manager instance for the given Quirrel VM.\n\n.. cpp:function:: HSQUIRRELVM SqModules::getVM()\n\nReturns module manager VM.\n\n.. cpp:function:: bool SqModules::requireModule(const char *fn, bool must_exist, const char *__name__, SqObjPtr &exports, std::string &out_err_msg)\n\n    :param const char \\*fn: name of the file to load\n    :param bool must_exist: if set to false treat missing file as success (return true)\n    :param const char \\*__name__: value of module's __name__ field (set nullptr to use actual file name)\n    :param SqObjPtr &exports: object to store export to\n    :param std\\:\\:string &out_err_msg: receives error message if call failed\n    :returns: true if succeeded\n    :remarks: Actually this is a function bound to script as require()\n\nLoads and executes script module or just returns its exports if it was already run.\n\n.. cpp:function:: bool SqModules::reloadModule(const char *fn, bool must_exist, const char *__name__, SqObjPtr &exports, std::string &out_err_msg)\n\nBasically the same as requireModule, but it unloads all previously loaded modules and newly executes\nall modules pulled by require() calls.\nThis can also be used for initial module execution - so that the first call to\nreloadModule(entry_point_fn) will load all modules and initialize persistent data and subsequent calls\nto reloadModule(entry_point_fn) will reload the module and all it depends on while reusing kept persistent data.\n\n.. cpp:function:: bool SqModules::addNativeModule(const char *module_name, const SqObjPtr &exports)\n\nRegisters a Quirrel object 'exports' under the provided 'module_name', so that it can be require()-d in script.\n\n.. cpp:function:: void SqModules::registerMathLib()\n\nRegisters standard \"math\" native library\n\n.. cpp:function:: void SqModules::registerStringLib()\n\nRegisters standard \"string\" native library\n\n.. cpp:function:: void SqModules::registerIoStreamLib()\n\nRegisters standard \"iostream\" native library module (blob and stream classes)\n\n.. cpp:function:: void SqModules::registerDateTimeLib()\n\nRegisters standard \"datetime\" native library\n\n.. cpp:function:: void SqModules::registerDebugLib()\n\nRegisters \"debug\" native library\n\n.. cpp:function:: void SqModules::registerSystemLib()\n\nRegisters standard 'system' library as \"system\" native module\n\n.. cpp:function:: void SqModules::registerIoLib()\n\nRegisters standard 'io' library as \"io\" native module\n"
  },
  {
    "path": "doc/source/quirrel.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\n    quirrel\n    ~~~~~~~~~~~~~~~~~~~~~~~~~\n\n    The Quirrel domain.\n\n    :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.\n    :license: BSD, see LICENSE for details.\n\n    NOTE: this is just modified copypaste of javascript from sphinx\n\"\"\"\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import directives\n\nfrom sphinx import addnodes\nfrom sphinx.directives import ObjectDescription\nfrom sphinx.domains import Domain, ObjType\nfrom sphinx.locale import _\nfrom sphinx.roles import XRefRole\nfrom sphinx.util.docfields import Field, GroupedField, TypedField\nfrom sphinx.util.docutils import SphinxDirective\nfrom sphinx.util.nodes import make_refnode\n\nif False:\n    # For type annotation\n    from typing import Any, Dict, Iterator, List, Tuple  # NOQA\n    from docutils import nodes  # NOQA\n    from sphinx.application import Sphinx  # NOQA\n    from sphinx.builders import Builder  # NOQA\n    from sphinx.environment import BuildEnvironment  # NOQA\n\n\nclass SQObject(ObjectDescription):\n    \"\"\"\n    Description of a Quirrel object.\n    \"\"\"\n    #: If set to ``True`` this object is callable and a `desc_parameterlist` is\n    #: added\n    has_arguments = False\n\n    #: what is displayed right before the documentation entry\n    display_prefix = None  # type: unicode\n\n    #: If ``allow_nesting`` is ``True``, the object prefixes will be accumulated\n    #: based on directive nesting\n    allow_nesting = False\n\n    def handle_signature(self, sig, signode):\n        # type: (unicode, addnodes.desc_signature) -> Tuple[unicode, unicode]\n        \"\"\"Breaks down construct signatures\n\n        Parses out prefix and argument list from construct definition. The\n        namespace and class will be determined by the nesting of domain\n        directives.\n        \"\"\"\n        sig = sig.strip()\n        if '(' in sig and sig[-1:] == ')':\n            member, arglist = sig.split('(', 1)\n            member = member.strip()\n            arglist = arglist[:-1].strip()\n        else:\n            member = sig\n            arglist = None\n        # If construct is nested, prefix the current prefix\n        prefix = self.env.ref_context.get('sq:object', None)\n        mod_name = self.env.ref_context.get('sq:module')\n        name = member\n        try:\n            member_prefix, member_name = member.rsplit('.', 1)\n        except ValueError:\n            member_name = name\n            member_prefix = ''\n        finally:\n            name = member_name\n            if prefix and member_prefix:\n                prefix = '.'.join([prefix, member_prefix])\n            elif prefix is None and member_prefix:\n                prefix = member_prefix\n        fullname = name\n        if prefix:\n            fullname = '.'.join([prefix, name])\n\n        signode['module'] = mod_name\n        signode['object'] = prefix\n        signode['fullname'] = fullname\n\n        if self.display_prefix:\n            signode += addnodes.desc_annotation(self.display_prefix,\n                                                self.display_prefix)\n        if prefix:\n            signode += addnodes.desc_addname(prefix + '.', prefix + '.')\n        elif mod_name:\n            signode += addnodes.desc_addname(mod_name + '.', mod_name + '.')\n        signode += addnodes.desc_name(name, name)\n        if self.has_arguments:\n            paramlist = addnodes.desc_parameterlist()\n            if arglist:\n                paramlist += addnodes.desc_parameter(arglist, arglist)\n            signode += paramlist\n        return fullname, prefix\n\n    def add_target_and_index(self, name_obj, sig, signode):\n        # type: (Tuple[unicode, unicode], unicode, addnodes.desc_signature) -> None\n        mod_name = self.env.ref_context.get('sq:module')\n        fullname = (mod_name and mod_name + '.' or '') + name_obj[0]\n        if fullname not in self.state.document.ids:\n            signode['names'].append(fullname)\n            signode['ids'].append(fullname.replace('$', '_S_'))\n            signode['first'] = not self.names\n            self.state.document.note_explicit_target(signode)\n            objects = self.env.domaindata['sq']['objects']\n            if fullname in objects:\n                self.state_machine.reporter.warning(\n                    'duplicate object description of %s, ' % fullname +\n                    'other instance in ' +\n                    self.env.doc2path(objects[fullname][0]),\n                    line=self.lineno)\n            objects[fullname] = self.env.docname, self.objtype\n\n        indextext = self.get_index_text(mod_name, name_obj)\n        if indextext:\n            self.indexnode['entries'].append(('single', indextext,\n                                              fullname.replace('$', '_S_'),\n                                              '', None))\n\n    def get_index_text(self, objectname, name_obj):\n        # type: (unicode, Tuple[unicode, unicode]) -> unicode\n        name, obj = name_obj\n        if self.objtype == 'function':\n            if not obj:\n                return _('%s() (built-in function)') % name\n            return _('%s() (%s method)') % (name, obj)\n        elif self.objtype == 'class':\n            return _('%s() (class)') % name\n        elif self.objtype == 'data':\n            return _('%s (global variable or constant)') % name\n        elif self.objtype == 'attribute':\n            return _('%s (%s attribute)') % (name, obj)\n        return ''\n\n    def before_content(self):\n        # type: () -> None\n        \"\"\"Handle object nesting before content\n\n        :py:class:`SQObject` represents Quirrel language constructs. For\n        constructs that are nestable, this method will build up a stack of the\n        nesting hierarchy so that it can be later de-nested correctly, in\n        :py:meth:`after_content`.\n\n        For constructs that aren't nestable, the stack is bypassed, and instead\n        only the most recent object is tracked. This object prefix name will be\n        removed with :py:meth:`after_content`.\n\n        The following keys are used in ``self.env.ref_context``:\n\n            sq:objects\n                Stores the object prefix history. With each nested element, we\n                add the object prefix to this list. When we exit that object's\n                nesting level, :py:meth:`after_content` is triggered and the\n                prefix is removed from the end of the list.\n\n            sq:object\n                Current object prefix. This should generally reflect the last\n                element in the prefix history\n        \"\"\"\n        prefix = None\n        if self.names:\n            (obj_name, obj_name_prefix) = self.names.pop()\n            prefix = obj_name_prefix.strip('.') if obj_name_prefix else None\n            if self.allow_nesting:\n                prefix = obj_name\n        if prefix:\n            self.env.ref_context['sq:object'] = prefix\n            if self.allow_nesting:\n                objects = self.env.ref_context.setdefault('sq:objects', [])\n                objects.append(prefix)\n\n    def after_content(self):\n        # type: () -> None\n        \"\"\"Handle object de-nesting after content\n\n        If this class is a nestable object, removing the last nested class prefix\n        ends further nesting in the object.\n\n        If this class is not a nestable object, the list of classes should not\n        be altered as we didn't affect the nesting levels in\n        :py:meth:`before_content`.\n        \"\"\"\n        objects = self.env.ref_context.setdefault('sq:objects', [])\n        if self.allow_nesting:\n            try:\n                objects.pop()\n            except IndexError:\n                pass\n        self.env.ref_context['sq:object'] = (objects[-1] if len(objects) > 0\n                                             else None)\n\n\nclass SQCallable(SQObject):\n    \"\"\"Description of a Quirrel function, method or constructor.\"\"\"\n    has_arguments = True\n\n    doc_field_types = [\n        TypedField('arguments', label=_('Arguments'),\n                   names=('argument', 'arg', 'parameter', 'param'),\n                   typerolename='func', typenames=('paramtype', 'type')),\n        GroupedField('errors', label=_('Throws'), rolename='err',\n                     names=('throws', ),\n                     can_collapse=True),\n        Field('returnvalue', label=_('Returns'), has_arg=False,\n              names=('returns', 'return')),\n        Field('returntype', label=_('Return type'), has_arg=False,\n              names=('rtype',)),\n    ]\n\n\nclass SQConstructor(SQCallable):\n    \"\"\"Like a callable but with a different prefix.\"\"\"\n    display_prefix = 'class '\n    allow_nesting = True\n\n\nclass SQModule(SphinxDirective):\n    \"\"\"\n    Directive to mark description of a new Quirrel module.\n\n    This directive specifies the module name that will be used by objects that\n    follow this directive.\n\n    Options\n    -------\n\n    noindex\n        If the ``noindex`` option is specified, no linkable elements will be\n        created, and the module won't be added to the global module index. This\n        is useful for splitting up the module definition across multiple\n        sections or files.\n\n    :param mod_name: Module name\n    \"\"\"\n\n    has_content = False\n    required_arguments = 1\n    optional_arguments = 0\n    final_argument_whitespace = False\n    option_spec = {\n        'noindex': directives.flag\n    }\n\n    def run(self):\n        # type: () -> List[nodes.Node]\n        mod_name = self.arguments[0].strip()\n        self.env.ref_context['sq:module'] = mod_name\n        noindex = 'noindex' in self.options\n        ret = []\n        if not noindex:\n            self.env.domaindata['sq']['modules'][mod_name] = self.env.docname\n            # Make a duplicate entry in 'objects' to facilitate searching for\n            # the module in QuirrelDomain.find_obj()\n            self.env.domaindata['sq']['objects'][mod_name] = (self.env.docname, 'module')\n            targetnode = nodes.target('', '', ids=['module-' + mod_name],\n                                      ismod=True)\n            self.state.document.note_explicit_target(targetnode)\n            ret.append(targetnode)\n            indextext = _('%s (module)') % mod_name\n            inode = addnodes.index(entries=[('single', indextext,\n                                             'module-' + mod_name, '', None)])\n            ret.append(inode)\n        return ret\n\n\nclass SQXRefRole(XRefRole):\n    def process_link(self, env, refnode, has_explicit_title, title, target):\n        # type: (BuildEnvironment, nodes.Node, bool, unicode, unicode) -> Tuple[unicode, unicode]  # NOQA\n        # basically what sphinx.domains.python.PyXRefRole does\n        refnode['sq:object'] = env.ref_context.get('sq:object')\n        refnode['sq:module'] = env.ref_context.get('sq:module')\n        if not has_explicit_title:\n            title = title.lstrip('.')\n            target = target.lstrip('~')\n            if title[0:1] == '~':\n                title = title[1:]\n                dot = title.rfind('.')\n                if dot != -1:\n                    title = title[dot + 1:]\n        if target[0:1] == '.':\n            target = target[1:]\n            refnode['refspecific'] = True\n        return title, target\n\n\nclass QuirrelDomain(Domain):\n    \"\"\"Quirrel language domain.\"\"\"\n    name = 'sq'\n    label = 'Quirrel'\n    # if you add a new object type make sure to edit SQObject.get_index_string\n    object_types = {\n        'function':  ObjType(_('function'),  'func'),\n        'method':    ObjType(_('method'),    'meth'),\n        'class':     ObjType(_('class'),     'class'),\n        'data':      ObjType(_('data'),      'data'),\n        'attribute': ObjType(_('attribute'), 'attr'),\n        'module':    ObjType(_('module'),    'mod'),\n    }\n    directives = {\n        'function':  SQCallable,\n        'method':    SQCallable,\n        'class':     SQConstructor,\n        'data':      SQObject,\n        'attribute': SQObject,\n        'module':    SQModule,\n    }\n    roles = {\n        'func':  SQXRefRole(fix_parens=True),\n        'meth':  SQXRefRole(fix_parens=True),\n        'class': SQXRefRole(fix_parens=True),\n        'data':  SQXRefRole(),\n        'attr':  SQXRefRole(),\n        'mod':   SQXRefRole(),\n    }\n    initial_data = {\n        'objects': {},  # fullname -> docname, objtype\n        'modules': {},  # mod_name -> docname\n    }  # type: Dict[unicode, Dict[unicode, Tuple[unicode, unicode]]]\n\n    def clear_doc(self, docname):\n        # type: (unicode) -> None\n        for fullname, (pkg_docname, _l) in list(self.data['objects'].items()):\n            if pkg_docname == docname:\n                del self.data['objects'][fullname]\n        for mod_name, pkg_docname in list(self.data['modules'].items()):\n            if pkg_docname == docname:\n                del self.data['modules'][mod_name]\n\n    def merge_domaindata(self, docnames, otherdata):\n        # type: (List[unicode], Dict) -> None\n        # XXX check duplicates\n        for fullname, (fn, objtype) in otherdata['objects'].items():\n            if fn in docnames:\n                self.data['objects'][fullname] = (fn, objtype)\n        for mod_name, pkg_docname in otherdata['modules'].items():\n            if pkg_docname in docnames:\n                self.data['modules'][mod_name] = pkg_docname\n\n    def find_obj(self, env, mod_name, prefix, name, typ, searchorder=0):\n        # type: (BuildEnvironment, unicode, unicode, unicode, unicode, int) -> Tuple[unicode, Tuple[unicode, unicode]]  # NOQA\n        if name[-2:] == '()':\n            name = name[:-2]\n        objects = self.data['objects']\n\n        searches = []\n        if mod_name and prefix:\n            searches.append('.'.join([mod_name, prefix, name]))\n        if mod_name:\n            searches.append('.'.join([mod_name, name]))\n        if prefix:\n            searches.append('.'.join([prefix, name]))\n        searches.append(name)\n\n        if searchorder == 0:\n            searches.reverse()\n\n        newname = None\n        for search_name in searches:\n            if search_name in objects:\n                newname = search_name\n\n        return newname, objects.get(newname)\n\n    def resolve_xref(self, env, fromdocname, builder, typ, target, node,\n                     contnode):\n        # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node  # NOQA\n        mod_name = node.get('sq:module')\n        prefix = node.get('sq:object')\n        searchorder = node.hasattr('refspecific') and 1 or 0\n        name, obj = self.find_obj(env, mod_name, prefix, target, typ, searchorder)\n        if not obj:\n            return None\n        return make_refnode(builder, fromdocname, obj[0],\n                            name.replace('$', '_S_'), contnode, name)\n\n    def resolve_any_xref(self, env, fromdocname, builder, target, node,\n                         contnode):\n        # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]]  # NOQA\n        mod_name = node.get('sq:module')\n        prefix = node.get('sq:object')\n        name, obj = self.find_obj(env, mod_name, prefix, target, None, 1)\n        if not obj:\n            return []\n        return [('sq:' + self.role_for_objtype(obj[1]),\n                 make_refnode(builder, fromdocname, obj[0],\n                              name.replace('$', '_S_'), contnode, name))]\n\n    def get_objects(self):\n        # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]\n        for refname, (docname, type) in list(self.data['objects'].items()):\n            yield refname, refname, type, docname, \\\n                refname.replace('$', '_S_'), 1\n\n    def get_full_qualified_name(self, node):\n        # type: (nodes.Node) -> unicode\n        modname = node.get('sq:module')\n        prefix = node.get('sq:object')\n        target = node.get('reftarget')\n        if target is None:\n            return None\n        else:\n            return '.'.join(filter(None, [modname, prefix, target]))\n\n\ndef setup(app):\n    # type: (Sphinx) -> Dict[unicode, Any]\n    app.add_domain(QuirrelDomain)\n\n    return {\n        'version': 'builtin',\n        'env_version': 1,\n        'parallel_read_safe': True,\n        'parallel_write_safe': True,\n    }\n\nmyst_heading_anchors = 3\n\nmyst_enable_extensions = [\n    \"amsmath\",\n    \"colon_fence\",\n    \"deflist\",\n    \"dollarmath\",\n    \"fieldlist\",\n    \"html_admonition\",\n    \"html_image\",\n#    \"linkify\",\n    \"replacements\",\n    \"smartquotes\",\n    \"strikethrough\",\n    \"substitution\",\n    \"tasklist\",\n]\n"
  },
  {
    "path": "doc/source/quirrel_pygment_lexer.py",
    "content": "\"\"\"\n    pygments.lexers.quirrel\n    ~~~~~~~~~~~~~~~~~~~~~~~~~~\n    Lexers for Quirrel.\n    :copyright: Copyright 2022 by the Gaijin.\n    :license: BSD, see LICENSE for details.\n\"\"\"\n\nimport re\n\nfrom pygments.lexer import bygroups, combined, default, do_insertions, include, \\\n    inherit, Lexer, RegexLexer, this, using, words\nfrom pygments.token import Text, Comment, Operator, Keyword, Name, String, \\\n    Number, Punctuation, Other, Generic, Whitespace\nfrom pygments.util import get_bool_opt\nimport pygments.unistring as uni\nfrom sphinx.highlighting import lexers\n\n__all__ = ['QuirrelLexer']\n\nSQ_IDENT_START = ('(?:[$_' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl') +\n                  ']|\\\\\\\\u[a-fA-F0-9]{4})')\nSQ_IDENT_PART = ('(?:[$' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl',\n                                       'Mn', 'Mc', 'Nd', 'Pc') +\n                 '\\u200c\\u200d]|\\\\\\\\u[a-fA-F0-9]{4})')\nSQ_IDENT = SQ_IDENT_START + '(?:' + SQ_IDENT_PART + ')*'\n\nline_re = re.compile('.*?\\n')\n\nclass QuirrelLexer(RegexLexer):\n    \"\"\"\n    For Quirrel source code.\n    \"\"\"\n\n    name = 'Quirrel'\n    url = 'https://quirrel.io'\n    aliases = ['javascript', 'js']\n    filenames = ['*.nut']\n    mimetypes = ['application/quirrel', 'application/squirrel']\n\n    flags = re.DOTALL | re.MULTILINE\n\n    tokens = {\n        'commentsandwhitespace': [\n            (r'\\s+', Whitespace),\n            (r'<!--', Comment),\n            (r'//.*?$', Comment.Single),\n            (r'/\\*.*?\\*/', Comment.Multiline)\n        ],\n        'slashstartsregex': [\n            include('commentsandwhitespace'),\n            (r'/(\\\\.|[^[/\\\\\\n]|\\[(\\\\.|[^\\]\\\\\\n])*])+/'\n             r'([gimuysd]+\\b|\\B)', String.Regex, '#pop'),\n            (r'(?=/)', Text, ('#pop', 'badregex')),\n            default('#pop')\n        ],\n        'badregex': [\n            (r'\\n', Whitespace, '#pop')\n        ],\n        'root': [\n            (r'^(?=\\s|/|<!--)', Text, 'slashstartsregex'),\n            include('commentsandwhitespace'),\n\n            # Numeric literals\n            (r'0[bB][01]+n?', Number.Bin),\n            (r'0[oO]?[0-7]+n?', Number.Oct),  # Browsers support \"0o7\" and \"07\" (< ES5) notations\n            (r'0[xX][0-9a-fA-F]+n?', Number.Hex),\n            (r'[0-9]+n', Number.Integer),  # Javascript BigInt requires an \"n\" postfix\n            # Javascript doesn't have actual integer literals, so every other\n            # numeric literal is handled by the regex below (including \"normal\")\n            # integers\n            (r'(\\.[0-9]+|[0-9]+\\.[0-9]*|[0-9]+)([eE][-+]?[0-9]+)?', Number.Float),\n\n            (r'\\.\\.\\.|=>', Punctuation),\n            (r'\\+\\+|--|~|\\?\\?=?|\\?|:|\\\\(?=\\n)|'\n             r'(<<|>>>?|==?|!=?|(?:\\*\\*|\\|\\||&&|[-<>+*%&|^/]))=?', Operator, 'slashstartsregex'),\n            (r'[{(\\[;,]', Punctuation, 'slashstartsregex'),\n            (r'[})\\].]', Punctuation),\n\n            (r'(typeof|instanceof|in|not in|delete)\\b', Operator.Word, 'slashstartsregex'),\n\n            # Match stuff like: constructor\n            (r'\\b(constructor|from|import)\\b', Keyword.Reserved),\n\n            (r'(foreach|for|in|while|do|break|return|continue|switch|case|default|if|else|'\n             r'throw|try|catch|yield|this|of|static|'\n             r'import|base)\\b', Keyword, 'slashstartsregex'),\n            (r'(local|let|const|function|class)\\b', Keyword.Declaration, 'slashstartsregex'),\n\n#            (r'(static)\\b', Keyword.Reserved),\n            (r'(true|false|null)\\b', Keyword.Constant),\n\n            (r'(require|print|println|assert|type)\\b', Name.Builtin),\n\n            (r'((?:Eval|Internal|Range|Reference|Syntax|Type|URI)?Error)\\b', Name.Exception),\n\n            # Match stuff like: super(argument, list)\n#            (r'(super)(\\s*)(\\([\\w,?.$\\s]+\\s*\\))',\n#             bygroups(Keyword, Whitespace), 'slashstartsregex'),\n            # Match stuff like: function() {...}\n            (r'([a-zA-Z_?.$][\\w?.$]*)(?=\\(\\) \\{)', Name.Other, 'slashstartsregex'),\n\n            (SQ_IDENT, Name.Other),\n            (r'\"(\\\\\\\\|\\\\[^\\\\]|[^\"\\\\])*\"', String.Double),\n            (r\"'(\\\\\\\\|\\\\[^\\\\]|[^'\\\\])*'\", String.Single),\n            (r'`', String.Backtick, 'interp'),\n        ],\n        'interp': [\n            (r'`', String.Backtick, '#pop'),\n            (r'\\\\.', String.Backtick),\n            (r'\\$\\{', String.Interpol, 'interp-inside'),\n            (r'\\$', String.Backtick),\n            (r'[^`\\\\$]+', String.Backtick),\n        ],\n        'interp-inside': [\n            # TODO: should this include single-line comments and allow nesting strings?\n            (r'\\}', String.Interpol, '#pop'),\n            include('root'),\n        ],\n    }\n\nlexers['sq'] = QuirrelLexer(startinline=True)\nlexers['quirrel'] = QuirrelLexer(startinline=True)\n\ndef setup(app):\n    return {\n        'version': 'builtin',\n        'env_version': 1,\n        'parallel_read_safe': True,\n        'parallel_write_safe': True,\n    }\n\n"
  },
  {
    "path": "doc/source/reference/api/bytecode_serialization.rst",
    "content": ".. _api_ref_bytecode_serialization:\n\n======================\nBytecode serialization\n======================\n\n.. _sq_readclosure:\n\n.. c:function:: SQRESULT sq_readclosure(HSQUIRRELVM v, SQREADFUNC readf, SQUserPointer up)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQREADFUNC readf: pointer to a read function that will be invoked by the vm during the serialization.\n    :param SQUserPointer up: pointer that will be passed to each call to the read function\n    :returns: a SQRESULT\n\nserialize (read) a closure and pushes it on top of the stack, the source is user defined through a read callback.\n\n\n\n\n\n.. _sq_writeclosure:\n\n.. c:function:: SQRESULT sq_writeclosure(HSQUIRRELVM v, SQWRITEFUNC writef, SQUserPointer up)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQWRITEFUNC writef: pointer to a write function that will be invoked by the vm during the serialization.\n    :param SQUserPointer up: pointer that will be passed to each call to the write function\n    :returns: a SQRESULT\n    :remarks: closures with free variables cannot be serialized\n\nserializes(writes) the closure on top of the stack, the destination is user defined through a write callback.\n"
  },
  {
    "path": "doc/source/reference/api/calls.rst",
    "content": ".. _api_ref_calls:\n\n=====\nCalls\n=====\n\n.. _sq_call:\n\n.. c:function:: SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool invoke_err_handler)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger params: number of parameters of the function\n    :param SQBool retval: if true the function will push the return value in the stack\n    :param SQBool invoke_err_handler: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.\n    :returns: a SQRESULT\n\ncalls a closure or a native closure. The function pops all the parameters and leave the closure in the stack; if retval is true the return value of the closure is pushed. If the execution of the function is suspended through sq_suspendvm(), the closure and the arguments will not be automatically popped from the stack.\n\nWhen using to create an instance, push a dummy parameter to be filled with the newly-created instance for the constructor's 'this' parameter.\n\n\n\n.. _sq_getcallee:\n\n.. c:function:: SQRESULT sq_getcallee(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a SQRESULT\n\npush in the stack the currently running closure.\n\n\n\n\n\n.. _sq_getlasterror:\n\n.. c:function:: SQRESULT sq_getlasterror(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a SQRESULT\n    :remarks: the pushed error descriptor can be any valid quirrel type.\n\npushes the last error in the stack.\n\n\n\n\n\n.. _sq_getlocal:\n\n.. c:function:: const char * sq_getlocal(HSQUIRRELVM v, SQUnsignedInteger level, SQUnsignedInteger nseq)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUnsignedInteger level: the function index in the calls stack, 0 is the current function\n    :param SQUnsignedInteger nseq: the index of the local variable in the stack frame (0 is 'this')\n    :returns: the name of the local variable if a variable exists at the given level/seq otherwise NULL.\n\nReturns the name of a local variable given stackframe and sequence in the stack and pushes is current value. Free variables are treated as local variables, by sq_getlocal(), and will be returned as they would be at the base of the stack, just before the real local variables.\n\n\n\n\n\n.. _sq_reseterror:\n\n.. c:function:: void sq_reseterror(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\nreset the last error in the virtual machine to null\n\n\n\n\n\n.. _sq_resume:\n\n.. c:function:: SQRESULT sq_resume(HSQUIRRELVM v, SQBool retval, SQBool invoke_err_handler)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool retval: if true the function will push the return value in the stack\n    :param SQBool invoke_err_handler: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.\n    :returns: a SQRESULT\n    :remarks: if retval != 0 the return value of the generator is pushed.\n\nresumes the generator at the top position of the stack.\n\n\n.. _sq_tailcall:\n\n.. c:function:: SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger params: number of parameters of the function\n\n\tCalls a closure and removes the caller function from the call stack.\n\tThis function must be invoke from a native closure and \n\the return value of sq_tailcall must be returned by the caller function(see example).\n\t\n*.eg*\n\n::\n\n    SQInteger tailcall_something_example(HSQUIRRELVM v)\n    {\n\t\t//push closure and parameters here\n\t\t... \n        return sq_tailcall(v,2);\n    }\n\n.. _sq_throwerror:\n\n.. c:function:: SQRESULT sq_throwerror(HSQUIRRELVM v, const char * err)\n\n    :param HSQUIRRELVM v: the target VM\n    :param const char * err: the description of the error that has to be thrown\n    :returns: the value that has to be returned by a native closure in order to throw an exception in the virtual machine.\n\nsets the last error in the virtual machine and returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine.\n\n\n.. _sq_throwobject:\n\n.. c:function:: SQRESULT sq_throwobject(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the value that has to be returned by a native closure in order to throw an exception in the virtual machine.\n\npops a value from the stack sets it as the last error in the virtual machine. Returns the value that has to be returned by a native closure in order to trigger an exception in the virtual machine (aka SQ_ERROR).\n"
  },
  {
    "path": "doc/source/reference/api/compiler.rst",
    "content": ".. _api_ref_compiler:\n\n========\nCompiler\n========\n\n\n.. _sq_compile:\n\n.. c:function:: SQRESULT sq_compile(HSQUIRRELVM v, const char* s, SQInteger size, const char * sourcename, SQBool raiseerror, const HSQOBJECT *bindings = nullptr)\n\n    :param HSQUIRRELVM v: the target VM\n    :param const char* s: a pointer to the buffer that has to be compiled.\n    :param SQInteger size: size in characters of the buffer passed in the parameter 's'.\n    :param const char * sourcename: the symbolic name of the program (used only for more meaningful runtime errors)\n    :param SQBool raiseerror: if this value true the compiler error handler will be called in case of an error\n    :param const HSQOBJECT \\*bindings: optional compile-time bindings object (default: nullptr)\n    :returns: a SQRESULT. If the sq_compile fails nothing is pushed in the stack.\n    :remarks: in case of an error the function will call the function set by sq_setcompilererrorhandler().\n\ncompiles a quirrel program from a memory buffer; if it succeeds, push the compiled script as function in the stack.\n\n\n\n.. _sq_notifyallexceptions:\n\n.. c:function:: void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool enable: if true enables the error callback notification of handled exceptions.\n    :remarks: By default the VM will invoke the error callback only if an exception is not handled (no try/catch traps are present in the call stack). If notifyallexceptions is enabled, the VM will call the error callback for any exception even if between try/catch blocks. This feature is useful for implementing debuggers.\n\nenable/disable the error callback notification of handled exceptions.\n\n\n\n\n\n.. _sq_setcompilererrorhandler:\n\n.. c:function:: void sq_setcompilererrorhandler(HSQUIRRELVM v, SQCOMPILERERROR f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQCOMPILERERROR f: A pointer to the error handler function\n    :remarks: if the parameter f is NULL no function will be called when a compiler error occurs. The compiler error handler is shared between friend VMs.\n\nsets the compiler error handler function\n\n\n.. _sq_getcompilererrorhandler:\n\n.. c:function:: SQCOMPILERERROR sq_getcompilererrorhandler(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a pointer to the current compiler error handler function, or NULL if no function is set\n\ngets the current compiler error handler function\n\n\n.. _sq_setcompilerdiaghandler:\n\n.. c:function:: void sq_setcompilerdiaghandler(HSQUIRRELVM v, SQ_COMPILER_DIAG_CB f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQ_COMPILER_DIAG_CB f: A pointer to the diagnostic callback function\n    :remarks: if the parameter f is NULL no function will be called when a compiler diagnostic occurs.\n\nsets the compiler diagnostic callback function\n"
  },
  {
    "path": "doc/source/reference/api/debug_interface.rst",
    "content": ".. _api_ref_debug_interface:\n\n===============\nDebug interface\n===============\n\n.. _sq_getfunctioninfo:\n\n.. c:function:: SQRESULT sq_getfunctioninfo(HSQUIRRELVM v, SQInteger level, SQFunctionInfo * fi)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger level: calls stack level\n    :param SQFunctionInfo * fi: pointer to the SQFunctionInfo structure that will store the closure informations\n    :returns: a SQRESULT.\n    :remarks: the member 'funcid' of the returned SQFunctionInfo structure is a unique identifier of the function; this can be useful to identify a specific piece of quirrel code in an application like for instance a profiler. this method will fail if the closure in the stack is a native C closure.\n\n\n\n*.eg*\n\n::\n\n\n    typedef struct tagSQFunctionInfo {\n        SQUserPointer funcid; //unique identifier for a function (all its closures will share the same funcid)\n        const char *name; //function name\n        const char *source; //function source file name\n    }SQFunctionInfo;\n\n\n\n\n\n\n\n.. _sq_setdebughook:\n\n.. c:function:: void sq_setdebughook(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: In order to receive a 'per line' callback, is necessary to compile the scripts with the line informations. Without line informations activated, only the 'call/return' callbacks will be invoked.\n\npops a closure from the stack an sets it as debug hook. When a debug hook is set it overrides any previously set native or non native hooks. if the hook is null the debug hook will be disabled.\n\n\n\n\n\n.. _sq_setnativedebughook:\n\n.. c:function:: void sq_setnativedebughook(HSQUIRRELVM v, SQDEBUGHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQDEBUGHOOK hook: the native hook function\n    :remarks: In order to receive a 'per line' callback, is necessary to compile the scripts with the line informations. Without line informations activated, only the 'call/return' callbacks will be invoked.\n\nsets the native debug hook. When a native hook is set it overrides any previously set native or non native hooks. if the hook is NULL the debug hook will be disabled.\n\n\n\n\n\n.. _sq_stackinfos:\n\n.. c:function:: SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos * si)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger level: calls stack level\n    :param SQStackInfos * si: pointer to the SQStackInfos structure that will store the stack informations\n    :returns: a SQRESULT.\n\nretrieve the calls stack informations of a ceratain level in the calls stack.\n"
  },
  {
    "path": "doc/source/reference/api/garbage_collector.rst",
    "content": ".. _api_ref_garbage_collector:\n\n=================\nGarbage Collector\n=================\n\n.. _sq_collectgarbage:\n\n.. c:function:: SQInteger sq_collectgarbage(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: this api only works with garbage collector builds (NO_GARBAGE_COLLECTOR is not defined)\n\nruns the garbage collector and returns the number of reference cycles found (and deleted)\n\n\n\n\n\n.. _sq_resurrectunreachable:\n\n.. c:function:: SQRESULT sq_resurrectunreachable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: this api only works with garbage collector builds (NO_GARBAGE_COLLECTOR is not defined)\n\nruns the garbage collector and pushes an array in the stack containing all unreachable object found. If no unreachable object is found, null is pushed instead. This function is meant to help debug reference cycles.\n"
  },
  {
    "path": "doc/source/reference/api/object_creation_and_handling.rst",
    "content": ".. _api_ref_object_creation_and_handling:\n\n============================\nObject creation and handling\n============================\n\n.. _sq_bindenv:\n\n.. c:function:: SQRESULT sq_bindenv(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :returns: a SQRESULT\n    :remarks: the cloned closure holds the environment object as weak reference\n\npops an object from the stack (must be a table, instance, or class); clones the closure at position idx in the stack and sets the popped object as environment of the cloned closure. Then pushes the new cloned closure on top of the stack.\n\n\n\n\n\n.. _sq_createinstance:\n\n.. c:function:: SQRESULT sq_createinstance(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class\n    :returns: a SQRESULT\n    :remarks: the function doesn't invoke the instance contructor. To create an instance and automatically invoke its contructor, sq_call must be used instead.\n\ncreates an instance of the class at 'idx' position in the stack. The new class instance is pushed on top of the stack.\n\n\n\n\n\n.. _sq_getbool:\n\n.. c:function:: SQRESULT sq_getbool(HSQUIRRELVM v, SQInteger idx, SQBool * b)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQBool * b: A pointer to the bool that will store the value\n    :returns: a SQRESULT\n\ngets the value of the bool at the idx position in the stack.\n\n\n\n\n\n.. _sq_getbyhandle:\n\n.. c:function:: SQRESULT sq_getbyhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class or instance\n    :param HSQMEMBERHANDLE* handle: a pointer to the member handle\n    :returns: a SQRESULT\n\npushes the value of a class or instance member using a member handle (see sq_getmemberhandle)\n\n\n\n\n\n.. _sq_getclosureinfo:\n\n.. c:function:: SQRESULT sq_getclosureinfo(HSQUIRRELVM v, SQInteger idx, SQInteger * nparams, SQInteger * nfreevars)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :param SQInteger * nparams: a pointer to an integer that will store the number of parameters\n    :param SQInteger * nfreevars: a pointer to an integer that will store the number of free variables\n    :returns: an SQRESULT\n\nretrieves number of parameters and number of freevariables from a quirrel closure.\n\n\n\n\n\n.. _sq_getclosurename:\n\n.. c:function:: SQRESULT sq_getclosurename(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target closure\n    :returns: an SQRESULT\n\npushes the name of the closure at position idx in the stack. Note that the name can be a string or null if the closure is anonymous or a native closure with no name assigned to it.\n\n\n\n.. _sq_getfloat:\n\n.. c:function:: SQRESULT sq_getfloat(HSQUIRRELVM v, SQInteger idx, SQFloat * f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQFloat * f: A pointer to the float that will store the value\n    :returns: a SQRESULT\n\ngets the value of the float at the idx position in the stack.\n\n\n\n\n\n.. _sq_gethash:\n\n.. c:function:: SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: the hash key of the value at the position idx in the stack\n    :remarks: the hash value function is the same used by the VM.\n\nreturns the hash key of a value at the idx position in the stack.\n\n\n\n\n\n.. _sq_getinstanceup:\n\n.. c:function:: SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer * up, SQUSerPointer typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * up: a pointer to the userpointer that will store the result\n    :param SQUSerPointer typetag: the typetag that has to be checked, if this value is set to 0 the typetag is ignored.\n    :returns: a SQRESULT\n\ngets the userpointer of the class instance at position idx in the stack. if the parameter 'typetag' is different than 0, the function checks that the class or a base class of the instance is tagged with the specified tag; if not the function fails. If 'typetag' is 0 the function will ignore the tag check.\n\n\n\n\n\n.. _sq_getinteger:\n\n.. c:function:: SQRESULT sq_getinteger(HSQUIRRELVM v, SQInteger idx, SQInteger * i)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQInteger * i: A pointer to the integer that will store the value\n    :returns: a SQRESULT\n\ngets the value of the integer at the idx position in the stack.\n\n\n\n\n\n.. _sq_getmemberhandle:\n\n.. c:function:: SQRESULT sq_getmemberhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class\n    :param HSQMEMBERHANDLE* handle: a pointer to the variable that will store the handle\n    :returns: a SQRESULT\n    :remarks: This method works only with classes. A handle retrieved through a class can be later used to set or get values from one of the class instances. Handles retrieved from base classes are still valid in derived classes and respect inheritance rules.\n\npops a value from the stack and uses it as index to fetch the handle of a class member. The handle can be later used to set or get the member value using sq_getbyhandle(), sq_setbyhandle().\n\n\n\n\n\n.. _sq_getreleasehook:\n\n.. c:function:: SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :remarks: if the object that position idx is not an userdata, class instance or class the function returns NULL.\n\ngets the release hook of the userdata, class instance or class at position idx in the stack.\n\n\n\n\n\n.. _sq_getscratchpad:\n\n.. c:function:: char * sq_getscratchpad(HSQUIRRELVM v, SQInteger minsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger minsize: the requested size for the scratchpad buffer\n    :remarks: the buffer is valid until the next call to sq_getscratchpad\n\nreturns a pointer to a memory buffer that is at least as big as minsize.\n\n\n\n\n\n.. _sq_getsize:\n\n.. c:function:: SQObjectType sq_getsize(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: the size of the value at the position idx in the stack\n    :remarks: this function only works with strings, arrays, tables, classes, instances, and userdata if the value is not a valid type, the function will return -1.\n\nreturns the size of a value at the idx position in the stack. If the value is a class or a class instance the size returned is the size of the userdata buffer (see sq_setclassudsize).\n\n\n\n\n\n.. _sq_getstring:\n\n.. c:function:: SQRESULT sq_getstring(HSQUIRRELVM v, SQInteger idx, const char ** c)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param const char ** c: a pointer to the pointer that will point to the string\n    :returns: a SQRESULT\n\ngets a pointer to the string at the idx position in the stack.\n\n\n\n\n\n.. _sq_getstringandsize:\n\n.. c:function:: SQRESULT sq_getstringandsize(HSQUIRRELVM v, SQInteger idx, const char ** c, SQInteger* size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param const char ** c: a pointer to the pointer that will point to the string\n    :param SQInteger * size: a pointer to a SQInteger which will receive the size of the string\n    :returns: a SQRESULT\n\ngets a pointer to the string at the idx position in the stack; additionally retrieves its size.\n\n\n\n\n.. _sq_getthread:\n\n.. c:function:: SQRESULT sq_getthread(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM* vthread)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param HSQUIRRELVM* vthread: A pointer to the variable that will store the thread pointer\n    :returns: a SQRESULT\n\ngets a pointer to the thread the idx position in the stack.\n\n\n\n\n\n.. _sq_gettype:\n\n.. c:function:: SQObjectType sq_gettype(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: the type of the value at the position idx in the stack\n\nreturns the type of the value at the position idx in the stack\n\n\n\n\n\n.. _sq_gettypetag:\n\n.. c:function:: SQRESULT sq_gettypetag(HSQUIRRELVM v, SQInteger idx, SQUserPointer * typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * typetag: a pointer to the variable that will store the tag\n    :returns: a SQRESULT\n    :remarks: the function works also with instances. if the target object is an instance, the typetag of its base class is fetched.\n\ngets the typetag of the object (userdata or class) at position idx in the stack.\n\n\n\n\n\n.. _sq_getuserdata:\n\n.. c:function:: SQRESULT sq_getuserdata(HSQUIRRELVM v, SQInteger idx, SQUserPointer * p, SQUserPointer * typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * p: A pointer to the userpointer that will point to the userdata's payload\n    :param SQUserPointer * typetag: A pointer to a SQUserPointer that will store the userdata tag(see sq_settypetag). The parameter can be NULL.\n    :returns: a SQRESULT\n\ngets a pointer to the value of the userdata at the idx position in the stack.\n\n\n\n\n\n.. _sq_getuserpointer:\n\n.. c:function:: SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer * p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer * p: A pointer to the userpointer that will store the value\n    :returns: a SQRESULT\n\ngets the value of the userpointer at the idx position in the stack.\n\n\n\n\n\n.. _sq_newarray:\n\n.. c:function:: void sq_newarray(HSQUIRRELVM v, SQInteger size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger size: the size of the array that as to be created\n\ncreates a new array and pushes it in the stack\n\n\n\n\n\n.. _sq_newclass:\n\n.. c:function:: SQRESULT sq_newclass(HSQUIRRELVM v, SQBool hasbase)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool hasbase: if the parameter is true the function expects a base class on top of the stack.\n    :returns: a SQRESULT\n\ncreates a new class object. If the parameter 'hasbase' is different than 0, the function pops a class from the stack and inherits the new created class from it. The new class is pushed in the stack.\n\n\n\n\n\n.. _sq_newclosure:\n\n.. c:function:: void sq_newclosure(HSQUIRRELVM v, HSQFUNCTION func, SQInteger nfreevars)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQFUNCTION func: a pointer to a native-function\n    :param SQInteger nfreevars: number of free variables(can be 0)\n\ncreate a new native closure, pops n values set those as free variables of the new closure, and push the new closure in the stack.\n\n\n\n\n\n.. _sq_newtable:\n\n.. c:function:: void sq_newtable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\ncreates a new table and pushes it in the stack\n\n\n\n\n\n.. _sq_newtableex:\n\n.. c:function:: void sq_newtableex(HSQUIRRELVM v, SQInteger initialcapacity)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger initialcapacity: number of key/value pairs to preallocate\n\ncreates a new table and pushes it in the stack. This function allows you to specify the initial capacity of the table to prevent unnecessary rehashing when the number of slots required is known at creation-time.\n\n\n\n\n\n.. _sq_newuserdata:\n\n.. c:function:: SQUserPointer sq_newuserdata(HSQUIRRELVM v, SQUnsignedInteger size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUnsignedInteger size: the size of the userdata that as to be created in bytes\n\ncreates a new userdata and pushes it in the stack\n\n\n\n\n\n.. _sq_pushbool:\n\n.. c:function:: void sq_pushbool(HSQUIRRELVM v, SQBool b)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool b: the bool that has to be pushed(SQTrue or SQFalse)\n\npushes a bool into the stack\n\n\n\n\n\n.. _sq_pushfloat:\n\n.. c:function:: void sq_pushfloat(HSQUIRRELVM v, SQFloat f)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQFloat f: the float that has to be pushed\n\npushes a float into the stack\n\n\n\n\n\n.. _sq_pushinteger:\n\n.. c:function:: void sq_pushinteger(HSQUIRRELVM v, SQInteger n)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger n: the integer that has to be pushed\n\npushes an integer into the stack\n\n\n\n\n\n.. _sq_pushnull:\n\n.. c:function:: void sq_pushnull(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes a null value into the stack\n\n\n\n\n\n.. _sq_pushstring:\n\n.. c:function:: void sq_pushstring(HSQUIRRELVM v, const char * s, SQInteger len)\n\n    :param HSQUIRRELVM v: the target VM\n    :param const char * s: pointer to the string that has to be pushed\n    :param SQInteger len: length of the string pointed by s\n    :remarks: if the parameter len is less than 0 the VM will calculate the length using strlen(s)\n\npushes a string in the stack\n\n\n\n\n\n.. _sq_pushuserpointer:\n\n.. c:function:: void sq_pushuserpointer(HSQUIRRELVM v, SQUserPointer p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUserPointer p: the pointer that as to be pushed\n\npushes a userpointer into the stack\n\n\n\n\n\n.. _sq_setbyhandle:\n\n.. c:function:: SQRESULT sq_setbyhandle(HSQUIRRELVM v, SQInteger idx, HSQMEMBERHANDLE* handle)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class\n    :param HSQMEMBERHANDLE* handle: a pointer the member handle\n    :returns: a SQRESULT\n\npops a value from the stack and sets it to a class or instance member using a member handle (see sq_getmemberhandle)\n\n\n\n\n\n.. _sq_setclassudsize:\n\n.. c:function:: SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack pointing to the class\n    :param SQInteger udsize: size in bytes reserved for user data\n    :returns: a SQRESULT\n\nSets the user data size of a class. If a class 'user data size' is greater than 0. When an instance of the class is created additional space will be reserved at the end of the memory chunk where the instance is stored. The userpointer of the instance will also be automatically set to this memory area. This allows you to minimize allocations in applications that have to carry data along with the class instance.\n\n\n\n\n.. _sq_setinstanceup:\n\n.. c:function:: SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer up)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer up: an arbitrary user pointer\n    :returns: a SQRESULT\n\nsets the userpointer of the class instance at position idx in the stack.\n\n\n\n\n\n.. _sq_setnativeclosurename:\n\n.. c:function:: SQRESULT sq_setnativeclosurename(HSQUIRRELVM v, SQInteger idx, const char * name)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target native closure\n    :param const char * name: the name that has to be set\n    :returns: an SQRESULT\n\nsets the name of the native closure at the position idx in the stack. The name of a native closure is purely for debug purposes. The name is retrieved through the function sq_stackinfos() while the closure is in the call stack.\n\n\n\n\n\n.. _sq_setparamscheck:\n\n.. c:function:: SQRESULT sq_setparamscheck(HSQUIRRELVM v, SQInteger nparamscheck, const char * typemask)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nparamscheck: defines the parameters number check policy (0 disables the param checking). If nparamscheck is greater than 0, the VM ensures that the number of parameters is exactly the number specified in nparamscheck (eg. if nparamscheck == 3 the function can only be called with 3 parameters). If nparamscheck is less than 0 the VM ensures that the closure is called with at least the absolute value of the number specified in nparamcheck (eg. nparamscheck == -3 will check that the function is called with at least 3 parameters). The hidden parameter 'this' is included in this number; free variables aren't. If SQ_MATCHTYPEMASKSTRING is passed instead of the number of parameters, the function will automatically infer the number of parameters to check from the typemask (eg. if the typemask is \".sn\", it is like passing 3).\n    :param const char * typemask: defines a mask to validate the parametes types passed to the function. If the parameter is NULL, no typechecking is applied (default).\n    :remarks: The typemask consists in a zero terminated string that represent the expected parameter type. The types are expressed as follows: 'o' null, 'i' integer, 'f' float, 'n' integer or float, 's' string, 't' table, 'a' array, 'u' userdata, 'c' closure and nativeclosure, 'g' generator, 'p' userpointer, 'v' thread, 'x' instance(class instance), 'y' class, 'b' bool. and '.' any type. The symbol '|' can be used as 'or' to accept multiple types on the same parameter. There isn't any limit on the number of 'or' that can be used. Spaces are ignored so can be inserted between types to increase readability. For instance to check a function that expect a table as 'this' a string as first parameter and a number or a userpointer as second parameter, the string would be \"tsn|p\" (table,string,number or userpointer). If the parameters mask is contains fewer parameters than 'nparamscheck', the remaining parameters will not be typechecked.\n\nSets the parameter validation scheme for the native closure at the top position in the stack. Allows you to validate the number of parameters accepted by the function and optionally their types. If the function call does not comply with the parameter schema set by sq_setparamscheck, an exception is thrown.\n\n*.eg*\n\n::\n\n    //example\n    SQInteger testy(HSQUIRRELVM v)\n    {\n        SQUserPointer p;\n        const char *s;\n        SQInteger i;\n        //no type checking, if the call complies with the mask\n        //surely the functions will succeed.\n        sq_getuserdata(v,1,&p,NULL);\n        sq_getstring(v,2,&s);\n        sq_getinteger(v,3,&i);\n        //... do something\n        return 0;\n    }\n\n    //the reg code\n\n    //....stuff\n    sq_newclosure(v,testy,0);\n    //expects exactly 3 parameters(userdata,string,number)\n    sq_setparamscheck(v,3,\"usn\");\n    //....stuff\n\n\n\n\n\n\n.. _sq_setreleasehook:\n\n.. c:function:: void sq_setreleasehook(HSQUIRRELVM v, SQInteger idx, SQRELEASEHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQRELEASEHOOK hook: a function pointer to the hook(see sample below)\n    :remarks: the function hook is called by the VM before the userdata memory is deleted.\n\nsets the release hook of the userdata, class instance, or class at position idx in the stack.\n\n*.eg*\n\n::\n\n\n    /* tyedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); */\n\n    SQInteger my_release_hook(SQUserPointer p,SQInteger size)\n    {\n        /* do something here */\n        return 1;\n    }\n\n\n\n\n\n\n.. _sq_settypetag:\n\n.. c:function:: SQRESULT sq_settypetag(HSQUIRRELVM v, SQInteger idx, SQUserPointer typetag)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQUserPointer typetag: an arbitrary SQUserPointer\n    :returns: a SQRESULT\n\nsets the typetag of the object (userdata or class) at position idx in the stack.\n\n\n\n\n\n.. _sq_tobool:\n\n.. c:function:: void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool * b)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :param SQBool * b: A pointer to the bool that will store the value\n    :remarks: if the object is not a bool the function converts the value to bool according to quirrel's rules. For instance the number 1 will result in true, and the number 0 in false.\n\ngets the value at position idx in the stack as bool.\n\n\n\n\n\n.. _sq_tostring:\n\n.. c:function:: void sq_tostring(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n\nconverts the object at position idx in the stack to string and pushes the resulting string in the stack.\n\n\n\n\n\n.. _sq_typeof:\n\n.. c:function:: SQObjectType sq_typeof(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: an index in the stack\n    :returns: a SQRESULT\n\npushes the type name of the value at the position idx in the stack. It also invokes the _typeof metamethod for tables and class instances that implement it; in that case the pushed object could be something other than a string (is up to the _typeof implementation).\n\n\n\n"
  },
  {
    "path": "doc/source/reference/api/object_manipulation.rst",
    "content": ".. _api_ref_object_manipulation:\n\n====================\nObject manipulation\n====================\n\n.. _sq_arrayappend:\n\n.. c:function:: SQRESULT sq_arrayappend(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\npops a value from the stack and pushes it in the back of the array at the position idx in the stack.\n\n\n\n\n\n.. _sq_arrayinsert:\n\n.. c:function:: SQRESULT sq_arrayinsert(HSQUIRRELVM v, SQInteger idx, SQInteger destpos)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :param SQInteger destpos: the position in the array where the item has to be inserted\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\npops a value from the stack and inserts it in an array at the specified position\n\n\n\n\n\n.. _sq_arraypop:\n\n.. c:function:: SQRESULT sq_arraypop(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\npops a value from the back of the array at the position idx in the stack.\n\n\n\n\n\n.. _sq_arrayremove:\n\n.. c:function:: SQRESULT sq_arrayremove(HSQUIRRELVM v, SQInteger idx, SQInteger itemidx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :param SQInteger itemidx: the index of the item in the array that has to be removed\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\nremoves an item from an array\n\n\n\n\n\n.. _sq_arrayresize:\n\n.. c:function:: SQRESULT sq_arrayresize(HSQUIRRELVM v, SQInteger idx, SQInteger newsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :param SQInteger newsize: requested size of the array\n    :returns: a SQRESULT\n    :remarks: Only works on arrays. If newsize if greater than the current size the new array slots will be filled with nulls.\n\nresizes the array at the position idx in the stack.\n\n\n\n\n\n.. _sq_arrayreverse:\n\n.. c:function:: SQRESULT sq_arrayreverse(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target array in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on arrays.\n\nreverses an array in place.\n\n\n\n\n\n.. _sq_clear:\n\n.. c:function:: SQRESULT sq_clear(HSQUIRRELVM v, SQInteger idx, SQBool freemem)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :param SQBool freemem: free allocated memory if needed. SQTrue by default.\n    :returns: a SQRESULT\n    :remarks: Only works on tables and arrays.\n\nclears all the elements of the table/array at position idx in the stack.\n\n\n\n\n\n.. _sq_clone:\n\n.. c:function:: SQRESULT sq_clone(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n\npushes a clone of the table, array, or class instance at the position idx.\n\n\n\n\n\n.. _sq_deleteslot:\n\n.. c:function:: SQRESULT sq_deleteslot(HSQUIRRELVM v, SQInteger idx, SQBool pushval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool pushval: if this param is true the function will push the value of the deleted slot.\n    :returns: a SQRESULT\n    :remarks: invoke the _delslot metamethod in the table delegate. it only works on tables.\n\npops a key from the stack and delete the slot indexed by it from the table at position idx in the stack; if the slot does not exist, nothing happens.\n\n\n\n\n\n.. _sq_get:\n\n.. c:function:: SQRESULT sq_get(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: this call will invokes the delegation system like a normal dereference it only works on tables, arrays, classes, instances and userdata; if the function fails, nothing will be pushed in the stack.\n\npops a key from the stack and performs a get operation on the object at the position idx in the stack; and pushes the result in the stack.\n\n\n\n\n\n.. _sq_getbase:\n\n.. c:function:: SQRESULT sq_getbase(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class in the stack\n    :returns: a SQRESULT\n\npushes the base class of the 'class' at stored position idx in the stack.\n\n\n\n\n\n.. _sq_getclass:\n\n.. c:function:: SQRESULT sq_getclass(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target class instance in the stack\n    :returns: a SQRESULT\n\npushes the class of the 'class instance' at stored position idx in the stack.\n\n\n\n\n\n.. _sq_getdelegate:\n\n.. c:function:: SQRESULT sq_getdelegate(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n\npushes the current delegate of the object at the position idx in the stack.\n\n\n\n\n\n.. _sq_getfreevariable:\n\n.. c:function:: const char * sq_getfreevariable(HSQUIRRELVM v, SQInteger idx, SQInteger nval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack(closure)\n    :param SQInteger nval: 0 based index of the free variable(relative to the closure).\n    :returns: the name of the free variable for pure quirrel closures. NULL in case of error or if the index of the variable is out of range. In case the target closure is a native closure, the return name is always \"@NATIVE\".\n    :remarks: The function works for both quirrel closure and native closure.\n\ngets the value of the free variable of the closure at the position idx in the stack.\n\n\n\n\n\n.. _sq_getweakrefval:\n\n.. c:function:: SQRESULT sq_getweakrefval(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target weak reference\n    :returns: a SQRESULT\n    :remarks: if the function fails, nothing is pushed in the stack.\n\npushes the object pointed by the weak reference at position idx in the stack.\n\n\n\n\n\n.. _sq_instanceof:\n\n.. c:function:: SQBool sq_instanceof(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: SQTrue if the instance at position -2 in the stack is an instance of the class object at position -1 in the stack.\n    :remarks: The function doesn't pop any object from the stack.\n\nDetermines if an object is an instance of a certain class. Expects an instance and a class in the stack.\n\n\n\n\n\n.. _sq_newmember:\n\n.. c:function:: SQRESULT sq_newmember(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool bstatic: if SQTrue creates a static member.\n    :returns: a SQRESULT\n\npops a key and a value from the stack and performs a new slot operation on the class that is at position idx in the stack; if the slot does not exist, it will be created.\n\n\n\n\n\n.. _sq_newslot:\n\n.. c:function:: SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool bstatic: if SQTrue creates a static member. This parameter is only used if the target object is a class.\n    :returns: a SQRESULT\n    :remarks: Invokes the _newslot metamethod in the table delegate. it only works on tables and classes.\n\npops a key and a value from the stack and performs a set operation on the table or class that is at position idx in the stack, if the slot does not exist it will be created.\n\n\n\n\n\n.. _sq_next:\n\n.. c:function:: SQRESULT sq_next(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n\nPushes in the stack the next key and value of an array, table, or class slot. To start the iteration this function expects a null value on top of the stack; at every call the function will substitute the null value with an iterator and push key and value of the container slot. Every iteration the application has to pop the previous key and value but leave the iterator(that is used as reference point for the next iteration). The function will fail when all slots have been iterated(see Tables and arrays manipulation).\n\n\n\n\n\n.. _sq_rawdeleteslot:\n\n.. c:function:: SQRESULT sq_rawdeleteslot(HSQUIRRELVM v, SQInteger idx, SQBool pushval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target table in the stack\n    :param SQBool pushval: if this param is true the function will push the value of the deleted slot.\n    :returns: a SQRESULT\n\nDeletes a slot from a table without employing the _delslot metamethod. Pops a key from the stack and delete the slot indexed by it from the table at position idx in the stack; if the slot does not exist nothing happens.\n\n\n\n\n\n.. _sq_rawget:\n\n.. c:function:: SQRESULT sq_rawget(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: Only works on tables and arrays.\n\npops a key from the stack and performs a get operation on the object at position idx in the stack, without employing delegation or metamethods.\n\n\n\n\n\n.. _sq_rawset:\n\n.. c:function:: SQRESULT sq_rawset(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: it only works on tables and arrays. if the function fails nothing will be pushed in the stack.\n\npops a key and a value from the stack and performs a set operation on the object at position idx in the stack, without employing delegation or metamethods.\n\n\n\n\n\n.. _sq_set:\n\n.. c:function:: SQRESULT sq_set(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: this call will invoke the delegation system like a normal assignment, it only works on tables, arrays and userdata.\n\npops a key and a value from the stack and performs a set operation on the object at position idx in the stack.\n\n\n\n\n\n.. _sq_setdelegate:\n\n.. c:function:: SQRESULT sq_setdelegate(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :returns: a SQRESULT\n    :remarks: to remove the delegate from an object, set a null value.\n\npops a table from the stack and sets it as the delegate of the object at the position idx in the stack.\n\n\n\n\n\n.. _sq_setfreevariable:\n\n.. c:function:: SQRESULT sq_setfreevariable(HSQUIRRELVM v, SQInteger idx, SQInteger nval)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :param SQInteger nval: 0 based index of the free variable(relative to the closure).\n    :returns: a SQRESULT\n\npops a value from the stack and sets it as a free variable of the closure at the position idx in the stack.\n\n\n\n\n\n.. _sq_weakref:\n\n.. c:function:: void sq_weakref(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index to the target object in the stack\n    :returns: a SQRESULT\n    :remarks: if the object at idx position is one of (integer, float, bool, null), the object itself is pushed instead of a weak ref.\n\npushes a weak reference to the object at position idx in the stack.\n"
  },
  {
    "path": "doc/source/reference/api/raw_object_handling.rst",
    "content": ".. _api_ref_raw_object_handling:\n\n===================\nRaw object handling\n===================\n\n.. _sq_addref:\n\n.. c:function:: void sq_addref(HSQUIRRELVM v, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT* po: pointer to an object handler\n\nadds a reference to an object handler.\n\n\n\n\n\n.. _sq_getobjtypetag:\n\n.. c:function:: SQRESULT sq_getobjtypetag(HSQOBJECT* o, SQUserPointer* typetag)\n\n    :param HSQOBJECT* o: pointer to an object handler\n    :param SQUserPointer* typetag: a pointer to the variable that will store the tag\n    :returns: a SQRESULT\n    :remarks: the function works also with instances. if the target object is an instance, the typetag of its base class is fetched.\n\ngets the typetag of a raw object reference(userdata or class).\n\n\n\n\n\n.. _sq_getrefcount:\n\n.. c:function:: SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT* po: object handler\n\nreturns the number of references of a given object.\n\n\n\n\n\n.. _sq_getstackobj:\n\n.. c:function:: SQRESULT sq_getstackobj(HSQUIRRELVM v, SQInteger idx, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the target object in the stack\n    :param HSQOBJECT* po: pointer to an object handler\n    :returns: a SQRESULT\n\ngets an object from the stack and stores it in a object handler.\n\n\n\n\n\n.. _sq_objtobool:\n\n.. c:function:: SQBool sq_objtobool(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object is not a bool will always return false.\n\nreturn the bool value of a raw object reference.\n\n\n\n\n\n.. _sq_objtofloat:\n\n.. c:function:: SQFloat sq_objtofloat(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object is an integer will convert it to float. If the object is not a number will always return 0.\n\nreturn the float value of a raw object reference.\n\n\n\n\n\n.. _sq_objtointeger:\n\n.. c:function:: SQInteger sq_objtointeger(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object is a float will convert it to integer. If the object is not a number will always return 0.\n\nreturn the integer value of a raw object reference.\n\n\n\n\n\n.. _sq_objtostring:\n\n.. c:function:: const char* sq_objtostring(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object doesn't reference a string it returns NULL.\n\nreturn the string value of a raw object reference.\n\n\n\n\n\n.. _sq_objtouserpointer:\n\n.. c:function:: SQUserPointer sq_objtouserpointer(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: If the object doesn't reference a userpointer it returns NULL.\n\nreturn the userpointer value of a raw object reference.\n\n\n\n\n\n.. _sq_pushobject:\n\n.. c:function:: void sq_pushobject(HSQUIRRELVM v, HSQOBJECT obj)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT obj: object handler\n\npush an object referenced by an object handler into the stack.\n\n\n\n\n\n.. _sq_release:\n\n.. c:function:: SQBool sq_release(HSQUIRRELVM v, HSQOBJECT* po)\n\n    :param HSQUIRRELVM v: the target VM\n    :param HSQOBJECT* po: pointer to an object handler\n    :returns: SQTrue if the object handler released has lost all is references(the ones added with sq_addref). SQFalse otherwise.\n    :remarks: the function will reset the object handler to null when it loses all references.\n\nremove a reference from an object handler.\n\n\n\n\n\n.. _sq_resetobject:\n\n.. c:function:: void sq_resetobject(HSQOBJECT* po)\n\n    :param HSQOBJECT* po: pointer to an object handler\n    :remarks: Every object handler has to be initialized with this function.\n\nresets(initialize) an object handler.\n"
  },
  {
    "path": "doc/source/reference/api/stack_operations.rst",
    "content": ".. _api_ref_stack_operations:\n\n================\nStack Operations\n================\n\n.. _sq_cmp:\n\n.. c:function:: SQInteger sq_cmp(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: > 0 if obj1>obj2\n    :returns: == 0 if obj1==obj2\n    :returns: < 0 if obj1<obj2\n\ncompares 2 object from the top of the stack. obj2 should be pushed before obj1.\n\n\n\n\n\n.. _sq_gettop:\n\n.. c:function:: SQInteger sq_gettop(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an integer representing the index of the top of the stack\n\nreturns the index of the top of the stack\n\n\n\n\n\n.. _sq_pop:\n\n.. c:function:: void sq_pop(HSQUIRRELVM v, SQInteger nelementstopop)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nelementstopop: the number of elements to pop\n\npops n elements from the stack\n\n\n\n\n\n.. _sq_poptop:\n\n.. c:function:: void sq_poptop(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npops 1 object from the stack\n\n\n\n\n\n.. _sq_push:\n\n.. c:function:: void sq_push(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: the index in the stack of the value that has to be pushed\n\npushes in the stack the value at the index idx\n\n\n\n\n\n.. _sq_remove:\n\n.. c:function:: void sq_remove(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: index of the element that has to be removed\n\nremoves an element from an arbitrary position in the stack\n\n\n\n\n\n.. _sq_reservestack:\n\n.. c:function:: SQRESULT sq_reservestack(HSQUIRRELVM v, SQInteger nsize)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nsize: required stack size\n    :returns: a SQRESULT\n\nensure that the stack space left is at least of a specified size.If the stack is smaller it will automatically grow. If there's a metamethod currently running the function will fail and the stack will not be resized, this situation has to be considered a \"stack overflow\".\n\n\n\n\n\n.. _sq_settop:\n\n.. c:function:: void sq_settop(HSQUIRRELVM v, SQInteger newtop)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger newtop: the new top index\n\nresize the stack. If new top is bigger then the current top the function will push nulls.\n"
  },
  {
    "path": "doc/source/reference/api/virtual_machine.rst",
    "content": ".. _api_ref_virtual_machine:\n\n===============\nVirtual Machine\n===============\n\n\n.. _sq_close:\n\n.. c:function:: void sq_close(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\nreleases a quirrel VM and all related friend VMs\n\n\n\n\n\n.. _sq_geterrorfunc:\n\n.. c:function:: SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a pointer to a SQPRINTFUNCTION, or NULL if no function has been set.\n\nreturns the current error function of the given Virtual machine. (see sq_setprintfunc())\n\n\n\n\n\n.. _sq_getforeignptr:\n\n.. c:function:: SQUserPointer sq_getforeignptr(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs foreign pointer.\n\nReturns the foreign pointer of a VM instance.\n\n\n\n\n\n.. _sq_getprintfunc:\n\n.. c:function:: SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: a pointer to a SQPRINTFUNCTION, or NULL if no function has been set.\n\nreturns the current print function of the given Virtual machine. (see sq_setprintfunc())\n\n\n\n\n\n.. _sq_getsharedforeignptr:\n\n.. c:function:: SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs shared foreign pointer\n\nReturns the shared foreign pointer of a group of friend VMs\n\n\n\n\n\n.. _sq_getsharedreleasehook:\n\n.. c:function:: SQUserPointer sq_getsharedreleasehook(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs release hook.\n\nReturns the shared release hook of a group of friend VMs\n\n\n\n\n\n.. _sq_getvmreleasehook:\n\n.. c:function:: SQUserPointer sq_getvmreleasehook(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the current VMs release hook.\n\nReturns the release hook of a VM instance\n\n\n\n\n\n.. _sq_getvmstate:\n\n.. c:function:: SQInteger sq_getvmstate(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: the state of the vm encoded as integer value. The following constants are defined: SQ_VMSTATE_IDLE, SQ_VMSTATE_RUNNING, SQ_VMSTATE_SUSPENDED.\n\nreturns the execution state of a virtual machine\n\n\n\n\n\n.. _sq_move:\n\n.. c:function:: void sq_move(HSQUIRRELVM dest, HSQUIRRELVM src, SQInteger idx)\n\n    :param HSQUIRRELVM dest: the destination VM\n    :param HSQUIRRELVM src: the source VM\n    :param SQInteger idx: the index in the source stack of the value that has to be moved\n\npushes the object at the position 'idx' of the source vm stack in the destination vm stack\n\n\n\n\n\n.. _sq_newthread:\n\n.. c:function:: HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)\n\n    :param HSQUIRRELVM friendvm: a friend VM\n    :param SQInteger initialstacksize: the size of the stack in slots(number of objects)\n    :returns: a pointer to the new VM.\n    :remarks: By default the roottable is shared with the VM passed as first parameter. The new VM lifetime is bound to the \"thread\" object pushed in the stack and behave like a normal quirrel object.\n\ncreates a new vm friendvm of the one passed as first parmeter and pushes it in its stack as \"thread\" object.\n\n\n\n\n\n.. _sq_open:\n\n.. c:function:: HSQUIRRELVM sq_open(SQInteger initialstacksize)\n\n    :param SQInteger initialstacksize: the size of the stack in slots(number of objects)\n    :returns: an handle to a quirrel vm\n    :remarks: the returned VM has to be released with sq_releasevm\n\ncreates a new instance of a quirrel VM that consists in a new execution stack.\n\n\n\n\n\n.. _sq_pushconsttable:\n\n.. c:function:: void sq_pushconsttable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes the current const table in the stack\n\n\n\n\n\n.. _sq_pushregistrytable:\n\n.. c:function:: void sq_pushregistrytable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes the registry table in the stack\n\n\n\n\n\n.. _sq_pushroottable:\n\n.. c:function:: void sq_pushroottable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npushes the current root table in the stack\n\n\n\n\n\n.. _sq_setconsttable:\n\n.. c:function:: void sq_setconsttable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npops a table from the stack and set it as const table\n\n\n\n\n\n.. _sq_seterrorhandler:\n\n.. c:function:: void sq_seterrorhandler(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :remarks: the error handler is shared by friend VMs\n\npops from the stack a closure or native closure an sets it as runtime-error handler.\n\n\n\n\n\n.. _sq_setforeignptr:\n\n.. c:function:: void sq_setforeignptr(HSQUIRRELVM v, SQUserPointer p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUserPointer p: The pointer that has to be set\n\nSets the foreign pointer of a certain VM instance. The foreign pointer is an arbitrary user defined pointer associated to a VM (by default is value id 0). This pointer is ignored by the VM.\n\n\n\n\n\n.. _sq_setprintfunc:\n\n.. c:function:: void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc, SQPRINTFUNCTION errorfunc)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQPRINTFUNCTION printfunc: a pointer to the print func or NULL to disable the output.\n    :param SQPRINTFUNCTION errorfunc: a pointer to the error func or NULL to disable the output.\n    :remarks: the print func has the following prototype: void printfunc(HSQUIRRELVM v,const char \\*s,...)\n\nsets the print function of the virtual machine. This function is used by the built-in function 'print()' to output text.\n\n\n\n\n\n.. _sq_setroottable:\n\n.. c:function:: void sq_setroottable(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\npops a table from the stack and set it as root table\n\n\n\n\n\n.. _sq_setsharedforeignptr:\n\n.. c:function:: void sq_setsharedforeignptr(HSQUIRRELVM v, SQUserPointer p)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQUserPointer p: The pointer that has to be set\n\nSets the shared foreign pointer. The foreign pointer is an arbitrary user defined pointer associated to a group of friend VMs (by default is value id 0). After a \"main\" VM is created using sq_open() all friend VMs created with sq_newthread share the same shared pointer.\n\n\n\n\n\n.. _sq_setsharedreleasehook:\n\n.. c:function:: void sq_setsharedreleasehook(HSQUIRRELVM v, SQRELESEHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQRELESEHOOK hook: The hook that has to be set\n\nSets the release hook of a certain VM group. The release hook is invoked when the last vm of the group vm is destroyed (usually when sq_close() is invoked). The userpointer passed to the function is the shared foreignpointer(see sq_getsharedforeignptr()). After a \"main\" VM is created using sq_open() all friend VMs created with sq_newthread() share the same shared release hook.\n\n\n\n\n\n.. _sq_setvmreleasehook:\n\n.. c:function:: void sq_setvmreleasehook(HSQUIRRELVM v, SQRELESEHOOK hook)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQRELESEHOOK hook: The hook that has to be set\n\nSets the release hook of a certain VM instance. The release hook is invoked when the vm is destroyed. The userpointer passed to the function is the vm foreignpointer (see sq_setforeignpointer())\n\n\n\n\n\n.. _sq_suspendvm:\n\n.. c:function:: HRESULT sq_suspendvm(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT(that has to be returned by a C function)\n    :remarks: sq_result can only be called as return expression of a C function. The function will fail is the suspension is done through more C calls or in a metamethod.\n\nSuspends the execution of the specified vm.\n\n*.eg*\n\n::\n\n    SQInteger suspend_vm_example(HSQUIRRELVM v)\n    {\n        return sq_suspendvm(v);\n    }\n\n\n\n\n\n\n.. _sq_wakeupvm:\n\n.. c:function:: HRESULT sq_wakeupvm(HSQUIRRELVM v, SQBool resumedret, SQBool retval, SQBool invoke_err_handler, SQBool throwerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQBool resumedret: if true the function will pop a value from the stack and use it as return value for the function that has previously suspended the virtual machine.\n    :param SQBool retval: if true the function will push the return value of the function that suspend the excution or the main function one.\n    :param SQBool invoke_err_handler: if true, if a runtime error occurs during the execution of the call, the vm will invoke the error handler.\n    :param SQBool throwerror: if true, the vm will thow an exception as soon as is resumed. the exception payload must be set beforehand invoking sq_thowerror().\n    :returns: an HRESULT.\n\nwake up the execution a previously suspended virtual machine\n"
  },
  {
    "path": "doc/source/reference/api_reference.rst",
    "content": ".. _api_reference:\n\n\n*************\nAPI Reference\n*************\n\n.. toctree::\n   api/virtual_machine.rst\n   api/compiler.rst\n   api/stack_operations.rst\n   api/object_creation_and_handling.rst\n   api/calls.rst\n   api/object_manipulation.rst\n   api/bytecode_serialization.rst\n   api/raw_object_handling.rst\n   api/garbage_collector.rst\n   api/debug_interface.rst\n"
  },
  {
    "path": "doc/source/reference/embedding/build_configuration.rst",
    "content": ".. _embedding_build_configuration:\n\n========================\nBuild Configuration\n========================\n\n.. _squirrel_64bits:\n\n--------------------------------\nQuirrel on 64-bit architectures\n--------------------------------\n\n.. index::\n    single: Quirrel on 64-bit architectures\n    single: 64 bits\n\nQuirrel can be compiled on 64-bit architectures by defining '_SQ64' in the C++\npreprocessor. This flag should be defined in any project that includes 'squirrel.h'.\n\n.. _userdata_alignment:\n\n------------------\nUserdata Alignment\n------------------\n\n.. index:: single: Userdata Alignment\n\nBoth class instances and userdatas can have a buffer associated to them.\nQuirrel specifies the alignment(in bytes) through the preprocessor defining 'SQ_ALIGNMENT'.\nBy default SQ_ALIGNMENT is defined as 4 for 32-bit builds and 8 for 64-bit builds and builds that use 64-bit floats.\nIt is possible to override the value of SQ_ALIGNMENT respecting the following rules.\nSQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and it shall be power of 2.\n\n.. note:: This only applies for userdata allocated by the VM, specified via sq_setclassudsize() or belonging to a userdata object.\n        userpointers specified by the user are not affected by alignment rules.\n\n.. _standalone_vm:\n\n------------------------------------\nStand-alone VM without compiler\n------------------------------------\n\n.. index:: single: Stand-alone VM without compiler\n\nQuirrel's VM can be compiled without its compiler by defining 'NO_COMPILER' in the C++ preprocessor.\nWhen 'NO_COMPILER' is defined all function related to the compiler (eg. sq_compile) will fail. Other functions\nthat conditionally load precompiled bytecode or compile a file (eg. sqstd_dofile) will only work with\nprecompiled bytecode.\n"
  },
  {
    "path": "doc/source/reference/embedding/calling_a_function.rst",
    "content": ".. _embedding_calling_a_function:\n\n==================\nCalling a function\n==================\n\nTo call a quirrel function it is necessary to push the function in the stack followed by the\nparameters and then call the function sq_call.\nThe function will pop the parameters and push the return value if the last sq_call\nparameter is > 0. ::\n\n    sq_pushroottable(v);\n    sq_pushstring(v,\"foo\",-1);\n    sq_get(v,-2); //get the function from the root table\n    sq_pushroottable(v); //'this' (function environment object)\n    sq_pushinteger(v,1);\n    sq_pushfloat(v,2.0);\n    sq_pushstring(v,\"three\",-1);\n    sq_call(v,4,SQFalse,SQFalse);\n    sq_pop(v,2); //pops the roottable and the function\n\nthis is equivalent to the following Quirrel code::\n\n    foo(1,2.0,\"three\");\n\nIf a runtime error occurs (or a exception is thrown) during the quirrel code execution\nthe sq_call will fail.\n"
  },
  {
    "path": "doc/source/reference/embedding/compiling_a_script.rst",
    "content": ".. embedding_compiling_a_script:\n\n==================\nCompiling a script\n==================\n\nYou can compile a Quirrel script with the function *sq_compile*.::\n\n    SQRESULT sq_compile(HSQUIRRELVM v, const char* s, SQInteger size,\n                const char *sourcename, SQBool raiseerror,\n                const HSQOBJECT *bindings = nullptr);\n\nThe function compiles a script from a memory buffer. The parameters are:\n\n* ``v``: the target VM\n* ``s``: pointer to the buffer containing the script source code\n* ``size``: size in characters of the buffer\n* ``sourcename``: symbolic name of the program (used for runtime errors)\n* ``raiseerror``: if true, the compiler error handler will be called on errors\n* ``bindings``: optional compile-time bindings object (can be nullptr)\n\nIf sq_compile succeeds, the compiled script will be pushed as Quirrel function in the\nstack.\n\n.. :note::\n    In order to execute the script, the function generated by *sq_compile()* has\n    to be called through *sq_call()*\n\nWhen the compiler fails for a syntax error it will try to call the 'compiler error handler';\nthis function must be declared as follow: ::\n\n    typedef void (*SQCOMPILERERROR)(HSQUIRRELVM v, SQMessageSeverity severity,\n                            const char *desc, const char *source,\n                            SQInteger line, SQInteger column, const char *extra_info);\n\nwhere ``severity`` indicates the message severity (error, warning, etc.), ``desc`` is the error description,\n``source`` is the source filename, ``line`` and ``column`` are the location, and ``extra_info`` provides\nadditional context.\n\nThe handler can be set with the following API call::\n\n    void sq_setcompilererrorhandler(HSQUIRRELVM v, SQCOMPILERERROR f);\n"
  },
  {
    "path": "doc/source/reference/embedding/creating_a_c_function.rst",
    "content": ".. _embedding_creating_a_c_function:\n\n===================\nCreate a C function\n===================\n\nA native C function must have the following prototype: ::\n\n    typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);\n\nThe parameters is an handle to the calling VM and the return value is an integer\nrespecting the following rules:\n\n* 1 if the function returns a value\n* 0 if the function does not return a value\n* SQ_ERROR runtime error is thrown\n\nIn order to obtain a new callable quirrel function from a C function pointer, is necessary\nto call sq_newclosure() passing the C function to it; the new Quirrel function will be\npushed in the stack.\n\nWhen the function is called, the stackbase is the first parameter of the function and the\ntop is the last. In order to return a value the function has to push it in the stack and\nreturn 1.\n\nFunction parameters are in the stack from position 1 ('this') to *n*.\n*sq_gettop()* can be used to determinate the number of parameters.\n\nIf the function has free variables, those will be in the stack after the explicit parameters\nan can be handled as normal parameters. Note also that the value returned by *sq_gettop()* will be\naffected by free variables. *sq_gettop()* will return the number of parameters plus\nnumber of free variables.\n\nHere an example, the following function print the value of each argument and return the\nnumber of arguments. ::\n\n    SQInteger print_args(HSQUIRRELVM v)\n    {\n        SQInteger nargs = sq_gettop(v); //number of arguments\n        for(SQInteger n=1;n<=nargs;n++)\n        {\n            printf(\"arg %d is \",n);\n            switch(sq_gettype(v,n))\n            {\n                case OT_NULL:\n                    printf(\"null\");\n                    break;\n                case OT_INTEGER:\n                    printf(\"integer\");\n                    break;\n                case OT_FLOAT:\n                    printf(\"float\");\n                    break;\n                case OT_STRING:\n                    printf(\"string\");\n                    break;\n                case OT_TABLE:\n                    printf(\"table\");\n                    break;\n                case OT_ARRAY:\n                    printf(\"array\");\n                    break;\n                case OT_USERDATA:\n                    printf(\"userdata\");\n                    break;\n                case OT_CLOSURE:\n                    printf(\"closure(function)\");\n                    break;\n                case OT_NATIVECLOSURE:\n                    printf(\"native closure(C function)\");\n                    break;\n                case OT_GENERATOR:\n                    printf(\"generator\");\n                    break;\n                case OT_USERPOINTER:\n                    printf(\"userpointer\");\n                    break;\n                case OT_CLASS:\n                    printf(\"class\");\n                    break;\n                case OT_INSTANCE:\n                    printf(\"instance\");\n                    break;\n                case OT_WEAKREF:\n                    printf(\"weak reference\");\n                    break;\n                default:\n                    return sq_throwerror(v,\"invalid param\"); //throws an exception\n            }\n        }\n        printf(\"\\n\");\n        sq_pushinteger(v,nargs); //push the number of arguments as return value\n        return 1; //1 because 1 value is returned\n    }\n\nHere an example of how to register a function::\n\n    SQInteger register_global_func(HSQUIRRELVM v,SQFUNCTION f,const char *fname)\n    {\n        sq_pushroottable(v);\n        sq_pushstring(v,fname,-1);\n        sq_newclosure(v,f,0); //create a new function\n        sq_newslot(v,-3,SQFalse);\n        sq_pop(v,1); //pops the root table\n        return 0;\n    }\n"
  },
  {
    "path": "doc/source/reference/embedding/debug_interface.rst",
    "content": ".. _embedding_debug_interface:\n\n===============\nDebug Interface\n===============\n\nThe quirrel VM exposes a very simple debug interface that allows to easily built a full\nfeatured debugger.\nThrough the functions sq_setdebughook and sq_setnativedebughook is possible in fact to set a callback function that\nwill be called every time the VM executes an new line of a script or if a function get\ncalled/returns. The callback will pass as argument the current line the current source and the\ncurrent function name (if any).::\n\n    SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v);\n\nor ::\n\n    SQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook);\n\nThe following code shows how a debug hook could look like(obviously is possible to\nimplement this function in C as well). ::\n\n    function debughook(event_type, sourcefile, line, funcname) {\n\n        local fname=funcname?funcname:\"unknown\"\n        local srcfile=sourcefile?sourcefile:\"unknown\"\n        switch (event_type) {\n        case 'l': //called every line(that contains some code)\n            println($\"LINE line [{line}] func [{fname}] file [{srcfile}]\")\n            break\n        case 'c': //called when a function has been called\n            println($\"LINE line [{line}] func [{fname}] file [{srcfile}]\")\n            break\n        case 'r': //called when a function returns\n            println($\"LINE line [{line}] func [{fname}] file [{srcfile}]\")\n            break\n        }\n    }\n\nThe parameter *event_type* can be 'l' ,'c' or 'r' ; a hook with a 'l' event is called for each line that\ngets executed, 'c' every time a function gets called and 'r' every time a function returns.\n\nA full-featured debugger always allows displaying local variables and calls stack.\nThe call stack information are retrieved through sq_getstackinfos()::\n\n    SQInteger sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si);\n\nWhile the local variables info through sq_getlocal()::\n\n    SQInteger sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger nseq);\n"
  },
  {
    "path": "doc/source/reference/embedding/error_conventions.rst",
    "content": ".. _embedding_error_convetions:\n\n\n========================\nError Conventions\n========================\n\n.. index::\n    single: Error Conventions\n\nMost of the functions in the API return a SQRESULT value; SQRESULT indicates if a\nfunction completed successfully or not.\nThe macros SQ_SUCCEEDED() and SQ_FAILED() are used to test the result of a function.::\n\n    if(SQ_FAILED(sq_getstring(v,-1,&s)))\n        printf(\"getstring failed\");\n"
  },
  {
    "path": "doc/source/reference/embedding/memory_management.rst",
    "content": ".. _embedding_memory_management:\n\n========================\nMemory Management\n========================\n\n.. index:: single: Memory Management\n\nQuirrel uses reference counting (RC) as primary system for memory management;\nhowever, the virtual machine (VM) has an auxiliary\nmark and sweep garbage collector that can be invoked on demand.\n\nThere are 2 possible compile time options:\n\n    * The default configuration consists in RC plus a mark and sweep garbage collector.\n      The host program can call the function sq_collectgarbage() and perform a garbage collection cycle\n      during the program execution. The garbage collector isn't invoked by the VM and has to\n      be explicitly called by the host program.\n\n    * The second a situation consists in RC only(define NO_GARBAGE_COLLECTOR); in this case is impossible for\n      the VM to detect reference cycles, so is the programmer that has to solve them explicitly in order to\n      avoid memory leaks.\n\nThe only advantage introduced by the second option is that saves 2 additional\npointers that have to be stored for each object in the default configuration with\ngarbage collector(8 bytes for 32 bits systems).\nThe types involved are: tables, arrays, functions, threads, userdata and generators; all other\ntypes are untouched. These options do not affect execution speed.\n"
  },
  {
    "path": "doc/source/reference/embedding/references_from_c.rst",
    "content": ".. embedding_references_from_c:\n\n========================================================\nMantaining references to Quirrel values from the C API\n========================================================\n\nQuirrel allows to reference values through the C API; the function sq_getstackobj() gets\na handle to a quirrel object(any type). The object handle can be used to control the lifetime\nof an object by adding or removing references to it( see sq_addref() and sq_release()).\nThe object can be also re-pushed in the VM stack using sq_pushobject().::\n\n    HSQOBJECT obj;\n\n    sq_resetobject(&obj); //initialize the handle\n    sq_getstackobj(v,-2,&obj); //retrieve an object handle from the pos -2\n    sq_addref(v,&obj); //adds a reference to the object\n\n    ... //do stuff\n\n    sq_pushobject(v,obj); //push the object in the stack\n    sq_release(v,&obj); //relese the object\n"
  },
  {
    "path": "doc/source/reference/embedding/runtime_error_handling.rst",
    "content": ".. _embedding_runtime_error_handling:\n\n======================\nRuntime error handling\n======================\n\nWhen an exception is not handled by Quirrel code with a try/catch statement, a runtime\nerror is raised and the execution of the current program is interrupted. It is possible to\nset a call back function to intercept the runtime error from the host program; this is\nuseful to show meaningful errors to the script writer and for implementing visual\ndebuggers.\nThe following API call pops a Quirrel function from the stack and sets it as error handler.::\n\n    SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v);\n\nThe error handler is called with 2 parameters, an environment object (this) and a object.\nThe object can be any quirrel type.\n"
  },
  {
    "path": "doc/source/reference/embedding/tables_and_arrays_manipulation.rst",
    "content": ".. _embedding_tables_and_arrays_manipulation:\n\n==============================\nTables and arrays manipulation\n==============================\n\nA new table is created calling sq_newtable, this function pushes a new table in the stack.::\n\n    void sq_newtable(HSQUIRRELVM v);\n\nTo create a new slot::\n\n    SQRESULT sq_newslot(HSQUIRRELVM v,SQInteger idx,SQBool bstatic);\n\nTo set or get the table delegate::\n\n    SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx);\n    SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx);\n\n\nA new array is created calling sq_newarray, the function pushes a new array in the\nstack; if the parameters size is bigger than 0 the elements are initialized to null.::\n\n    void sq_newarray (HSQUIRRELVM v,SQInteger size);\n\nTo append a value to the back of the array::\n\n    SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx);\n\nTo remove a value from the back of the array::\n\n    SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQInteger pushval);\n\nTo resize the array::\n\n    SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize);\n\nTo retrieve the size of a table or an array you must use sq_getsize()::\n\n    SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);\n\nTo set a value in an array or table::\n\n    SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);\n\nTo get a value from an array or table::\n\n    SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);\n\nTo get or set a value from a table without employing delegation::\n\n    SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx);\n    SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx);\n\nTo iterate a table or an array::\n\n    SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx);\n\nHere an example of how to perform an iteration: ::\n\n    //push your table/array here\n    sq_pushnull(v)  //null iterator\n    while(SQ_SUCCEEDED(sq_next(v,-2)))\n    {\n        //here -1 is the value and -2 is the key\n\n        sq_pop(v,2); //pops key and val before the nex iteration\n    }\n\n    sq_pop(v,1); //pops the null iterator\n"
  },
  {
    "path": "doc/source/reference/embedding/the_registry_table.rst",
    "content": ".. _embedding_the_registry_table:\n\n==================\nThe registry table\n==================\n\nThe registry table is an hidden table shared between vm and all his thread(friend vms).\nThis table is accessible only through the C API and is meant to be an utility structure\nfor native C library implementation.\nFor instance the sqstdlib (quirrel standard library) uses it to store configuration and shared objects\ndelegates.\nThe registry is accessible through the API call *sq_pushregistrytable()*.::\n\n    void sq_pushregistrytable(HSQUIRRELVM v);\n"
  },
  {
    "path": "doc/source/reference/embedding/the_stack.rst",
    "content": ".. _embedding_the_stack:\n\n\n==========\nThe Stack\n==========\n\nQuirrel exchanges values with the virtual machine through a stack. This mechanism has\nbeen inherited from the language Lua.\nFor instance to call a Quirrel function from C it is necessary to push the function and the\narguments in the stack and then invoke the function; also when Quirrel calls a C\nfunction the parameters will be in the stack as well.\n\n-------------\nStack indexes\n-------------\n\nMany API functions can arbitrarily refer to any element in the stack through an index.\nThe stack indexes follow those conventions:\n\n* 1 is the stack base\n* Negative indexes are considered an offset from top of the stack. For instance -1 isthe top of the stack.\n* 0 is an invalid index\n\nHere an example (let's pretend that this table is the VM stack)\n\n+------------+--------------------+--------------------+\n| **STACK**  | **positive index** | **negative index** |\n+============+====================+====================+\n| \"test\"     | 4                  | -1(top)            |\n+------------+--------------------+--------------------+\n| 1          | 3                  | -2                 |\n+------------+--------------------+--------------------+\n| 0.5        | 2                  | -3                 |\n+------------+--------------------+--------------------+\n| \"foo\"      | 1(base)            | -4                 |\n+------------+--------------------+--------------------+\n\nIn this case, the function *sq_gettop* would return 4;\n\n------------------\nStack manipulation\n------------------\n\nThe API offers several functions to push and retrieve data from the Quirrel stack.\n\nTo push a value that is already present in the stack in the top position::\n\n    void sq_push(HSQUIRRELVM v,SQInteger idx);\n\nTo pop an arbitrary number of elements::\n\n    void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop);\n\nTo remove an element from the stack::\n\n    void sq_remove(HSQUIRRELVM v,SQInteger idx);\n\nTo retrieve the top index (and size) of the current\nvirtual stack you must call *sq_gettop* ::\n\n    SQInteger sq_gettop(HSQUIRRELVM v);\n\nTo force the stack to a certain size you can call *sq_settop* ::\n\n    void sq_settop(HSQUIRRELVM v,SQInteger newtop);\n\nIf the newtop is bigger than the previous one, the new positions in the stack will be\nfilled with null values.\n\nThe following function pushes a C value into the stack::\n\n    void sq_pushstring(HSQUIRRELVM v,const char *s,SQInteger len);\n    void sq_pushfloat(HSQUIRRELVM v,SQFloat f);\n    void sq_pushinteger(HSQUIRRELVM v,SQInteger n);\n    void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);\n    void sq_pushbool(HSQUIRRELVM v,SQBool b);\n\nthis function pushes a null into the stack::\n\n    void sq_pushnull(HSQUIRRELVM v);\n\nreturns the type of the value in a arbitrary position in the stack::\n\n    SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);\n\nthe result can be one of the following values: ::\n\n    OT_NULL,OT_INTEGER,OT_FLOAT,OT_STRING,OT_TABLE,OT_ARRAY,OT_USERDATA,\n    OT_CLOSURE,OT_NATIVECLOSURE,OT_GENERATOR,OT_USERPOINTER,OT_BOOL,OT_INSTANCE,OT_CLASS,OT_WEAKREF\n\nThe following functions convert a quirrel value in the stack to a C value::\n\n    SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const char **c);\n    SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const char **c,SQInteger size);\n    SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);\n    SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);\n    SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p);\n    SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag);\n    SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *p);\n\nThe function sq_cmp compares 2 values from the stack and returns their relation (like strcmp() in ANSI C).::\n\n    SQInteger sq_cmp(HSQUIRRELVM v);\n"
  },
  {
    "path": "doc/source/reference/embedding/userdata_and_userpointers.rst",
    "content": ".. _embedding_userdata_and_userpointers:\n\n=========================\nUserdata and UserPointers\n=========================\n\nQuirrel allows the host application put arbitrary data chunks into a Quirrel value, this is\npossible through the data type userdata.::\n\n    SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size);\n\nWhen the function *sq_newuserdata* is called, Quirrel allocates a new userdata with the\nspecified size, returns a pointer to his payload buffer and push the object in the stack; at\nthis point the application can do whatever it want with this memory chunk, the VM will\nautomatically take cake of the memory deallocation like for every other built-in type.\nA userdata can be passed to a function or stored in a table slot. By default Quirrel\ncannot manipulate directly userdata; however is possible to assign a delegate to it and\ndefine a behavior like it would be a table.\nBecause the application would want to do something with the data stored in a userdata\nobject when it get deleted, is possible to assign a callback that will be called by the VM\njust before deleting a certain userdata.\nThis is done through the API call *sq_setreleasehook*.::\n\n    typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size);\n\n    void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);\n\nAnother kind of userdata is the userpointer; this type is not a memory chunk like the\nnormal userdata, but just a 'void*' pointer. It cannot have a delegate and is passed by\nvalue, so pushing a userpointer doesn't cause any memory allocation.::\n\n    void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);\n\n"
  },
  {
    "path": "doc/source/reference/embedding/vm_initialization.rst",
    "content": ".. _embedding_vm_initialization:\n\n==============================\nVirtual Machine Initialization\n==============================\n\nThe first thing that a host application has to do, is create a virtual machine.\nThe host application can create any number of virtual machines through the function\n*sq_open()*.\nEvery single VM that was created using *sq_open()* has to be released with the function *sq_close()* when it is no\nlonger needed.::\n\n    int main(int argc, char* argv[])\n    {\n        HSQUIRRELVM v;\n        v = sq_open(1024); //creates a VM with initial stack size 1024\n\n        //do some stuff with quirrel here\n\n        sq_close(v);\n    }\n"
  },
  {
    "path": "doc/source/reference/embedding_squirrel.rst",
    "content": ".. _embedding_squirrel:\n\n***************************\n  Embedding Quirrel\n***************************\n\n*This section describes how to embed Quirrel in a host application,\nC language knowledge is required to understand this part of the manual.*\n\nBecause of his nature of extension language, Quirrel's compiler and virtual machine\nare implemented as C library. The library exposes a set of functions to compile scripts,\ncall functions, manipulate data and extend the virtual machine.\nAll declarations needed for embedding the language in an application are in the header file 'squirrel.h'.\n\n.. toctree::\n    embedding/memory_management.rst\n    embedding/build_configuration.rst\n    embedding/error_conventions.rst\n    embedding/vm_initialization.rst\n    embedding/the_stack.rst\n    embedding/runtime_error_handling.rst\n    embedding/compiling_a_script.rst\n    embedding/calling_a_function.rst\n    embedding/creating_a_c_function.rst\n    embedding/tables_and_arrays_manipulation.rst\n    embedding/userdata_and_userpointers.rst\n    embedding/the_registry_table.rst\n    embedding/references_from_c.rst\n    embedding/debug_interface.rst\n"
  },
  {
    "path": "doc/source/reference/index.rst",
    "content": ".. _reference:\n\n#####################################\n  Quirrel |version| Reference Manual\n#####################################\n\nProject source code is available at https://github.com/GaijinEntertainment/quirrel\n\nCopyright (c) 2003-2016 Alberto Demichelis\nCopyright (c) 2016-2024 Gaijin Games KFT\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n.. toctree::\n   :maxdepth: 3\n   :numbered:\n\n   language.rst\n   embedding_squirrel.rst\n   api_reference.rst\n"
  },
  {
    "path": "doc/source/reference/language/arrays.rst",
    "content": ".. _arrays:\n\n\n=================\nArrays\n=================\n\n.. index::\n    single: Arrays\n\nAn array is a sequence of values indexed by a integer number from 0 to the size of the\narray minus 1. Arrays elements can be obtained through their index.::\n\n    let a=[\"I'm a string\", 123]\n    print(typeof a[0]) //prints \"string\"\n    print(typeof a[1]) //prints \"integer\"\n\nResizing, insertion, deletion of arrays and arrays elements is done through a set of\nstandard functions (see :ref:`built-in functions <builtin_functions>`).\n"
  },
  {
    "path": "doc/source/reference/language/builtin_functions.rst",
    "content": ".. _builtin_functions:\n\n\n==================\nBuilt-in Functions\n==================\n\n.. index::\n    single: Built-in Functions\n    pair: Global Symbols; Built-in Functions\n\n\n^^^^^^^^^^^^^^\nGlobal Symbols\n^^^^^^^^^^^^^^\n\n.. sq:function:: array(size,[fill])\n\ncreates and returns an array of a specified size. If the optional parameter fill is specified, its value will be used to fill the new array's slots. If the fill parameter is omitted, null is used instead.\n\n.. sq:function:: callee()\n\nreturns the currently running closure\n\n.. sq:function:: getroottable()\n\nreturns the root table of the VM.\n\n.. sq:function:: getconsttable()\n\nreturns the const table of the VM.\n\n.. sq:function:: assert(exp, [message])\n\nthrows an exception if exp is null or false. Throws \"assertion failed\" string by default, or message if specified.\nIf the message argument is a function, it is evaluated and the return value is used as the message text. This is to avoid\nunnecessary string formatting when it is not needed.\n\n.. sq:function:: print(...)\n\nprints all arguments (space-separated if more than one) calling the host app printing function set by (:ref:`sq_setprintfunc <sq_setprintfunc>`) call\n\n.. sq:function:: println(...)\n\nprints space-separated arguments adding a line feed ('\\n') to the resulting string\n\n.. sq:function:: error(...)\n\nsame as print() but using the error printing function set by (:ref:`sq_setprintfunc <sq_setprintfunc>`) call\n\n.. sq:function:: errorln(...)\n\nsame as error() but adds a line feed ('\\n') to the resulting string\n\n.. sq:function:: compilestring(string,[buffername],[bindings])\n\ncompiles a string containing a quirrel script into a function and returns it::\n\n    let compiledscript=compilestring(\"println(\\\"ciao\\\")\")\n    //run the script\n    compiledscript()\n\nor providing compile-time bindings::\n\n    let api = {function foo() {println(\"foo() called\")}}\n    let compiledscript=compilestring(\"foo()\", \"bindings_test\", api)\n    compiledscript()\n\n.. sq:function:: type(obj)\n\nreturns the 'raw' type of an object without invoking the metamethod '_typeof'.\n\n.. sq:function:: newthread(threadfunc)\n\ncreates a new cooperative thread object (coroutine) and returns it\n\n.. sq:function:: freeze(x)\n\nreturns an immutable reference to the given object.\nThrows an error if the argument is of POD type (to help prevent errors).\n\n.. sq:function:: getobjflags(x)\n\nGiven an object handle, returns its flags that may be:\n\n  * 0 - no special flags\n  * SQOBJ_FLAG_IMMUTABLE - bit set if the object handle is immutable\n\n.. _builtin_type_classes:\n\n----------------------\nBuilt-in Type Classes\n----------------------\n\nEvery Quirrel value is an instance of a built-in type class. These classes (``Integer``, ``Float``, ``String``, ``Bool``, ``Array``, ``Table``, ``Null``, etc.) are available through the ``types`` module and contain methods to manipulate and retrieve information from values of that type.\n\nThe built-in type classes can be imported like::\n\n    from \"types\" import Integer, Float, String, Array, Table, Bool, Null\n    // or\n    from \"types\" import *\n    // or\n    import types\n\nType methods can be called directly on values.\nThey can also be called by adding the $ symbol before the method name, like ``table.$tostring()`` or ``table?.$tostring()```.\nWith the '$' symbol, Quirrel will call the built-in type method.\nThis matters in tables and instances (``{len=@() 0}.len() //0`` vs ``{len= @() 0}.$len() //1``).\nWhile having such names in tables is not a good idea, this can happen with data coming from external sources.\n\nValues can be tested against classes using ``instanceof``, just like script class instances::\n\n    let x = 5\n    if (x instanceof Integer) {\n        println(\"x is an integer\")\n    }\n\n^^^^^^^\nInteger\n^^^^^^^\n\n.. sq:function:: integer.tofloat()\n\nconverts the number to float and returns it\n\n\n.. sq:function:: integer.tostring()\n\nconverts the number to string and returns it\n\n\n.. sq:function:: integer.tointeger()\n\ndummy function; returns the value of the integer.\n\n\n.. sq:function:: integer.tochar()\n\nreturns a string containing a single character represented by the integer.\n\n\n.. sq:function:: integer.weakref()\n\ndummy function; returns the integer itself.\n\n^^^^^\nFloat\n^^^^^\n\n.. sq:function:: float.tofloat()\n\nreturns the value of the float (dummy function)\n\n\n.. sq:function:: float.tointeger()\n\nconverts the number to integer and returns it\n\n\n.. sq:function:: float.tostring()\n\nconverts the number to string and returns it\n\n\n.. sq:function:: float.tochar()\n\nreturns a string containing a single character represented by the integer part of the float.\n\n\n.. sq:function:: float.weakref()\n\ndummy function; returns the float itself.\n\n^^^^\nBool\n^^^^\n\n.. sq:function:: bool.tofloat()\n\nreturns 1.0 for true, 0.0 for false\n\n\n.. sq:function:: bool.tointeger()\n\nreturns 1 for true, 0 for false\n\n\n.. sq:function:: bool.tostring()\n\nreturns \"true\" for true and \"false\" for false\n\n\n.. sq:function:: bool.weakref()\n\ndummy function; returns the bool itself.\n\n^^^^^^\nString\n^^^^^^\n\n.. sq:function:: string.len()\n\nreturns the string length\n\n\n.. sq:function:: string.tointeger([base])\n\nConverts the string to integer and returns it. An optional parameter base can be specified--if a base is not specified, it defaults to base 10.\n\n\n.. sq:function:: string.tofloat()\n\nconverts the string to float and returns it\n\n\n.. sq:function:: string.tostring()\n\nreturns the string (really, a dummy function)\n\n\n.. sq:function:: string.slice(start,[end])\n\nreturns a section of the string as a new string. Copies from start to the end (not included). If start is negative, the index is calculated as length + start, if end is negative, the index is calculated as length + end. If end is omitted, end is equal to the string length.\n\n\n.. sq:function:: string.indexof(substr,[startidx])\n\nSearches for a substring (substr) starting from the index startidx and returns the position of its first occurrence. If startidx is omitted, the search operation starts from the beginning of the string. The function returns null if substr is not found.\n\n.. sq:function:: string.contains(substr,[startidx])\n\nChecks if the string contains a substring (substr) anywhere starting from the index startidx. Returns a boolean value.\n\n\n.. sq:function:: string.tolower()\n\nreturns a lowercase copy of the string.\n\n\n.. sq:function:: string.toupper()\n\nreturns an uppercase copy of the string.\n\n\n.. sq:function:: string.weakref()\n\nreturns a weak reference to the object.\n\n.. sq:function:: string.subst(...)\n\nFormats strings. A format string can contain variable positional arguments and table keys.\nAs parameters, you can pass an arbitrary number of tables and an arbitrary number of positional arguments. If the key is found in several tables,\nthen the value from the leftmost table will be used.\n\nExample: ::\n\n\"Score: {0}\".subst(4200) => \"Score: 4200\"\n\"x={0} y={1} z={2}\".subst(42, 45.53, -10.8) => \"x=42 y=45.53 z=-10.8\"\n\"Score: {score}\".subst({score=4200}) => \"Score: 4200\"\n\"x={x} y={y} z={z}\".subst({y=45.53, x=42, z=-10.8}) => \"x=42 y=45.53 z=-10.8\"\n\"Type: {type}, Health: {hp}\".subst({hp=100, damage=5}, {isAir=true, type=\"helicopter\"}) => \"Type: helicopter, Health: 100\"\n\"Type: {type}, Pos: x={0} y={1} z={2}\".subst({isAir=true, type=\"helicopter\"}, 42, 45.53, -10.8) => \"Type: helicopter, Pos: x=42 y=45.53 z=-10.8\"\n\"Score: {0}\".subst() => \"Score: {0}\"\n\"Score: {score}\".subst({}) => \"Score: {score}\"\n\n.. sq:function:: string.replace(from, to)\n\nReplaces all occurrences of the 'from' substring with 'to'\n\n.. sq:function:: string.join(arr, [filter])\n\nConcatenates all items in the provided array using the string itself as a separator.\nExample: ::\n\", \".join([\"a\", \"b\", \"c\"]) // => \"a, b, c\"\n\nAn optional filter parameter can be specified.\nWhen it is set to true (boolean), the default filter is used which keeps items that are non-null and not \"\" (empty string).\nWhen filter is a function, it is called for every item and must return true for elements that should be included in the resulting string.\nExample: ::\n\", \".join([\"a\", null, \"b\", \"\", \"\", \"c\"], true) // => \"a, b, c\"\n\", \".join([\"a\", null, \"b\", \"\", \"\", \"c\"], @(v) v!=null)) // => \"a, b, , , c\"\n\n.. sq:function:: string.concat(...)\n\nConcatenates all arguments using the string itself as a separator.\nExample: ::\n\", \".concat(\"a\", \"b\", \"c\") // => \"a, b, c\"\n\n.. sq:function:: string.split([sep])\n\nReturns a list of the words in the string, using sep as the delimiter string.\nIf sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings\n(for example, '1,,2'.split(',') returns ['1', '', '2']).\nThe sep argument may consist of multiple characters (for example, '1<>2<>3'.split('<>') returns ['1', '2', '3']).\nSplitting an empty string with a specified separator returns [''].\n\nIf sep is not specified or is None, a different splitting algorithm is applied:\nruns of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings\nat the start or end if the string has leading or trailing whitespace.\nConsequently, splitting an empty string or a string consisting of just whitespace without providing a separator returns [].\n\n.. sq:function:: string.split_by_chars(separators [, skipempty])\n\n    returns an array of strings split at each point where a separator character occurs in `str`.\n    The separator is not returned as part of any array element.\n    The parameter `separators` is a string that specifies the characters to be used for the splitting.\n    The parameter `skipempty` is a boolean (default false). If `skipempty` is true, empty strings are not added to the array.\n\n    ::\n\n        e.g.\n        let a = \"1.2-3;;4/5\".split_by_chars(\".-/;\")\n        // the result will be  [1,2,3,,4,5]\n        or\n        let b = \"1.2-3;;4/5\".split_by_chars(\".-/;\",true)\n        // the result will be  [1,2,3,4,5]\n\n.. sq:function:: string.hash()\n\nReturns the integer hash value of a string. It is always non-negative (so it doesn't always match the Quirrel string internal hash value).\n\n.. sq:function:: string.lstrip()\n\n    Strips whitespace-only characters that might appear at the beginning of the given string\n    and returns the new stripped string.\n\n.. sq:function:: string.rstrip()\n\n    Strips whitespace-only characters that might appear at the end of the given string\n    and returns the new stripped string.\n\n.. sq:function:: string.strip()\n\n    Strips whitespace-only characters that might appear at the beginning or end of the given string and returns the new stripped string.\n\n.. sq:function:: string.startswith(cmp)\n\n    Returns `true` if the beginning of the string `str` matches the string `cmp`; otherwise returns `false`\n\n.. sq:function:: string.hasindex(index)\n\n    The same as `index < string.len() && string >= 0`. Returns true if index is within string and false if it is not.\n\n\n^^^^^\nTable\n^^^^^\n\n.. sq:function:: table.len()\n\nReturns the number of slots contained in a table\n\n\n.. sq:function:: table.rawget(key)\n\nTries to get a value from the slot 'key' without employing delegation\n\n\n.. sq:function:: table.rawset(key,val)\n\nSets the slot 'key' with the value 'val' without employing delegation. If the slot does not exist, it will be created. Returns the table itself.\n\n\n.. sq:function:: table.rawdelete(key)\n\nDeletes the slot key without employing delegation and returns its value. If the slot does not exist, returns null.\n\n\n.. sq:function:: table.rawin(key)\n\nReturns true if the slot 'key' exists. The function has the same effect as the operator 'in' but does not employ delegation.\n\n\n.. sq:function:: table.weakref()\n\nReturns a weak reference to the object.\n\n\n.. sq:function:: table.tostring()\n\nTries to invoke the _tostring metamethod. If that fails, it returns \"(table : pointer)\".\n\n\n.. sq:function:: table.clear()\n\nRemoves all the slots from the table. Returns the table itself.\n\n.. sq:function:: table.filter(func(val, [key], [table_ref]))\n\nCreates a new table with all values that pass the test implemented by the provided function. In detail, it creates a new table, invokes the specified function for each key-value pair in the original table; if the function returns 'true', then the value is added to the newly created table at the same key.\n\n.. sq:function:: table.keys()\n\nReturns an array containing all the keys of the table slots.\n\n.. sq:function:: table.values()\n\nReturns an array containing all the values of the table slots.\n\n.. sq:function:: table.topairs()\n\nReturns an array containing arrays of pairs [key, value]. Useful when you need to sort data from a table.\n\n.. sq:function:: table.clone()\n\nReturns a clone of the table.\n\n.. sq:function:: table.map(func(slot_value, [slot_key], [table_ref]))\n\nCreates a new table of the same size. For each element in the original table, invokes the function 'func' and assigns the return value of the function to the corresponding slot of the newly created table.\nThe provided func can accept up to 3 arguments: slot value (required), slot key in table (optional), reference to table itself (optional).\nIf the callback func throws null, the element is skipped and not added to the destination table.\n\n.. sq:function:: table.each(func(slot_value, [slot_key], [table_ref]))\n\nIterates a table and calls the provided function for each element.\n\n.. sq:function:: table.findindex(func(slot_value, [slot_key], [table_ref]))\n\nPerforms a linear search calling the provided function for each value in the table.\nReturns the index of the value if it was found (callback returned a true (non-false) value) or null otherwise.\n\n.. sq:function:: table.findvalue(func(slot_value, [slot_key], [table_ref]), [def=null])\n\nPerforms a linear search calling the provided function for each value in the table.\nReturns the matched value (for which the callback returned a non-false value) or the default value otherwise (null if not provided).\n\n.. sq:function:: table.reduce(func(accumulator, slot_value, [slot_key], [table_ref]), [initializer])\n\nReduces a table to a single value (similar to array.reduce()).\nFor each table slot, invokes the function 'func' passing the initial value\n(or value from the previous callback call) and the value of the current element.\nThe callback function can also take optional parameters: key in table for current value and reference to table itself.\nIteration order is not determined.\n\n.. sq:function:: table.__merge(table_1, [table_2], [table_3], ...)\n\nCreates a new table from the old and given ones.\nArguments to merge fields from can be tables, classes, and instances.\n\n.. sq:function:: table.__update(table_1, [table_2], [table_3], ...)\n\nCopies all key-value pairs from each argument into the target table, **modifying it in-place**.\nIf multiple arguments contain the same key, the value from the last argument wins.\nArguments can be tables, classes, or instances. Returns the target table.\n\nThrows an error if the target table is frozen (immutable).\n\n.. note::\n\n    To create a new table without modifying the original, use :sq:func:`table.__merge` instead.\n\nExample: ::\n\n    let foo = {fizz=1}\n    let bar = foo.__update({buzz=2})\n    => foo == {fizz=1, buzz=2}; bar={fizz=1, buzz=2}\n\n.. sq:function:: table.getfuncinfos()\n\nExample: ::\n\n    let foo = {fizz=1}\n    let bar = foo.__merge({buzz=2})\n    => foo == {fizz=1}; bar={fizz=1, buzz=2}\n\nIf the table has a delegate with the _call() metamethod, gets info about it (see function.getfuncinfos() for details).\n\n\n.. sq:function:: table.swap(index1, index2)\n\nSwaps two values in the table by indices.\nReturns table\n\n\n.. sq:function:: table.replace_with(source_tbl)\n\nCopies the content of the source table into the given table by replacing its contents. Returns the target table itself.\n\n.. sq:function:: table.is_frozen()\n\nReturns true if the reference to the table is frozen with the 'freeze' global function.\n\n.. sq:function:: table.hasindex(index)\n\nThe same as `index in table`. Returns true if index is in table and false if it is not.\n\n.. sq:function:: table.hasvalue(value)\n\nThe same as `table.findvalue(@(v) v==value) != null`. Returns true if value is in table and false if it is not.\n\n^^^^^^\nArray\n^^^^^^\n\n.. sq:function:: array.len()\n\nreturns the length of the array\n\n\n.. sq:function:: array.append(val, [val_2], [val_3], ...)\n\nsequentially appends the values of arguments 'val' to the end of the array. Returns the array itself.\n\n\n.. sq:function:: array.extend(array_1, [array_2], [array_3], ...)\n\nExtends the array by appending all the items in all the arrays passed as arguments. Returns the target array itself.\n\n\n.. sq:function:: array.pop()\n\nremoves a value from the back of the array and returns it.\n\n\n.. sq:function:: array.top()\n\nreturns the value of the array with the highest index\n\n\n.. sq:function:: array.insert(idx,val)\n\ninserts the value 'val' at the position 'idx' in the array. Returns the array itself.\n\n\n.. sq:function:: array.remove(idx)\n\nremoves the value at the position 'idx' in the array and returns its value.\n\n\n.. sq:function:: array.resize(size,[fill])\n\nResizes the array. If the optional parameter 'fill' is specified, its value will be used to fill the new array's slots when the size specified is bigger than the previous size. If the fill parameter is omitted, null is used instead. Returns the array itself.\n\n\n.. sq:function:: array.sort([compare_func])\n\nSorts the array in-place. A custom compare function can be optionally passed. The function prototype has to be the following::\n\n    function custom_compare(a,b) {\n        if (a>b) return 1\n        else if (a<b) return -1\n        return 0;\n    }\n\nA more compact version of a custom compare can be written using a lambda expression and the operator <=> ::\n\n    arr.sort(@(a,b) a <=> b);\n\nReturns the array itself.\n\n.. sq:function:: array.reverse()\n\nreverses the elements of the array in place. Returns the array itself.\n\n\n.. sq:function:: array.slice(start,[end])\n\nReturns a section of the array as a new array. Copies from start to the end (not included). If start is negative, the index is calculated as length + start, if end is negative, the index is calculated as length + end. If end is omitted, end is equal to the array length.\n\n\n.. sq:function:: array.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: array.tostring()\n\nreturns the string \"(array : pointer)\".\n\n\n.. sq:function:: array.totable()\n\nCreates a table from arrays containing arrays of pairs [key,value]. Reverse of table.topairs().\n\n\n.. sq:function:: array.clear()\n\nremoves all the items from the array\n\n\n.. sq:function:: array.map(func(item_value, [item_index], [array_ref]))\n\nCreates a new array of the same size. For each element in the original array, invokes the function 'func' and assigns the return value of the function to the corresponding element of the newly created array.\nThe provided func can accept up to 3 arguments: array item value (required), array item index (optional), reference to array itself (optional).\nIf the callback func throws null, the element is skipped and not added to the destination array.\n\n\n.. sq:function:: array.apply(func([item_value, [item_index], [array_ref]))\n\nfor each element in the array, invokes the function 'func' and replaces the original value of the element with the return value of the function.\n\n.. sq:function:: array.each(func(item_value, [item_index], [array_ref]))\n\nIterates an array and calls the provided function for each element.\n\n.. sq:function:: array.reduce(func(prevval,curval,[index],[array_ref]), [initializer])\n\nReduces an array to a single value. For each element in the array, invokes the function 'func' passing\nthe initial value (or value from the previous callback call) and the value of the current element.\nThe callback can optionally accept the index of the current value and a reference to the array itself.\nThe return value of the function is then used as 'prevval' for the next element.\nIf the optional initializer is present, it is placed before the items of the array in the calculation,\nand serves as a default when the sequence is empty.\nIf initializer is not given, then for a sequence containing only one item, reduce() returns the first item,\nand for an empty sequence returns null.\n\nGiven a sequence with 2 or more elements (including initializer), calls the function with the first two elements as the parameters,\ngets that result, then calls the function with that result and the third element, gets that result,\ncalls the function with that result and the fourth parameter and so on until all elements have been processed.\nFinally, returns the return value of the last invocation of func.\n\n\n.. sq:function:: array.filter(func(val, [index], [array_ref]))\n\nCreates a new array with all elements that pass the test implemented by the provided function. In detail, it creates a new array, for each element in the original array invokes the specified function passing the index of the element and its value; if the function returns 'true', then the value of the corresponding element is added to the newly created array.\n\n.. sq:function:: array.indexof(value)\n\nPerforms a linear search for the value in the array. Returns the index of the value if it was found, null otherwise.\n\n.. sq:function:: array.contains(value)\n\nPerforms a linear search for the value in the array. Returns true if it was found and false otherwise.\n\n.. sq:function:: array.findindex(func(item_value, [item_index], [array_ref]))\n\nPerforms a linear search calling the provided function for each value in the array.\nReturns the index of the value if it was found (callback returned a true (non-false) value) or null otherwise.\n\n.. sq:function:: array.findvalue(func(item_value, [item_index], [array_ref]), [def=null])\n\nPerforms a linear search calling the provided function for each value in the array.\nReturns the matched value (for which the callback returned a non-false value) or the default value otherwise (null if not provided).\n\n.. sq:function:: array.replace_with(source_arr)\n\nCopies the content of the source array into the given array by replacing its contents. Returns the target array itself.\n\n.. sq:function:: array.swap(index1, index2)\n\nSwaps two values in the array by indices. If the index is negative, it is used as an index from the array end.\n\n.. sq:function:: array.is_frozen()\n\nReturns true if the reference to the array is frozen with the 'freeze' global function.\n\n.. sq:function:: array.hasvalue(value)\n\nThe same as `array.contains(v)`. Returns true if value is in array and false if it is not.\n\n.. sq:function:: array.hasindex(index)\n\nThe same as `index < array.len() && index >= 0`. Returns true if index is within array and false if it is not.\n\n.. sq:function:: array.clone()\n\nReturns a clone of the array.\n\n^^^^^^^^\nFunction\n^^^^^^^^\n\n.. sq:function:: function.call(_this,args...)\n\ncalls the function with the specified environment object ('this') and parameters\n\n\n.. sq:function:: function.pcall(_this,args...)\n\ncalls the function with the specified environment object ('this') and parameters. This function will not invoke the error callback in case of failure (pcall stands for 'protected call')\n\n\n.. sq:function:: function.acall(array_args)\n\ncalls the function with the specified environment object ('this') and parameters. The function accepts an array containing the parameters that will be passed to the called function. The array_args has to contain the required 'this' object at the [0] position.\n\n\n.. sq:function:: function.pacall(array_args)\n\ncalls the function with the specified environment object ('this') and parameters. The function accepts an array containing the parameters that will be passed to the called function. The array_args has to contain the required 'this' object at the [0] position. This function will not invoke the error callback in case of failure (pacall stands for 'protected array call')\n\n\n.. sq:function:: function.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: function.tostring()\n\nreturns the string \"(closure : pointer)\".\n\n\n.. sq:function:: function.bindenv(env)\n\nclones the function (aka closure) and binds the environment object to it (table, class, or instance). The this parameter of the newly created function will always be set to env. Note that the created function holds a weak reference to its environment object so it cannot be used to control its lifetime.\n\n\n.. sq:function:: function.getfuncinfos()\n\nreturns a table containing information about the function, like parameters, name, and source name::\n\n    //the data is returned as a table in this form\n    //pure quirrel function\n    {\n      native = false\n      name = \"zefuncname\"\n      src = \"/something/something.nut\"\n      parameters = [\"a\",\"b\",\"c\"]\n      defparams = [1,\"def\"]\n      varargs = 2\n      freevars = 0\n    }\n    //native C function\n    {\n      native = true\n      name = \"zefuncname\"\n      paramscheck = 2\n      typecheck = [83886082,83886384] //this is the typemask (see C defines OT_INTEGER,OT_FLOAT etc...)\n      freevars = 2\n    }\n\n.. sq:function:: function.getfreevar(idx)\n\nreturns a table containing information about the given free variable::\n  { name=\"foo\", value=5 }\n\n\n^^^^^\nClass\n^^^^^\n\n.. sq:function:: class.instance()\n\nreturns a new instance of the class. This function does not invoke the instance constructor. The constructor must be explicitly called (e.g. class_inst.constructor(class_inst) ).\n\n\n.. sq:function:: class.rawin(key)\n\nreturns true if the slot 'key' exists. The function has the same effect as the operator 'in' but does not employ delegation.\n\n\n.. sq:function:: class.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: class.tostring()\n\nreturns the string \"(class : pointer)\".\n\n\n.. sq:function:: class.rawget(key)\n\ntries to get a value from the slot 'key' without employing delegation\n\n\n.. sq:function:: class.rawset(key,val)\n\nsets the slot 'key' with the value 'val' without employing delegation. If the slot does not exist, it will be created.\n\n\n.. sq:function:: class.newmember(key,val,[bstatic])\n\nsets/adds the slot 'key' with the value 'val'. If bstatic is true, the slot will be added as static. If the slot does not exist, it will be created.\n\n\n.. sq:function:: class.getfuncinfos()\n\nIf the class has the _call() metamethod, gets info about it (see function.getfuncinfos() for details).\n\n.. sq:function:: class.getmetamethod(name)\n\nReturns the metamethod closure (e.g. Foo.getmetamethod(\"_add\")) or null if the method is not implemented in the class.\n\n.. sq:function:: class.__merge(table_or_class_1, [table_or_class_2], [table_or_class_3], ...)\n\nThis delegate is used to create a new class from the old and given ones.\nArguments to merge fields from can be tables, classes, and instances.\n\n.. sq:function:: class.__update(table_1, [table_2], [table_3], ...)\n\nCopies all members from each argument into the class, modifying it in-place.\nArguments can be tables, classes, or instances. Returns the class.\n\n.. sq:function:: class.lock()\n\nSeals the class, protecting it from modifying its fields even if it was not instantiated yet.\n\n.. sq:function:: class.swap(key1, key2)\n\nSwaps two values in the class by keys.\n\n.. sq:function:: class.hasindex(index)\n\nThe same as `index in class`. Returns true if index is in class and false if it is not.\n\n\n^^^^^^^^^^^^^^\nClass Instance\n^^^^^^^^^^^^^^\n\n.. sq:function:: instance.getclass()\n\nreturns the class that created the instance.\n\n\n.. sq:function:: instance.rawin(key)\n\n    :param key: the key\n\nreturns true if the slot 'key' exists. The function has the same effect as the operator 'in' but does not employ delegation.\n\n\n.. sq:function:: instance.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: instance.tostring()\n\ntries to invoke the _tostring metamethod. If it fails, returns \"(instance : pointer)\".\n\n\n.. sq:function:: instance.rawget(key)\n\ntries to get a value from the slot 'key' without employing delegation\n\n\n.. sq:function:: instance.rawset(key,val)\n\nsets the slot 'key' with the value 'val' without employing delegation. If the slot does not exist, it will be created.\n\n.. sq:function:: instance.getfuncinfos()\n\nIf the instance has the _call() metamethod, gets info about it (see function.getfuncinfos() for details).\n\n.. sq:function:: instance.getmetamethod(name)\n\nReturns the metamethod closure (e.g. foo.getmetamethod(\"_add\")) or null if the method is not implemented in the class.\n\n.. sq:function:: instance.is_frozen()\n\nReturns true if the reference to the instance is frozen with the 'freeze' global function.\n\n.. sq:function:: instance.swap(key1, key2)\n\nSwaps two values in the instance by keys.\n\n.. sq:function:: instance.hasindex(index)\n\nThe same as `index in instance`. Returns true if index is in class and false if it is not.\n\n\n^^^^^^^^^^^^^^\nGenerator\n^^^^^^^^^^^^^^\n\n\n.. sq:function:: generator.getstatus()\n\nreturns the status of the generator as a string: \"running\", \"dead\", or \"suspended\".\n\n\n.. sq:function:: generator.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: generator.tostring()\n\nreturns the string \"(generator : pointer)\".\n\n^^^^^^^^^^^^^^\nThread\n^^^^^^^^^^^^^^\n\n.. sq:function:: thread.call(...)\n\nstarts the thread with the specified parameters\n\n\n.. sq:function:: thread.wakeup([wakeupval])\n\nwakes up a suspended thread, accepts an optional parameter that will be used as the return value for the function that suspended the thread (usually suspend())\n\n\n.. sq:function:: thread.wakeupthrow(objtothrow,[propagateerror = true])\n\nwakes up a suspended thread, throwing an exception in the awakened thread, throwing the object 'objtothrow'.\n\n\n.. sq:function:: thread.getstatus()\n\nreturns the status of the thread (\"idle\",\"running\",\"suspended\")\n\n\n.. sq:function:: thread.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: thread.tostring()\n\nreturns the string \"(thread : pointer)\".\n\n\n.. sq:function:: thread.getstackinfos(stacklevel)\n\nreturns the stack frame information at the given stack level (0 is the current function, 1 is the caller, and so on).\n\n^^^^^^^^^^^^^^\nWeak Reference\n^^^^^^^^^^^^^^\n\n.. sq:function:: weakreference.ref()\n\nreturns the object that the weak reference is pointing at; null if the object that was pointed at was destroyed.\n\n\n.. sq:function:: weakreference.weakref()\n\nreturns a weak reference to the object.\n\n\n.. sq:function:: weakreference.tostring()\n\nreturns the string \"(weakref : pointer)\".\n\n^^^^^^^^^^^^^^\nUserdata\n^^^^^^^^^^^^^^\n\n.. sq:function:: userdata.getfuncinfos()\n\nIf userdata has the _call() metamethod in its delegate, gets info about it (see function.getfuncinfos() for details).\n"
  },
  {
    "path": "doc/source/reference/language/classes.rst",
    "content": ".. _classes:\n\n\n=================\nClasses\n=================\n\n.. index::\n    single: Classes\n\nQuirrel implements a class mechanism similar to languages like Java/C++/etc...\nhowever because of its dynamic nature it differs in several aspects.\nClasses are first class objects like integer or strings and can be stored in\ntable slots local variables, arrays and passed as function parameters.\n\nAll Quirrel values are instances of classes. Fundamental types (integers, floats, strings, arrays, tables, etc.)\nhave built-in type classes (``Integer``, ``Float``, ``String``, ``Array``, ``Table``, etc.) available through\nthe ``types`` module. These can be used with ``instanceof`` just like user-defined classes.\nSee :ref:`Built-in Type Classes <builtin_type_classes>` for details.\n\n-----------------\nClass Declaration\n-----------------\n\n.. index::\n    pair: declaration; Class\n    single: Class Declaration\n\nA class object is created through the keyword ``class`` . The class object follows\nthe same declaration syntax of a table(see :ref:`Tables <tables>`) with the only difference\nof using ``;`` as optional separator rather than ``,``.\n\nFor instance: ::\n\n    class Foo {\n        //constructor\n        constructor(a) {\n            this.testy = [\"stuff\",1,2,3,a]\n        }\n        //member function\n        function PrintTesty() {\n            foreach(i,val in this.testy) {\n                print(\"idx = \"+i+\" = \"+val)\n            }\n        }\n        //property\n        testy = null\n    }\n\n\nAfter its declaration, methods or properties can be added or modified by following\nthe same rules that apply to a table (operator ``<-``).::\n\n    //adds a new property\n    Foo.stuff <- 10\n\n    //modifies the default value of an existing property\n    Foo.testy <- \"I'm a string\"\n\nAfter a class is instantiated is no longer possible to add new properties however is possible to add or replace methods.\n\n^^^^^^^^^^^^^^^^\nStatic variables\n^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: static variables; Class\n    single: Static variables\n\nQuirrel's classes support static member variables. A static variable shares its value\nbetween all instances of the class. Statics are declared by prefixing the variable declaration\nwith the keyword ``static``; the declaration must be in the class body.\n\n.. note:: Statics are read-only.\n\n::\n\n    class Foo {\n        constructor() {\n            //..stuff\n        }\n        name = \"normal variable\"\n        //static variable\n        static classname = \"The class name is foo\"\n    };\n\n-----------------\nClass Instances\n-----------------\n\n.. index::\n    pair: instances; Class\n    single: Class Instances\n\nThe class objects inherits several of the table's feature with the difference that multiple instances of the\nsame class can be created.\nA class instance is an object that share the same structure of the table that created it but\nholds is own values.\nClass *instantiation* uses function notation.\nA class instance is created by calling a class object. Can be useful to imagine a class like a function\nthat returns a class instance.::\n\n    //creates a new instance of Foo\n    let inst = Foo()\n\nWhen a class instance is created its member are initialized *with the same value* specified in the\nclass declaration. The values are copied verbatim, *no cloning is performed* even if the value is a container or a class instances.\n\n.. note:: FOR C# and Java programmers:\n\n    Quirrel doesn't clone member's default values nor executes the member declaration for each instance (as C# or java do), just like in Python.\n\n    So consider this example: ::\n\n        class Foo {\n            myarray = [1,2,3]\n            mytable = {}\n        }\n\n        let a = Foo()\n        let b = Foo()\n\n    In the snippet above both instances will refer to the same array and same table.\n    To achieve what a C# or Java programmer would expect, the following approach should be taken. ::\n\n        class Foo {\n            myarray = null\n            mytable = null\n            constructor() {\n                this.myarray = [1,2,3]\n                this.mytable = {}\n            }\n        }\n\n        let a = Foo()\n        let b = Foo()\n\nWhen a class defines a method called 'constructor', the class instantiation operation will\nautomatically invoke it for the newly created instance.\nThe constructor method can have parameters, this will impact on the number of parameters\nthat the *instantiation operation* will require.\nConstructors, as normal functions, can have variable number of parameters (using the parameter ``...``).\n\n::\n\n    class Rect {\n        constructor(w,h) {\n            this.width = w\n            this.height = h\n        }\n        x = 0\n        y = 0\n        width = null\n        height = null\n    }\n\n    //Rect's constructor has 2 parameters so the class has to be 'called'\n    //with 2 parameters\n    let rc = Rect(100,100)\n\nAfter an instance is created, its properties can be set or fetched following the\nsame rules that apply to tables. Methods cannot be set.\n\nInstance members cannot be removed.\n\nThe class object that created a certain instance can be retrieved through the built-in function\n``instance.getclass()`` (see :ref:`built-in functions <builtin_functions>`)\n\nThe operator ``instanceof`` tests if a class instance is an instance of a certain class.\n\n::\n\n    let rc = Rect(100, 100)\n    if (rc instanceof Rect) {\n        println(\"It's a rect\")\n    }\n    else {\n        println(\"It isn't a rect\")\n    }\n\n.. note:: Since Squirrel 3.x instanceof doesn't throw an exception if the left expression is not a class, it simply fails\n\n--------------\nInheritance\n--------------\n\n.. index::\n    pair: inheritance; Class\n    single: Inheritance\n\nQuirrel's classes support single inheritance.\nThe syntax for a derived class is the following: ::\n\n    class DerivedClas(BaseClass) {\n        function DoSomething() {\n            println(\"I'm doing something\")\n        }\n    }\n\nWhen a derived class is declared, Quirrel first copies all base's members in the\nnew class then proceeds with evaluating the rest of the declaration.\n\nA derived class inherits all members and properties of its base, if the derived class\noverrides a base function the base implementation is shadowed.\nIt's possible to access a overridden method of the base class by fetching the method from it\nthrough the 'base' keyword.\n\nHere an example:\n\n::\n\n    class Foo {\n        function DoSomething() {\n            println(\"I'm the base\")\n        }\n    };\n\n    class SuperFoo(Foo) {\n        //overridden method\n        function DoSomething() {\n            //calls the base method\n            base.DoSomething()\n            println(\"I'm doing something\")\n        }\n    }\n\n\nSame rule apply to the constructor. The constructor is a regular function (apart from being automatically invoked on construction).\n\n::\n\n    class BaseClass {\n        constructor() {\n            println(\"Base constructor\")\n        }\n    }\n\n    class ChildClass(BaseClass) {\n        constructor() {\n            base.constructor()\n            println(\"Child constructor\")\n        }\n    }\n\n    let test = ChildClass()\n\n\nThe base class of a derived class can be retrieved through the built-in method ``getbase()``.\n\n::\n\n    let thebaseclass = SuperFoo.getbase()\n\n\nNote that because methods do not have special protection policies when calling methods of the same\nobjects, a method of a base class that calls a method of the same class can end up calling a overridden method of the derived class.\n\nA method of a base class can be explicitly invoked by a method of a derived class though the keyword ``base`` (as in base.MyMethod() ).\n\n::\n\n    class Foo {\n        function DoSomething() {\n            println(\"I'm the base\")\n        }\n        function DoIt() {\n            this.DoSomething()\n        }\n    };\n\n    class SuperFoo(Foo) {\n        //overridden method\n        function DoSomething() {\n            println(\"I'm the derived\")\n        }\n        function DoIt() {\n            base.DoIt()\n        }\n    }\n\n    //creates a new instance of SuperFoo\n    let inst = SuperFoo()\n\n    //prints \"I'm the derived\"\n    inst.DoIt()\n\n----------------------\nMetamethods\n----------------------\n\n.. index::\n    pair: metamethods; Class\n    single: Class metamethods\n\nClass instances allow the customization of certain aspects of the\ntheir semantics through metamethods(see see :ref:`Metamethods <metamethods>`).\nFor C++ programmers: \"metamethods behave roughly like overloaded operators\".\nThe metamethods supported by classes are ``_add, _sub, _mul, _div, _unm, _modulo,\n_set, _get, _typeof, _nexti, _cmp, _call, _delslot, _tostring``\n\nthe following example show how to create a class that implements the metamethod ``_add``.\n\n::\n\n    class Vector3 {\n        constructor(...) {\n            if(vargv.len() >= 3) {\n                this.x = vargv[0]\n                this.y = vargv[1]\n                this.z = vargv[2]\n            }\n        }\n        function _add(other) {\n            return ::Vector3(this.x+other.x, this.y+other.y, this.z+other.z)\n        }\n\n        x = 0\n        y = 0\n        z = 0\n    }\n\n    let v0 = Vector3(1,2,3)\n    let v1 = Vector3(11,12,13)\n    let v2 = v0 + v1\n    println($\"{v2.x}, \"{v2.y}, {v2.z}\")\n"
  },
  {
    "path": "doc/source/reference/language/compiler_directives.rst",
    "content": ".. _compiler_directives:\n\n\n=========================\nCompiler directives\n=========================\n\n.. index::\n    single: Compiler directives\n\nQuirrel has a way to for flexibly customize language features.\n\nThis allows to smoothly change compiler, while keeping backward compatibility if needed.\n\nExample\n::\n\n   #default:strict\n\n   function foo() {\n     #relaxed-bool\n     if (123)\n       print(\"bar\")\n   }\n\n\nPrefix directive with 'default:' to apply it to entire VM, otherwise directive applies to closure in which it is declared.\n\n\n=============================\nList of Compiler directives\n=============================\n\n\n-----------------------------------------------\nDisable access to root table via ``::``\n-----------------------------------------------\n\n::\n\n    #forbid-root-table\n\nForbids use of ``::`` operator for the current unit\nUsing root table is dangerous (as all global vairables)\n\n-----------------------------------------------\nEnable access to root table via ``::``\n-----------------------------------------------\n\n::\n\n    #allow-root-table\n\nAllows use of ``::`` operator for the current unit\n\n\n----------------------------------------------\nClone operator\n----------------------------------------------\n\n  ::\n    \n    #allow-clone-operator\n\nAllow using 'clone' operator (let a = clone {})\n\n  ::\n    \n    forbid-clone-operator\n\nForbid using 'clone' operator use .$clone instead (let a = {}.$clone())\n'clone' is not a keyword in this case you call variables with it for example.\n\n----------------------------------------------\nDelete operator\n----------------------------------------------\n\n  ::\n    \n    #allow-delete-operator\n\nAllow using 'delete' operator (let a = delete {foo = 2}[\"foo\"] //2)\n\n  ::\n    \n    forbid-delete-operator\n\nForbid using 'delete' operator use .$rawdelete instead (let a = {foo=2}.$rawdelete(\"foo\") //2)\n'delete' is not a keyword in this case and you call variables with it for example.\n\n\n----------------------------------------------\n`switch` statement\n----------------------------------------------\n\n  ::\n\n    #allow-switch-statement\n\nAllow 'switch' statement in syntax (deprecated)\n\n  ::\n\n    #forbid-switch-statement\n\nExclude ``switch`` statement and ``switch`` / ``case`` / ``default`` keywords from syntax\n\n------------------\n#strict\n------------------\n\n::\n\n   #strict\n\nEnable all extra checks/restrictions\n\n\n------------------\n#relaxed\n------------------\n\n::\n\n   #relaxed\n\nDisable all extra checks/restrictions\n\n\n"
  },
  {
    "path": "doc/source/reference/language/constants_and_enumerations.rst",
    "content": ".. _constants_and_enumerations:\n\n\n========================\nConstants & Enumerations\n========================\n\n.. index::\n    single: Constants & Enumerations\n\n\n\nQuirrel allows to bind constant values to an identifier that will be evaluated compile-time.\nThis is achieved though constants and Enumerations.\n\n---------------\nConstants\n---------------\n\n.. index::\n    single: Constants\n\nConstants bind a specific value to an identifier. Constants are similar to\nglobal values, except that they are evaluated compile time and their value cannot be changed.\n\nConstants values can be:\n    * Simple types such as integers, floats, null, string literals\n    * Tables and arrays of simple types (nested table/arrayes are allowed)\n    * Values of other constants\n    * Results of evaluating pure functions\n    * Function declarations\n    * Arithmetic and logical expressions\n\nConstants are declared with the following syntax.::\n\n    const foobar = 100\n    const floatbar = 1.2\n    const stringbar = \"I'm a constant string\"\n    const nullconst = null\n    const compound = { a = 10, b = \"string\", c = 1.2, d = [null, 555], e = [1,2,3] }\n    const another = foobar\n    const nested = compound.d[1]\n    const evaluated = foobar + ((\"a\" in compound) ? compound.e[0] : (nullconst ?? floatbar))\n\n::\n    from \"math\" import max\n    const maxval = max(10, 20)\n\nConstants are locally scoped, from the moment they are declared.\nTo make constant global, use the ``global`` keyword.::\n\n    global const baz = 123\n\n::\n\n    let x = foobar * 2\n\n..  Warning::\n  Constant values are initialized at compile-time when code is being generated, not executed.\n  And their values can be reassigned with new ones (also during compilation) while the same constant objects is being used in generated code.\n\nExample::\n\n  global const foo = 0\n  if (\"foo\" not in getconsttable())\n    global const foo = 1\n  print(foo) //prints 1\n\n-----------------------\nInline const expression\n-----------------------\n\nA `const` keyword can also be used in an expression to declare a local anonymous constant.\n\n::\n\n    let x = const [5,6,7]\n    println(x[2]) // prints 7\n\n    let y = 2>3 ? const [1,2,3] : const [8,9,0]\n    println(y[2]) // prints 0\n\nUsing this method functions can be declared\n\n::\n\n    const lambda = @[pure](x) x*123\n    const foo = function [pure] foo() {}\n\nThe latter expression can be written in a shorter form:\n\n::\n\n    const function [pure] foo() {}\n\nFunctions declared as compile-time constants can contain nested functions,\nbut cannot reference any outer variables.\n\n---------------\nEnumerations\n---------------\n\n.. index::\n    single: Enumerations\n\nAs Constants, Enumerations bind a specific value to a name. Enumerations are also evaluated at compile time\nand their value cannot be changed.\n\nAn enum declaration introduces a new enumeration into the program.\nEnumeration values can only be integers, floats or string literals. No expression are allowed.::\n\n    enum Stuff {\n      first, //this will be 0\n      second, //this will be 1\n      third //this will be 2\n    }\n\nor::\n\n    enum Stuff {\n      first = 10\n      second = \"string\"\n      third = 1.2\n    }\n\nAn enum value is accessed in a manner that's similar to accessing a static class member.\nThe name of the member must be qualified with the name of the enumeration, for example ``Stuff.second``\n\n::\n\n    let x = Stuff.first * 2\n\nLike with constants, to declare globally-scoped enum, use the ``global`` keyword.::\n\n    global enum Stuff { first, second }\n\n--------------------\nImplementation notes\n--------------------\n\nEnumerations and Constants are a compile-time feature.\n\nIf a const or enum is global, when declared it is added compile time to the ``consttable``. This table is stored in the VM shared state\nand is shared by the VM and all its threads.\nThe ``consttable`` is a regular quirrel table; In the same way as the ``roottable``\nit can be modified runtime.\nYou can access the ``consttable`` through the built-in function ``getconsttable()``\nand also change it through the built-in function ``setconsttable()``\n\nhere some example: ::\n\n    //creates a constant\n    getconsttable()[\"something\"] <- 10\"\n    //creates an enumeration\n    getconsttable()[\"somethingelse\"] <- { a = \"10\", c = \"20\", d = \"200\"};\n    //deletes the constant\n    delete getconsttable()[\"something\"]\n    //deletes the enumeration\n    delete getconsttable()[\"somethingelse\"]\n\nThis system allows to procedurally declare constants and enumerations, it is also possible to assign any quirrel type\nto a constant/enumeration(function,classes etc...). However this will make serialization of a code chunk impossible.\n"
  },
  {
    "path": "doc/source/reference/language/datatypes.rst",
    "content": ".. _datatypes_and_values:\n\n=====================\nValues and Data types\n=====================\n\nWhile Quirrel is a dynamically typed language and variables do not\nhave a type, different operations may interpret the variable as\ncontaining a type. Quirrel's basic types are integer, float, string,\nnull, table, array, function, generator, class, instance, bool, thread\nand userdata.\n\nEach value in Quirrel is an instance of a built-in type class (available through\nthe ``types`` module):\n\n* ``Integer``\n* ``Float``\n* ``Bool``\n* ``String``\n* ``Array``\n* ``Table``\n* ``Null``\n* ``Function`` - for both script and native closures\n* ``Generator``\n* ``Thread`` - thread/coroutine\n* ``Class``\n* ``Instance``\n* ``WeakRef``\n* ``Userdata``\n\nThese classes can be used with ``instanceof`` for type checking.\nSee :ref:`Built-in Type Classes <builtin_type_classes>` for available methods on each type.\n\n.. _userdata-index:\n\n--------\nInteger\n--------\n\nAn Integer represents a 32 bit (or better) signed number.::\n\n    local a = 123 //decimal\n    local b = 0x0012 //hexadecimal\n    local d = 'w' //char code\n    local e = 123_456 // underscores may be used to visually sepearate digit groups\n    local f = 0xAB_CD_01_23 // also underscores\n\n--------\nFloat\n--------\n\nA float represents a 32 bit (or better) floating point number.::\n\n    local a = 1.0\n    local b = 0.234\n    local c = 6.5e-11 //exponential notation\n    local d = 12.345_67e+2 // digit group separators\n\n--------\nString\n--------\n\nStrings are an immutable sequence of characters. In order to modify a\nstring is it necessary create a new one.\n\nQuirrel's strings are similar to strings in C or C++.  They are\ndelimited by quotation marks(``\"``) and can contain escape\nsequences (``\\t``, ``\\a``, ``\\b``, ``\\n``, ``\\r``, ``\\v``, ``\\f``,\n``\\\\``, ``\\\"``, ``\\'``, ``\\0``, ``\\x<hh>``, ``\\u<hhhh>`` and\n``\\U<hhhhhhhh>``).\n\nVerbatim string literals do not interpret escape sequences. They begin\nwith ``@\"`` and end with the matching quote.  Verbatim string literals\nalso can extend over a line break. If they do, they include any white\nspace characters between the quotes: ::\n\n    let a = \"I'm a wonderful string\\n\"\n    // has a newline at the end of the string\n    let x = @\"I'm a verbatim string\\n\"\n    // the \\n is literal, similar to \"\\\\n\" in a regular string.\n\nHowever, a doubled quotation mark within a verbatim string is replaced\nby a single quotation mark: ::\n\n    let multiline = @\"\n        this is a multiline string\n        it will \"\"embed\"\" all the new line\n        characters\n    \"\n\n--------\nNull\n--------\n\nThe null value is a primitive value that represents the null, empty, or non-existent\nreference. The type Null has exactly one value, called null.::\n\n    local a = null\n\n--------\nBool\n--------\n\nBool is a double-valued (Boolean) data type. Its literals are ``true``\nand ``false``. A bool value expresses the validity of a condition\n(tells whether the condition is true or false).::\n\n    local a = true\n\n--------\nTable\n--------\n\nTables are associative containers implemented as a set of key/value pairs\ncalled slots.::\n\n    let t = {}\n    let test = {\n        a = 10\n        b = function(x) { return x+1 }\n    }\n\n--------\nArray\n--------\n\nArrays are simple sequence of objects. Their size is dynamic and their index always starts from 0.::\n\n    let a  = [\"I'm\",\"an\",\"array\"]\n    let b = [null]\n    b[0] = a[2]\n\n--------\nFunction\n--------\n\nFunctions are similar to those in other C-like languages with a few key differences (see below).\n\n--------\nClass\n--------\n\nClasses are associative containers implemented as sets of key/value\npairs. Classes are created through a 'class expression' or a 'class\nstatement'. class members can be inherited from another class object\nat creation time. After creation, members can be added until an\ninstance of the class is created.\n\n--------------\nClass Instance\n--------------\n\nClass instances are created by calling a *class object*. Instances, as\ntables, are implemented as sets of key/value pairs. Instance members\ncannot be dynamically added or removed; however the value of the\nmembers can be changed.\n\n---------\nGenerator\n---------\n\nGenerators are functions that can be suspended with the statement\n'yield' and resumed later (see :ref:`Generators <generators>`).\n\n---------\nUserdata\n---------\n\nUserdata objects are blobs of memory or pointers defined by the host\napplication but stored within Quirrel variables (See :ref:`Userdata\nand UserPointers <embedding_userdata_and_userpointers>`).\n\n---------\nThread\n---------\n\nThreads are objects representing a cooperative thread of execution,\nalso known as coroutines.\n\n--------------\nWeak Reference\n--------------\n\nWeak References are objects that point to another (non-scalar) object but do not own a strong reference to it.\n(See :ref:`Weak References <weak_references>`).\n"
  },
  {
    "path": "doc/source/reference/language/destructuring_assignment.rst",
    "content": ".. _destructuring_assignment:\n\n\n=========================\nDestructuring assignment\n=========================\n\n.. index::\n    single: Destructuring assignment\n\nThe destructuring assignment syntax is an expression that makes it possible to unpack\nvalues from arrays, or properties from tables/classes/instances, into distinct variables.\nThis is similar to destructuring assignment in JavaScript (ECMAScript 2015)\n\nExample\n::\n\n   let arr = [123, 567]\n   let [a, b] = arr\n   print(a) // => 123\n   print(b) // => 567\n\n   function foo() {\n     return {x = 555, y=777, z=999, w=111}\n   }\n   let {x, y=1, q=3} = foo()\n   print(x) // => 555\n   print(y) // => 777\n   print(q) // => 3\n\nIf a default value is provided it will be used if the slot does not exist in the source object.\nIf no default value is given and a slot with this name/index is missing, a runtime error will be raised.\nComma separators are optional.\n\n\nDestructuring in function parameters\n====================================\n\nDestructuring patterns can also be used directly in function parameter lists.\nThis allows function arguments to be unpacked at the call site, with full support\nfor default values and type annotations.\n\nExample\n::\n\n   function test1({x, y}, [a, b]) {\n     println(x, y, a, b)\n   }\n\n   function test2({x: int = 5}, [a: string, b: float = 2.2]) {\n     println(x, a, b)\n   }\n\nDefault values in destructured parameters are applied when the corresponding\nslot is missing in the passed argument. Type annotations may be used on individual\ndestructured elements in the same way as for regular parameters.\n\nEmpty patterns ``{}`` and ``[]`` are accepted and simply discard the argument.\n\n\nDestructuring in ``foreach`` loops\n==================================\n\nThe iteration value of a ``foreach`` loop may be a destructuring pattern. Both\ntable-style ``{...}`` and array-style ``[...]`` patterns are supported, with or\nwithout an index variable. Default values and type annotations work the same\nway as in :ref:`destructuring_assignment` and in function parameters.\n\nExample\n::\n\n   let pairs = [[1, 2], [3, 4]]\n   foreach ([a, b] in pairs)\n     println(a, b)\n\n   let rows = [{x = 1, y = 2}, {x = 3, y = 4}]\n   foreach (i, {x, y} in rows)\n     println(i, x, y)\n\n   // defaults applied when a slot is missing\n   foreach ({x = -1, y = -2} in [{x = 10}, {y = 20}, {}])\n     println(x, y)\n\n   // typed defaults\n   foreach ({x: int = 0, y: int|null = null} in [{x = 5}, {y = 7}])\n     println(x, y)\n\n   // empty patterns are allowed (the iteration value is discarded)\n   foreach ({} in rows)\n     println(\"tick\")\n\nThe destructured bindings are scoped to the loop body. Each iteration produces\nfresh bindings, so closures captured inside the body observe the value from\ntheir own iteration.\n"
  },
  {
    "path": "doc/source/reference/language/expressions.rst",
    "content": ".. _expressions:\n\n\n=================\nExpressions\n=================\n\n.. index::\n    single: Expressions\n\n----------------\nAssignment\n----------------\n\n.. index::\n    single: assignment(=)\n\n::\n\n    exp := derefexp '=' exp\n\n::\n\n    a = 10\n\nFor adding new fields to tables there is the \"new slot\" operator. (see :ref:`Tables <tables>`)\n\n::\n\n    exp:= derefexp '<-' exp\n\n::\n\n    tbl.a <- 10\n    tbl[\"b\"] <- 20\n\nIf the slot already exists in the table this behaves like a normal assignment.\n\n----------------\nOperators\n----------------\n\n.. index::\n    single: Operators\n\n^^^^^^^^^^^^^\n?: Operator\n^^^^^^^^^^^^^\n\n.. index::\n    pair: ?: Operator; Operators\n\n::\n\n    exp := exp_cond '?' exp1 ':' exp2\n\nconditionally evaluate an expression depending on the result of an expression.\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n?? Null-coalescing operator\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: ?? Operator; Operators\n\n::\n\n    exp := exp1 '??' exp2\n\n\nConditionally evaluate an expression2 depending on the result of an expression1.\nGiven code is equivalent to:\n\n::\n\n    exp := (exp1 '!=' null) '?' exp1 ':' exp2\n\n\nC#-like ``??`` syntax was chosen over Elvis operator ``?:`` which is\ncommon in other languages because it is not equivalent to\nvisually similar ternary ``? :`` operator (which checks for falsiness,\nnot null).\n\nIt evaluates expressions until the first non-null value\n(just like ``||`` operators for the first ``true`` one).\n\nOperator precedence also follows C# design, so that ``??`` has\nlower priority than ``||``\n\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n?. and ?[] - Null-propagation operators\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: ?. and ?[] Operators; Operators\n\n::\n\n    exp := value '?.' key\n\n\n::\n\n    exp := value '?[' key ']'\n\n\nIf key exists, return result of 'get' operations, else return null.\n\n::\n\n    let tbl = {bar=123}\n\n    tbl.bar // returns 123\n    tbl.baz // throws an error\n    tbl?.bar // returns 123\n    tbl?.baz // returns null\n    null.bar // throws an error\n    null?.bar // returns null\n    tbl?[\"bar\"] // returns 123\n    tbl?[4567] // returns null\n\n\nThis works for any type (internally done via SQVM::Get(), like an 'in' operator), including null.\nTherefore operator can be chained\n\n::\n\n    let x = tbl?.foo?.bar?.baz?[\"spam\"]\n\nTo avoid extra typing, null-propagation operators affect the rest of expression.\nOtherwise, an expression like\n\n::\n\n    a?.b.c.d\n\nwould make no sense because without automatic propagation a null value's slot could possibly be accessed in runtime.\nOne would have to type ?. everywhere, writing it as\n\n::\n\n    a?.b?.c?.d\n\nInstead it is done by compiler - once a null-operator is met, it is also assumed for the subsequent ., [] and () operators in an expression.\n\nNote: 'key' should not be separated from '?.' or '.' by space[s] or new line.\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n.$ and ?.$ - Type methods access operator\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: .$ and ?.$ Operators; Operators\n\n::\n\n    exp := value '.$' key\n\n\n::\n\n    exp := value '?.$' key\n\n\nIf 'key' exists in value's type methods returns method's closure, else returns null in case of '?.$' or throws an error if '.$'\n\nNote: 'key' should not be separated from '.$' and '?.$' by space[s] or new line.\n\n^^^^^^^^^^^^^\nArithmetic\n^^^^^^^^^^^^^\n\n.. index::\n    pair: Arithmetic Operators; Operators\n\n::\n\n    exp:= 'exp' op 'exp'\n\nQuirrel supports the standard arithmetic operators ``+, -, *, / and %``.\nOther than that is also supports compact operators (``+=,-=,*=,/=,%=``) and\nincrement and decrement operators(++ and --);::\n\n    a += 2;\n    //is the same as writing\n    a = a + 2;\n    x++\n    //is the same as writing\n    x = x + 1\n\nAll operators work normally with integers and floats; if one operand is an integer and one\nis a float the result of the expression will be float.\nThe ``+`` operator has a special behavior with strings; if one of the operands is a string the\noperator ``+`` will try to convert the other operand to string as well and concatenate both\ntogether. For instances and tables, ``_tostring`` is invoked.\n\n^^^^^^^^^^^^^\nRelational\n^^^^^^^^^^^^^\n\n.. index::\n    pair: Relational Operators; Operators\n\n::\n\n    exp:= 'exp' op 'exp'\n\nRelational operators in Quirrel are : ``==, <, <=, <, <=, !=``\n\nThese operators return ``true`` if the expression is ``false`` and a value different than ``true`` if the\nexpression is ``true``. Internally the VM uses the integer ``1`` as ``true`` but this could change in\nthe future.\n\n^^^^^^^^^^^^^^\n3 ways compare\n^^^^^^^^^^^^^^\n\n.. index::\n    pair: 3 ways compare operator; Operators\n\n::\n\n    exp:= 'exp' <=> 'exp'\n\nthe 3 ways compare operator <=> compares 2 values A and B and returns an integer less than 0\nif A < B, 0 if A == B and an integer greater than 0 if A > B.\n\n^^^^^^^^^^^^^^\nLogical\n^^^^^^^^^^^^^^\n\n.. index::\n    pair: Logical operators; Operators\n\n::\n\n    exp := exp op exp\n    exp := '!' exp\n\nLogical operators in Quirrel are : ``&&, ||, !``\n\nThe operator ``&&`` (logical and) returns null if its first argument is null, otherwise returns\nits second argument.\nThe operator ``||`` (logical or) returns its first argument if is different than null, otherwise\nreturns the second argument.\n\nThe '!' operator will return null if the given value to negate was different than null, or a\nvalue different than null if the given value was null.\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nin operator, not in operator\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: in operator, not in operator; Operators\n\n::\n\n    exp:= keyexp 'in' tableexp\n    exp:= keyexp 'not in' tableexp\n\nTests the existence of a slot in a table.\n'in' operator returns true if *keyexp* is a valid key in *tableexp*\n'not in' operator returns true if *keyexp* is missing in *tableexp*\n\n::\n\n    let t = {\n        foo=\"I'm foo\",\n        [123]=\"I'm not foo\"\n    }\n\n    if(\"foo\" in t) dostuff(\"yep\");\n    if(123 in t) dostuff();\n    if(123 not in t) dostuff();\n\n^^^^^^^^^^^^^^^^^^^\ninstanceof operator\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: instanceof operator; Operators\n\n::\n\n    exp:= instanceexp 'instanceof' classexp\n\nTests if a class instance is an instance of a certain class.\nReturns true if *instanceexp* is an instance of *classexp*.\n\n^^^^^^^^^^^^^^^^^^^\ntypeof operator\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: typeof operator; Operators\n\n::\n\n    exp:= 'typeof' exp\n\nreturns the type name of a value as string.::\n\n    local a={},b=\"quirrel\"\n    print(typeof a); //will print \"table\"\n    print(typeof b); //will print \"string\"\n\n^^^^^^^^^^^^^^^^^^^\nBitwise Operators\n^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: Bitwise Operators; Operators\n\n::\n\n    exp:= 'exp' op 'exp'\n    exp := '~' exp\n\nQuirrel supports the standard C-like bitwise operators ``&, |, ^, ~, <<, >>`` plus the unsigned\nright shift operator ``>>>``. The unsigned right shift works exactly like the normal right shift operator(``>>``)\nexcept for treating the left operand as an unsigned integer, so is not affected by the sign. Those operators\nonly work on integer values; passing of any other operand type to these operators will\ncause an exception.\n\n^^^^^^^^^^^^^^^^^^^^^\nOperators precedence\n^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: Operators precedence; Operators\n\n+---------------------------------------+-----------+\n| ``-, ~, !, typeof, static, ++, --,``  | highest   |\n+---------------------------------------+-----------+\n| ``/, *, %``                           | ...       |\n+---------------------------------------+-----------+\n| ``+, -``                              |           |\n+---------------------------------------+-----------+\n| ``<<, >>, >>>``                       |           |\n+---------------------------------------+-----------+\n| ``<, <=, >, >=, instanceof``          |           |\n+---------------------------------------+-----------+\n| ``==, !=, <=>``                       |           |\n+---------------------------------------+-----------+\n| ``&``                                 |           |\n+---------------------------------------+-----------+\n| ``^``                                 |           |\n+---------------------------------------+-----------+\n| ``&&, in``                            |           |\n+---------------------------------------+-----------+\n| ``||``                                |           |\n+---------------------------------------+-----------+\n| ``??``                                |           |\n+---------------------------------------+-----------+\n| ``+=, =, -=, /=, *=, %=``             | ...       |\n+---------------------------------------+-----------+\n\n.. _table_constructor:\n\n-----------------\nTable Constructor\n-----------------\n\n.. index::\n    single: Table Contructor\n\n::\n\n    tslots := ( 'id' '=' exp | '[' exp ']' '=' exp  | 'id' ) [',']\n    exp := '{' [tslots] '}'\n\nCreates a new table.::\n\n    let a = {} //create an empty table\n\nA table constructor can also contain slots declaration; With the syntax: ::\n\n    let a = {\n        slot1 = \"I'm the slot value\"\n    }\n\nAn alternative syntax can be::\n\n    '[' exp1 ']' = exp2 [',']\n\nA new slot with exp1 as key and exp2 as value is created::\n\n    let a = {\n        [1]=\"I'm the value\"\n    }\n\nES2015-style shorthand table initialization is supported, so the code like below ::\n\n    local x = 123\n    local y = 345\n    let tbl = {x=x, y=y}\n\ncan also be written as ::\n\n    local x = 123\n    local y = 345\n    let tbl = {x, y}\n\n\nAll syntaxes can be mixed::\n\n    local x = \"bar\"\n    let table=\n    {\n        a=10,\n        b=\"string\",\n        x,\n        [10]={},\n        function bau(a,b)\n        {\n            return a+b;\n        }\n    }\n\nThe comma between slots is optional.\n\n^^^^^^^^^^^^^^^^^^^^^^\nTable with JSON syntax\n^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Table with JSON syntax\n\nSince Squirrel 3.0 is possible to declare a table using JSON syntax(see http://www.wikipedia.org/wiki/JSON).\n\nthe following JSON snippet: ::\n\n    let x = {\n      \"id\": 1,\n      \"name\": \"Foo\",\n      \"price\": 123,\n      \"tags\": [\"Bar\",\"Eek\"]\n    }\n\nis equivalent to the following quirrel code: ::\n\n    let x = {\n      id = 1,\n      name = \"Foo\",\n      price = 123,\n      tags = [\"Bar\",\"Eek\"]\n    }\n\n-----------------\nclone\n-----------------\n\n.. index::\n    single: clone\n\n::\n\n    exp:= 'clone' exp\n\nClone performs shallow copy of a table, array or class instance (copies all slots in the new object without\nrecursion).\n\nAfter the new object is ready the \"_cloned\" meta method is called (see :ref:`Metamethods <metamethods>`).\n\nWhen a class instance is cloned the constructor is not invoked(initializations must rely on ```_cloned``` instead\n\nNote: Usage of this operator could be prohibited with ``#forbid-clone-operator``.\n\n------------------------------------------\nStatic Memoization Operator (static)\n------------------------------------------\n\nThe ``static`` operator allows you to evaluate an expression once and cache the result for reuse every time that part of the script is executed again. This can improve performance and ensure result immutability.\n\n.. index::\n    single: static\n\n::\n\n    exp := static exp\n\nBehavior:\n\n- The expression after ``static`` is evaluated only once on the first execution.\n- The resulting value is cached and reused on all subsequent executions at the same code location.\n- All data types are supported.\n- If the result of the expression is an object of one of the following types: \"array\", \"table\", \"instance\", \"class\", \"userdata\", it will be frozen (made immutable), as if passed to ``freeze()``, and cannot be modified.\n- Nested constant expressions are allowed but redundant, the outer ``static`` already handles caching.\n- Operator precedence is the same as for unary operators such as ``unary -``, ``typeof``, ``clone``.\n\nExamples:\n::\n\n    local x = static(expensiveCalculation()) // expensiveCalculation() is called only once\n\n    local frozenTable = static { a = 1, b = 2 } // table will be frozen\n    frozenTable.a = 42 // Error: attempt to modify a frozen object\n\nResetting Cached Values:\n\nTo clear all previously cached results, call ``reset_static_memos()``:\n::\n\n    let modules = require(\"modules\")\n    ...\n    modules.reset_static_memos()\n\nThis will cause all static memo expressions to be re-evaluated the next time they are executed.\n\n``reset_static_memos()`` is not a real-time operation. It is intended to be called infrequently, for example, when scripts are reloaded or the screen resolution changes.\n\n-----------------\nArray contructor\n-----------------\n\n.. index::\n    single: Array constructor\n\n::\n\n    exp := '[' [explist] ']'\n\nCreates a new array.::\n\n    a <- [] //creates an empty array\n\nArrays can be initialized with values during the construction::\n\n    a <- [1,\"string!\",[],{}] //creates an array with 4 elements\n"
  },
  {
    "path": "doc/source/reference/language/functions.rst",
    "content": ".. _functions:\n\n\n=================\nFunctions\n=================\n\n.. index::\n    single: Functions\n\nFunctions are first-class values like integers or strings and can be stored in table slots,\nlocal variables, arrays and passed as function parameters.\nFunctions can be implemented in Quirrel or in a native language with calling conventions\ncompatible with ANSI C.\n\n--------------------\nFunction declaration\n--------------------\n\n.. index::\n    single: Function Declaration\n\nA local function can be declared with the following function expression::\n\n    function tuna(a,b,c) {\n        return a+b-c;\n    }\n\n    let function tuna(a,b,c) {\n        return a+b-c;\n    }\n\n    let tuna = function tuna(a,b,c) {\n        return a+b-c;\n    }\n\nThese declarations mean that `tuna` can't be reassigned (see `bindings`)\n\nor::\n\n    local tuna = function tuna(a,b,c) {\n        return a+b-c;\n    }\n\n    local function tuna(a,b,c) {\n        return a+b-c;\n    }\n\n\nThese declarations declare a local variable that can be reassigned\n\n^^^^^^^^^^^^^^^^^^\nDefault Parameters\n^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Function Default Parameters\n\nQuirrel functions can have default parameters.\n\nA function with default parameters is declared as follows: ::\n\n    function test(a, b, c = 10, d = 20) {\n        ....\n    }\n\nwhen the function *test* is invoked and parameter c or d is not specified,\nthe VM automatically assigns the default value to the unspecified parameter. A default parameter can be\nany valid quirrel expression. The expression is evaluated at runtime.\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nFunctions with variable number of parameters\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Functions with variable number of parameters\n\nQuirrel functions can have a variable number of parameters (varargs functions).\n\nA vararg function is declared by adding three dots (``...``) at the end of its parameter list.\n\nWhen the function is called all the extra parameters will be accessible through the *array*\ncalled ``vargv``, that is passed as an implicit parameter.\n\n``vargv`` is a regular quirrel array and can be used accordingly.::\n\n    function test(a,b,...) {\n\n        for (local i = 0; i< vargv.len(); i++) {\n            println($\"varparam {i} = {vargv[i]}\")\n        }\n        foreach (i,val in vargv) {\n            println($\"varparam {i} = {val}\")\n        }\n    }\n\n    test(\"goes in a\",\"goes in b\",0,1,2,3,4,5,6,7,8)\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nFunction attributes\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Function attributes\n\nA function can have attributes that can be used to provide additional information about the function.\nCurrently the only supported attribute is ``pure``.\nA pure function is a function that does not have side effects and does not modify any\nexternal state. This can be used to optimize the evaluation of constant expressions.\n\nA pure function is declared as follows: ::\n\n    function [pure] test(a, b) {\n        return a + b\n    }\n\nor, in lambda form ::\n\n    @[pure](a, b) {\n        return a + b\n    }\n\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nType Annotations in Functions\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    single: Function Type Annotations\n\nQuirrel supports optional **type annotations** for function parameters and return values. Type annotations are validated during execution; passing a value of an incompatible type to a parameter or returning a mismatched type results in a runtime error. Type annotations improve code readability, enable better tooling support, and help document expected interfaces.\n\nA function with type annotations uses the following syntax::\n\n    function name(param1: Type1, param2: Type2, ...: VarargType): ReturnType {\n        // body\n    }\n\nParameter types are specified after a colon following the parameter name, and the return type is declared after the closing parenthesis of the parameter list, also preceded by a colon.\n\nSupported types include:\n\n- Primitive types: ``int``, ``float``, ``number`` (shorthand for ``int | float``), ``bool``, ``string``\n- Container and system types: ``table``, ``array``, ``function``, ``thread``, ``userdata``, ``generator``, ``userpointer``, ``instance``, ``class``, ``weakref``\n- Special types: ``null``, ``any``\n- Union types using the ``|`` operator: e.g., ``number | null``\n\nUnion types may be wrapped in parentheses for clarity::\n\n    function f(x: (number | null)): (null | number)\n\nVariadic parameters (``...``) can also be annotated to indicate the expected type of extra arguments::\n\n    function type_test2(x: int, ...: float): int {\n        return 1 + x\n    }\n\nHere, ``...: float`` documents that all variadic arguments are expected to be of type ``float``.\n\nDefault parameters may carry type annotations as well::\n\n    function type_test4(x: number|null = null): null|number {\n        return 1.0 + (x ?? 6)\n    }\n\nLambda (anonymous) functions fully support type annotations::\n\n    let type_test8 = @(x: bool|number|string, y: any): any (\n        x + y\n    )\n\nThe ``any`` type disables static checking for that position and accepts any value. It is useful when exact types are unknown or intentionally flexible.\n\nFunction attributes (such as ``[pure]``) can be combined with type annotations::\n\n    let type_test10 = (@ [pure] type_test10(x: bool|number|int|null, y: any): any (\n        x + y\n    ))\n\n\n---------------\nFunction calls\n---------------\n\n.. index::\n    single: Function calls\n\n::\n\n    exp:= derefexp '(' explist ')'\n\nThe expression is evaluated in this order: derefexp after the explist (arguments) and at\nthe end the call.\n\nA function call in Quirrel passes the current environment object *this* as a hidden parameter.\nBut when the function was immediately indexed from an object, *this* shall be the object\nwhich was indexed, instead.\n\nIf we call a function with the syntax::\n\n    mytable.foo(x,y)\n\nthe environment object passed to 'foo' as *this* will be 'mytable' (since 'foo' was immediately indexed from 'mytable')\n\nWhereas with the syntax::\n\n    foo(x,y) // implicitly equivalent to this.foo(x,y)\n\nthe environment object will be the current *this* (that is, propagated from the caller's *this*).\n\nIt may help to remember the rules in the following way:\n\n    ``foo(x,y)`` ---> ``this.foo(x,y)``\n\n    ``table.foo(x,y)`` ---> call ``foo`` with ``(table,x,y)``\n\nIt may also help to consider why it works this way: it was initially designed to assist with object-oriented style.\nWhen calling ``foo(x,y)`` it was assumed you're calling another member of the object (or of the file) and\nso should operate on the same object.\nWhen calling ``mytable.foo(x,y)`` it is written plainly that you're calling a member of a different object.\n\n---------------------------------------------\nBinding an environment to a function\n---------------------------------------------\n\n.. index::\n    single: Binding an environment to a function\n\nwhile by default a quirrel function call passes as environment object ``this``, the object\nfrom which the function was indexed. However, it is also possible to statically bind an environment to a\nclosure using the built-in method ``closure.bindenv(env_obj)``.\nThe method ``bindenv()`` returns a new instance of a closure with the environment bound to it.\nWhen an environment object is bound to a function, every time the function is invoked, its\n``this`` parameter will always be the previously bound environment.\nThis mechanism is useful to implement callback systems similar to C# delegates.\n\n.. note:: The closure keeps a weak reference to the bound environment object, because of this if\n          the object is deleted, the next call to the closure will result in a ``null``\n          environment object.\n\n---------------------------------------------\nLambda Expressions\n---------------------------------------------\n\n.. index::\n    single: Lambda Expressions\n\n::\n\n    exp := '@' '(' paramlist ')' exp\n\nLambda expressions are syntactic sugar to quickly define a function that consists of a single expression.\nThis feature comes in handy when functional programming patterns are applied, like map/reduce or passing a compare method to\narray.sort().\n\nhere is a lambda expression::\n\n    let myexp = @(a,b) a + b\n\nthat is equivalent to::\n\n    let myexp = function(a,b) { return a + b }\n\na more useful usage could be::\n\n    let arr = [2,3,5,8,3,5,1,2,6]\n    arr.sort(@(a,b) a <=> b)\n    arr.sort(@(a,b) -(a <=> b))\n\nthat could have been written as::\n\n    let arr = [2,3,5,8,3,5,1,2,6]\n    arr.sort(function(a,b) { return a <=> b } )\n    arr.sort(function(a,b) { return -(a <=> b) } )\n\nother than being limited to a single expression lambdas support all features of regular functions.\nin fact they are implemented as a compile-time feature.\n\n---------------------------------------------\nFree Variables\n---------------------------------------------\n\n.. index::\n    single: Free Variables\n\nA free variable is a variable external to the function scope and is not a local variable\nor parameter of the function.\nFree variables reference a local variable from an outer scope.\nIn the following example the variables ``testy``, ``x`` and ``y`` are bound to the function ``foo``.::\n\n    local x = 10\n    local y = 20\n    let testy = \"I'm testy\"\n\n    let function foo(a,b) {\n        print(testy)\n        return a+b+x+y\n    }\n\nA program can read or write a free variable.\n\n---------------------------------------------\nTail Recursion\n---------------------------------------------\n\n.. index::\n    single: Tail Recursion\n\nTail recursion is a method for partially transforming recursion in a program into\niteration: it applies when the recursive calls in a function are the last executed\nstatements in that function (just before the return).\nIf this happens the quirrel interpreter collapses the caller stack frame before the\nrecursive call; because of that very deep recursions are possible without risk of a stack\noverflow.::\n\n    function loopy(n) {\n        if (n > 0) {\n            println($\"n={n}\")\n            return loopy(n-1)\n        }\n    }\n\n    loopy(1000)\n"
  },
  {
    "path": "doc/source/reference/language/generators.rst",
    "content": ".. _generators:\n\n\n=================\nGenerators\n=================\n\n.. index::\n    single: Generators\n\nA function that contains a ``yield`` statement is called *'generator function'* .\nWhen a generator function is called, it does not execute the function body, instead it\nreturns a new suspended generator.\nThe returned generator can be resumed through the resume statement while it is alive.\nThe yield keyword, suspends the execution of a generator and optionally returns the\nresult of an expression to the function that resumed the generator.\nThe generator dies when it returns, this can happen through an explicit return\nstatement or by exiting the function body; If an unhandled exception (or runtime error)\noccurs while a generator is running, the generator will automatically die. A dead\ngenerator cannot be resumed anymore.::\n\n    function geny(n) {\n        for (local i=1; i<=n; ++i)\n            yield i\n        return null\n    }\n\n    let gtor = geny(10)\n    for (local x=resume gtor; x; x=resume gtor)\n        print(x+\"\\n\")\n\nthe output of this program will be::\n\n    1\n    2\n    3\n    4\n    5\n    6\n    7\n    8\n    9\n    10\n\ngenerators can also be iterated using the foreach statement. When a generator is evaluated\nby ``foreach``, the generator will be resumed for each iteration until it returns. The value\nreturned by the ``return`` statement will be ignored.\n\n.. note:: A suspended generator will hold a strong reference to all the values stored in its local variables except the ``this``\n        object that is only a weak reference. A running generator holds a strong reference also to the ``this`` object.\n"
  },
  {
    "path": "doc/source/reference/language/lexical_structure.rst",
    "content": ".. _lexical_structure:\n\n\n=================\nLexical Structure\n=================\n\n.. index:: single: lexical structure\n\n-----------\nIdentifiers\n-----------\n\n.. index:: single: identifiers\n\nIdentifiers start with an alphabetic character or the symbol '_' followed by any number\nof alphabetic characters, '_' or digits ([0-9]). Quirrel is a case sensitive language\nmeaning that the lowercase and uppercase representation of the same alphabetic\ncharacter are considered different characters. For instance, \"foo\", \"Foo\" and \"fOo\" are\ntreated as 3 distinct identifiers.\n\n-----------\nKeywords\n-----------\n\n.. index:: single: keywords\n\nThe following words are reserved and cannot be used as identifiers:\n\n+------------+------------+-----------+------------+------------+-------------+\n| base       | break      | case      | catch      | class      | clone       |\n+------------+------------+-----------+------------+------------+-------------+\n| continue   | const      | default   | delete     | else       | enum        |\n+------------+------------+-----------+------------+------------+-------------+\n| for        | foreach    | function  | if         | in         |             |\n+------------+------------+-----------+------------+------------+-------------+\n| local      | null       | resume    | return     | switch     | this        |\n+------------+------------+-----------+------------+------------+-------------+\n| throw      | try        | typeof    | while      | yield      | constructor |\n+------------+------------+-----------+------------+------------+-------------+\n| instanceof | true       | false     | static     | __LINE__   | __FILE__    |\n+------------+------------+-----------+------------+------------+-------------+\n| let        |            |           |            |            |             |\n+------------+------------+-----------+------------+------------+-------------+\n\nKeywords are covered in detail later in this document.\n\n-----------\nOperators\n-----------\n\n.. index:: single: operators\n\nQuirrel recognizes the following operators:\n\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``!``    | ``!=``   | ``||``   | ``==``   | ``&&``   | ``>=``   | ``<=``   | ``>``    |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``<=>``  | ``+``    | ``+=``   | ``-``    | ``-=``   | ``/``    | ``/=``   | ``*``    |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``*=``   | ``%``    | ``%=``   | ``++``   | ``--``   | ``<-``   | ``=``    | ``&``    |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n| ``^``    | ``|``    | ``~``    | ``>>``   | ``<<``   | ``>>>``  | ``??``   |          |\n+----------+----------+----------+----------+----------+----------+----------+----------+\n\n------------\nOther tokens\n------------\n\n.. index::\n    single: delimiters\n    single: other tokens\n\nOther significant tokens are:\n\n+----------+----------+----------+----------+----------+----------+\n| ``{``    | ``}``    | ``[``    | ``]``    | ``.``    | ``:``    |\n+----------+----------+----------+----------+----------+----------+\n| ``::``   | ``'``    | ``;``    | ``\"``    | ``@\"``   |          |\n+----------+----------+----------+----------+----------+----------+\n\n-----------\nLiterals\n-----------\n\n.. index::\n    single: literals\n    single: string literals\n    single: numeric literals\n\nQuirrel accepts integer numbers, floating point numbers and string literals.\n\n+-------------------------------+------------------------------------------+\n| ``34``                        | Integer number(base 10)                  |\n+-------------------------------+------------------------------------------+\n| ``0xFF00A120``                | Integer number(base 16)                  |\n+-------------------------------+------------------------------------------+\n| ``0753``                      | Integer number(base 8)                   |\n+-------------------------------+------------------------------------------+\n| ``'a'``                       | Integer number                           |\n+-------------------------------+------------------------------------------+\n| ``1.52``                      | Floating point number                    |\n+-------------------------------+------------------------------------------+\n| ``1.e2``                      | Floating point number                    |\n+-------------------------------+------------------------------------------+\n| ``1.e-2``                     | Floating point number                    |\n+-------------------------------+------------------------------------------+\n| ``\"I'm a string\"``            | String                                   |\n+-------------------------------+------------------------------------------+\n| ``@\"I'm a verbatim string\"``  | String                                   |\n+-------------------------------+------------------------------------------+\n| ``@\" I'm a``                  |                                          |\n| ``multiline verbatim string`` |                                          |\n| ``\"``                         | String                                   |\n+-------------------------------+------------------------------------------+\n\nPesudo BNF\n\n.. productionlist::\n    IntegerLiteral : [1-9][0-9]* | '0x' [0-9A-Fa-f]+ | ''' [.]+ ''' | 0[0-7]+\n    FloatLiteral : [0-9]+ '.' [0-9]+\n    FloatLiteralExp : [0-9]+ '.' 'e'|'E' '+'|'-' [0-9]+\n    StringLiteral: '\"'[.]* '\"'\n    VerbatimStringLiteral: '@''\"'[.]* '\"'\n\n-----------\nComments\n-----------\n\n.. index:: single: comments\n\nA comment is text that the compiler ignores but that is useful for programmers.\nComments are normally used to embed annotations in the code. The compiler\ntreats them as white space.\n\nA comment can be ``/*`` (slash, asterisk) characters, followed by any\nsequence of characters (including new lines),\nfollowed by the ``*/`` characters. This syntax is the same as ANSI C.::\n\n    /*\n    this is\n    a multiline comment.\n    this lines will be ignored by the compiler\n    */\n\nA comment can also be ``//`` (two slashes) characters, followed by any sequence of\ncharacters.  A new line not immediately preceded by a backslash terminates this form of\ncomment.  It is commonly called a *\"single-line comment.\"*::\n\n    //this is a single line comment. this line will be ignored by the compiler\n"
  },
  {
    "path": "doc/source/reference/language/limitations.rst",
    "content": ".. _limitation:\n\n\n=================\nLimitations\n=================\n\n.. index::\n    single: Limitations\n\nQuirrel has a number of limitations\n\n - Maximum number of local variables (including `let`-bindings) is **256**\n - Maximum nesting level of code tree is **500**"
  },
  {
    "path": "doc/source/reference/language/metamethods.rst",
    "content": ".. _metamethods:\n\n-----------\nMetamethods\n-----------\n\nMetamethods are a mechanism that allows the customization of certain aspects of the\nlanguage semantics. Those methods are normal functions placed in a class declaration;\nIt is possible to change many aspects of a table/class instance behavior by just defining\na metamethod.\n\nFor example when we use relational operators other than '==' on 2 instances, the VM will\ncheck if the class has a method in his parent called '_cmp'; if so it will call it to determine\nthe relation between the objects.::\n\n    class Comparable {\n        constructor(n)\n        {\n            name = n;\n        }\n        function _cmp(other)\n        {\n            if(name<other.name) return -1;\n            if(name>other.name) return 1;\n            return 0;\n        }\n        name = null;\n    }\n\n    let a = Comparable(\"Alberto\");\n    let b = Comparable(\"Wouter\");\n\n    if(a>b)\n        print(\"a>b\")\n    else\n        print(\"b<=a\");\n\n^^^^^\n_set\n^^^^^\n\n::\n\n    _set(idx,val)\n\ninvoked when the index idx is not present in the object or in its delegate chain.\n``_set`` must 'throw null' to notify that a key wasn't found but the there were not runtime errors (clean failure).\nThis allows the program to differentiate between a runtime error and a 'index not found'.\n\n^^^^^\n_get\n^^^^^\n\n::\n\n    _get(idx)\n\ninvoked when the index idx is not present in the object or in its delegate chain.\n_get must 'throw null' to notify that a key wasn't found but the there were not runtime errors (clean failure).\nThis allows the program to differentiate between a runtime error and a 'index not found'.\n\n^^^^^^^^^\n_newslot\n^^^^^^^^^\n\n::\n\n    _newslot(key,value)\n\ninvoked when a script tries to add a new slot in a table.\n\nif the slot already exists in the target table the method will not be invoked also if the\n\"new slot\" operator is used.\n\n^^^^^^^^^\n_delslot\n^^^^^^^^^\n\n::\n\n    _delslot(key)\n\ninvoked when a script deletes a slot from a table.\nif the method is invoked quirrel will not try to delete the slot himself\n\n^^^^^^^^\n_add\n^^^^^^^^\n\n::\n\n    _add(other)\n\nthe + operator\n\nreturns this + other\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_sub\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _sub(other)\n\nthe - operator (like _add)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_mul\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _mul(other)\n\nthe ``*`` operator (like _add)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_div\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _div(other)\n\nthe ``/`` operator (like _add)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_modulo\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _modulo(other)\n\nthe ``%`` operator (like _add)\n\n^^^^^^^^^\n_unm\n^^^^^^^^^\n\n::\n\n    _unm()\n\nthe unary minus operator\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_typeof\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _typeof()\n\ninvoked by the typeof operator on tables, userdata, and class instances.\n\nReturns the type of ``this`` as string\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_cmp\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _cmp(other)\n\ninvoked to emulate the ``< > <= >=`` and ``<=>`` operators\n\nreturns an integer as follow:\n\n+-----------+----------------------------+\n| returns   | relationship               |\n+===========+============================+\n|  > 0      | if ``this`` > ``other``    |\n+-----------+----------------------------+\n|  0        | if ``this`` == ``other``   |\n+-----------+----------------------------+\n|  < 0      | if ``this`` < ``other``    |\n+-----------+----------------------------+\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_call\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _call(other)\n\ninvoked when a table, userdata, or class instance is called\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_cloned\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _cloned(original)\n\ninvoked when a table or class instance is cloned(in the cloned table)\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_nexti\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _nexti(previdx)\n\ninvoked when a userdata or class instance is iterated by a foreach loop.\n\nIf previdx==null it means that it is the first iteration.\nThe function has to return the index of the 'next' value.\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_tostring\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _tostring()\n\nInvoked when during string concatenation or when the ``print`` function prints a table, instance, or userdata.\nThe method is also invoked by the sq_tostring() API.\n\nMust return a string representation of the object.\n\n^^^^^^^^^^^^^^^^^^^^^^^^\n_lock\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n    _lock()\n\nMetamethods of class object only.\nCalled when a class is locked (manually by an explicit call to ``cls.lock()``, when the class is being inherited or when its instance is first created).\n``this`` references the class object itself.\nAt this stage the class still can be modified.\n"
  },
  {
    "path": "doc/source/reference/language/statements.rst",
    "content": ".. _statements:\n\n\n=================\nStatements\n=================\n\n.. index::\n    single: statements\n\nA quirrel program is a simple sequence of statements.::\n\n    stats := stat [';'|'\\n'] stats\n\nStatements in quirrel are comparable to the C-Family languages (C/C++, Java, C#\netc...): assignment, function calls, program flow control structures etc.. plus some\ncustom statement like yield, table and array constructors (All those will be covered in detail\nlater in this document).\nStatements can be separated with a new line or ';' (or with the keywords case or default if\ninside a switch/case statement), both symbols are not required if the statement is\nfollowed by '}'.\n\n------\nBlock\n------\n\n.. index::\n    pair: block; statement\n\n::\n\n    stat := '{' stats '}'\n\nA sequence of statements delimited by curly brackets ({ }) is called block;\na block is a statement itself.\n\n-----------------------\nControl Flow Statements\n-----------------------\n\n.. index::\n    single: control flow statements\n\nquirrel implements the most common control flow statements: ``if, while, do-while, switch-case, for, foreach``\n\n^^^^^^^^^^^^^^\ntrue and false\n^^^^^^^^^^^^^^\n\n.. index::\n    single: true and false\n    single: true\n    single: false\n\nQuirrel has a boolean type (bool) however like C++ it considers null, 0(integer) and 0.0(float)\nas *false*, any other value is considered *true*.\n\n^^^^^^^^^^^^^^^^^\nif/else statement\n^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: if/else; statement\n    pair: if; statement\n    pair: else; statement\n\n::\n\n    stat := 'if' '(' [decl ';'] exp ')' stat ['else' stat]\n\nConditionally execute a statement depending on the result of an expression.\nOptionally, a variable may be declared before the condition using a declaration\nsyntax (`local` or `let`). The declared variable is scoped to the entire\nif-else block (including all `else` and `else if` branches) and is destroyed\nafter the block ends.\n\nExamples::\n\n    if (a > b)\n        a = b\n    else\n        b = a\n\n    if ( a == 10 ) {\n        b = a + b\n        return a\n    }\n\n    if (local cv = iv)\n        println(cv)\n\n    if (let cv: int|null = iv)\n        println(cv)\n    else\n        println(cv - 1)\n\n    if (local cv: int = iv; cv > -1000000)\n        println(cv)\n\n    if (let cv = iv)\n        println(cv)\n    else if (local cv2 = iv)\n        println(\"fail\")\n\n^^^^^^^^^^^^^^^^^\nwhile statement\n^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: while; statement\n\n::\n\n    stat:= 'while' '(' exp ')' stat\n\nExecutes a statement while the condition is true.::\n\n    function testy(n) {\n\n        local a = 0\n        while ( a < n ) a+=1\n\n        while(1) {\n            if ( a < 0 ) break;\n            a -= 1;\n        }\n    }\n\n^^^^^^^^^^^^^^^^^^\ndo/while statement\n^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: do/while; statement\n\n::\n\n    stat:= 'do' stat 'while' '(' expression ')'\n\nExecutes a statement once, and then repeats execution of the statement until a condition\nexpression evaluates to false.::\n\n    local a=0\n    do {\n        println(a)\n        a += 1\n    } while(a>100)\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nswitch statement (deprecated, use ``if``)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. index::\n    pair: switch; statement\n\n::\n\n    stat := 'switch' ''( exp ')' '{'\n    'case' case_exp ':'\n        stats\n    ['default' ':'\n        stats]\n    '}'\n\nSwitch is a control statement allows multiple selections of code by passing control to one of the\ncase statements within its body.\nThe control is transferred to the case label whose case_exp matches with exp if none of\nthe case match will jump to the default label (if present).\nA switch statement can contain any number if case instances, if 2 case have the same\nexpression result the first one will be taken in account first. The default label is only\nallowed once and must be the last one.\nA break statement will jump outside the switch block.\n\n-----\nLoops\n-----\n\n.. index::\n    single: Loops\n\n^^^^^^^^\nfor\n^^^^^^^^\n\n.. index::\n    pair: for; statement\n\n::\n\n    stat:= 'for' '(' [initexp] ';' [condexp] ';' [incexp] ')' statement\n\nExecutes a statement as long as a condition is different than false.::\n\n    for (local a=0;a<10;a+=1)\n        println(a)\n    //or\n    glob <- null\n    for (glob=0;glob<10;glob+=1) {\n        println(glob)\n    }\n    //or\n    for (;;) {\n        println(\"loops forever\")\n    }\n\n^^^^^^^^\nforeach\n^^^^^^^^\n\n.. index::\n    pair: foreach; statement\n\n::\n\n    value_pat   := id | '[' destr_fields ']' | '{' destr_fields '}'\n    'foreach' '(' [index_id','] value_pat 'in' exp ')' stat\n\nExecutes a statement for every element contained in an array, table, class, string or generator.\nIf exp is a generator it will be resumed every iteration as long as it is alive; the value will\nbe the result of 'resume' and the index the sequence number of the iteration starting\nfrom 0.::\n\n    let a=[10,23,33,41,589,56]\n    foreach (idx, val in a)\n        println($\"index={idx} value={val}\")\n    //or\n    foreach (val in a)\n        println ($\"value={val}\")\n\nThe iteration value may also be a destructuring pattern, in which case the\nyielded value is unpacked into the named bindings on each iteration.\nDefault values and type annotations are supported in the same way as for\n:ref:`destructuring assignments <destructuring_assignment>`.::\n\n    foreach ([a, b] in [[1, 2], [3, 4]])\n        println(a, b)\n\n    foreach (i, {x, y} in [{x = 1, y = 2}, {x = 3, y = 4}])\n        println(i, x, y)\n\n    foreach ({n: int = 0} in [{n = 5}, {}])\n        println(n)\n\nSee :ref:`destructuring_assignment` for the full pattern syntax.\n\n-------\nbreak\n-------\n\n.. index::\n    pair: break; statement\n\n::\n\n    stat := 'break'\n\nThe break statement terminates the execution of a loop (for, foreach, while or do/while)\nor jumps out of switch statement;\n\n---------\ncontinue\n---------\n\n.. index::\n    pair: continue; statement\n\n::\n\n    stat := 'continue'\n\nThe continue operator jumps to the next iteration of the loop skipping the execution of\nthe following statements.\n\n---------\nreturn\n---------\n\n.. index::\n    pair: return; statement\n\n::\n\n    stat:= return [exp]\n\nThe return statement terminates the execution of the current function/generator and\noptionally returns the result of an expression. If the expression is omitted the function\nwill return null. If the return statement is used inside a generator, the generator will not\nbe resumable anymore.\n\n---------\nyield\n---------\n\n.. index::\n    pair: yield; statement\n\n::\n\n    stat := yield [exp]\n\n(see :ref:`Generators <generators>`).\n\n\n--------------------------------------\nLocal variables declaration ( local )\n--------------------------------------\n\n.. index::\n    pair: Local variables declaration; statement\n\n::\n\n    initz := id [= exp][',' initz]\n    stat := 'local' initz\n\nLocal variables can be declared at any point in the program; they exist between their\ndeclaration to the end of the block where they have been declared.\n*EXCEPTION:* a local declaration statement is allowed as first expression in a for loop.::\n\n    for (local a=0; a<10; a+=1)\n        print(a)\n\n-----------------------------------\nNamed bindings declaration ( let )\n-----------------------------------\n\n.. index::\n    pair: Named bindings declaration; statement\n\n::\n\n    initz := id = exp[',' initz]\n    stat := 'let' initz\n\nNamed bindings like Local variables can be declared at any point in the program;\nthey exist between their\ndeclaration to the end of the block where they have been declared.\nNamed bindings MUST be initialized.\nNamed bindings works *exactly* as `const` in JavaScript ES6 (Note - big there is siginificant difference with `const` in Squirrel).\nThe main difference between local variables and named bindings is that named bindings can't be reassigned.\nSo if you see somewhere in function scope let foo =  you can be sure that foo will always reference object on initialization\n\n::\n\n  local foo = 2\n  foo = 3\n  print(foo) //3\n\n  let foo = 2\n  foo = 3 //error in script compilation\n\n.. note::\n  While named bindings looks like constants they do not provide immutability. Named bindings can reference mutable objects (like array or instance or table)\n\n  \n\n--------------------\nFunction declaration\n--------------------\n\n.. index::\n    pair: Function declaration; statement\n\n::\n\n    funcname := id ['::' id]\n    stat:= 'function' id + '(' args ')' '{' stat '}'\n\ncreates a new function.\n\n-----------------\nClass declaration\n-----------------\n\n.. index::\n    pair: Class declaration; statement\n\n::\n\n    memberdecl := id '=' exp [';'] |    '[' exp ']' '=' exp [';'] | functionstat | 'constructor' functionexp\n    stat:= 'class' derefexp ['(' derefexp ')'] '{'\n            [memberdecl]\n        '}'\n\ncreates a new class.\n\n-----------\ntry/catch\n-----------\n\n.. index::\n    pair: try/catch; statement\n\n::\n\n    stat:= 'try' stat 'catch' '(' id ')' stat\n\nThe try statement encloses a block of code in which an exceptional condition can occur,\nsuch as a runtime error or a throw statement. The catch clause provides the exception-handling\ncode. When a catch clause catches an exception, its id is bound to that\nexception.\n\n-----------\nthrow\n-----------\n\n.. index::\n    pair: throw; statement\n\n::\n\n    stat:= 'throw' exp\n\nThrows an exception. Any value can be thrown.\n\n--------------\nconst\n--------------\n\n.. index::\n    pair: const; statement\n\n::\n\n    stat:= 'const' id '=' 'Integer | Float | StringLiteral\n\nDeclares a constant (see :ref:`Constants & Enumerations <constants_and_enumerations>`).\n\n--------------\nenum\n--------------\n\n.. index::\n    pair: enum; statement\n\n::\n\n    enumerations := ( 'id' '=' Integer | Float | StringLiteral ) [',']\n    stat:= 'enum' id '{' enumerations '}'\n\nDeclares an enumeration (see :ref:`Constants & Enumerations <constants_and_enumerations>`).\n\n--------------------\nExpression statement\n--------------------\n\n.. index::\n    pair: Expression statement; statement\n\n::\n\n    stat := exp\n\nIn Quirrel every expression is also allowed as statement, if so, the result of the\nexpression is thrown away.\n\n"
  },
  {
    "path": "doc/source/reference/language/string_interpolation.rst",
    "content": ".. _string_interpolation:\n\n\n========================\n$ - String interpolation\n========================\n\n.. index::\n    single: String interpolation\n\n\nThe ``$`` special character identifies a string literal as an interpolated string.\nAn interpolated string is a string literal that might contain interpolation expressions.\nString interpolation provides a more readable and convenient syntax to create formatted strings\nthan a string concatenation or ``subst()`` method.\n\nThe following example uses both features to produce the same output:\n\n::\n\n  local x = 123\n  local y = 567\n  print(\"x = {0}, sin(y) = {1}\".subst(x, math.sin(y)))\n  print($\"x = {x}, sin(y) = {math.sin(y)}\")\n\nInternally string interpolation translates to ``subst()`` call.\n\nNested interpolation strings are not supported.\n\nTo use curly brackets {} inside interpolation string, ``{`` and ``}`` characters should be escaped using ``\\``\n\n::\n\n  local foo = 123\n  print($\"\\{ foo = {foo} \\}\") // will output: { foo = 123 }\n"
  },
  {
    "path": "doc/source/reference/language/tables.rst",
    "content": ".. _tables:\n\n\n=================\nTables\n=================\n\n.. index::\n    single: Tables\n\nTables are associative containers implemented as pairs of key/value (called slot); values\ncan be any possible type and keys any type except 'null'.\nTables are quirrel's skeleton, delegation and many other features are all implemented\nthrough this type; even the environment, where \"global\" variables are stored, is a table\n(known as root table).\n\n------------------\nConstruction\n------------------\n\nTables are created through the table constructor (see :ref:`Table constructor <table_constructor>`)\n\n------------------\nSlot creation\n------------------\n\n.. index::\n    single: Slot Creation(table)\n\nAdding a new slot in a existing table is done through the \"new slot\" operator ``<-``; this\noperator behaves like a normal assignment except that if the slot does not exists it will\nbe created.::\n\n    let a = {}\n\nThe following line will cause an exception because the slot named 'newslot' does not exist\nin the table 'a'::\n\n    a.newslot = 1234\n\nthis will succeed: ::\n\n    a.newslot <- 1234;\n\nor::\n\n    a[1] <- \"I'm the value of the new slot\";\n\n-----------------\nSlot deletion\n-----------------\n\n.. index::\n    single: Slot Deletion(table)\n\n\n::\n\n    exp:= delete derefexp\n\nDeletion of a slot is done through the keyword delete; the result of this expression will be\nthe value of the deleted slot.::\n\n    a <- {\n        test1=1234\n        deleteme=\"now\"\n    }\n\n    delete a.test1\n    print(delete a.deleteme); //this will print the string \"now\"\n\nNote: Usage of this method could be prohibited with ``#forbid-delete-operator``\n"
  },
  {
    "path": "doc/source/reference/language/threads.rst",
    "content": ".. _threads:\n\n\n========================\nThreads\n========================\n\n.. index::\n    single: Threads\n\nQuirrel supports cooperative threads(also known as coroutines).\nA cooperative thread is a subroutine that can suspended in mid-execution and provide a value to the\ncaller without returning program flow, then its execution can be resumed later from the same\npoint where it was suspended.\nAt first look a Quirrel thread can be confused with a generator, in fact their behaviour is quite similar.\nHowever while a generator runs in the caller stack and can suspend only the local routine stack a thread\nhas its own execution stack, global table and error handler; This allows a thread to suspend nested calls and\nhave its own error policies.\n\n------------------\nUsing threads\n------------------\n\n.. index::\n    single: Using Threads\n\nThreads are created through the built-in function 'newthread(func)'; this function\ngets as parameter a quirrel function and bind it to the new thread objects (will be the thread body).\nThe returned thread object is initially in 'idle' state. the thread can be started with the function\n'threadobj.call()'; the parameters passed to 'call' are passed to the thread function.\n\nA thread can be be suspended calling the function suspend(), when this happens the function\nthat wokeup(or started) the thread returns (If a parameter is passed to suspend() it will\nbe the return value of the wakeup function , if no parameter is passed the return value will be null).\nA suspended thread can be resumed calling the function 'threadobj.wakeup', when this happens\nthe function that suspended the thread will return(if a parameter is passed to wakeup it will\nbe the return value of the suspend function, if no parameter is passed the return value will be null).\n\nA thread terminates when its main function returns or when an unhandled exception occurs during its execution.::\n\n    function coroutine_test(a, b) {\n        println($\"{a} {b}\")\n        local ret = suspend(\"suspend 1\")\n        println($\"the coroutine says {ret}\")\n        ret = suspend(\"suspend 2\")\n        println($\"the coroutine says {ret}\")\n        ret = suspend(\"suspend 3\")\n        println($\"the coroutine says {ret}\")\n        return \"I'm done\"\n    }\n\n    local coro = newthread(coroutine_test)\n\n    local susparam = coro.call(\"test\",\"coroutine\") //starts the coroutine\n\n    local i = 1\n    do {\n        println($\"suspend passed {susparam}\")\n        susparam = coro.wakeup(\"ciao \"+i)\n        ++i\n    } while(coro.getstatus()==\"suspended\")\n\n    println($\"return passed {susparam}\")\n\nthe result of this program will be::\n\n    test coroutine\n    suspend passed (suspend 1)\n    the coroutine says ciao 1\n    suspend passed (suspend 2)\n    the coroutine says ciao 2\n    suspend passed (suspend 3)\n    the coroutine says ciao 3\n    return passed (I'm done).\n\n\nthe following is an interesting example of how threads and tail recursion\ncan be combined.::\n\n    function state1() {\n        suspend(\"state1\")\n        return state2() //tail call\n    }\n\n    function state2() {\n        suspend(\"state2\")\n        return state3() //tail call\n    }\n\n    function state3() {\n        suspend(\"state3\")\n        return state1() //tail call\n    }\n\n    local statethread = newthread(state1)\n\n    println(statethread.call())\n\n    for (local i = 0; i < 10000; i++)\n        println(statethread.wakeup())\n\n"
  },
  {
    "path": "doc/source/reference/language/type_annotations.rst",
    "content": "﻿.. _type_annotations:\n\n\nType Annotations in Quirrel\n===========================\n\nQuirrel extends the Squirrel language with optional static type annotations that are enforced at runtime. Type checks occur during function calls, return statements, assignments, and destructuring operations, providing safety without requiring a separate compilation step.\n\nBasic Type Syntax\n-----------------\n\nPrimitive Types\n~~~~~~~~~~~~~~~\n\nQuirrel supports the following built-in types:\n\n- ``int`` - Signed integer\n- ``float`` - Floating-point number\n- ``number`` - Union of ``int | float`` (numeric values)\n- ``bool`` - Boolean values (``true`` / ``false``)\n- ``string`` - Immutable string values\n- ``null`` - Null value type\n\nComplex Types\n~~~~~~~~~~~~~\n\n- ``table`` - Associative array / object\n- ``array`` - Ordered sequence container\n- ``function`` - Callable function or closure\n- ``userdata`` - Opaque C/C++ data reference\n- ``generator`` - Coroutine/generator object\n- ``userpointer`` - Raw pointer value\n- ``thread`` - Execution thread\n- ``instance`` - Class instance\n- ``class`` - Class definition object\n- ``weakref`` - Weak reference to an object\n- ``any`` - Accepts any type (opt-out of type checking)\n\nType Unions\n~~~~~~~~~~~\n\nCombine multiple types using the pipe operator (``|``):\n\n.. code-block:: quirrel\n\n    local value: int|float = 42\n    local maybeString: string|null = null\n    local numeric: number = 3.14  // equivalent to int|float\n\nParentheses may be used for clarity in complex unions:\n\n.. code-block:: quirrel\n\n    local x: (int | null) = null\n    local y: (string | table | null) = {}\n\nFunction Type Annotations\n-------------------------\n\nParameters and Return Types\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAnnotate parameters and return values with type specifiers:\n\n.. code-block:: quirrel\n\n    function add(x: int, y: int): int {\n        return x + y\n    }\n\n    function toString(value: any): string {\n        return value.tostring()\n    }\n\nNullable Parameters with Defaults\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCombine unions with default values for optional parameters:\n\n.. code-block:: quirrel\n\n    function greet(name: string|null = null): string {\n        return name ? \"Hello \" + name : \"Hello guest\"\n    }\n\nVararg Type Annotations\n~~~~~~~~~~~~~~~~~~~~~~~\n\nSpecify the expected type for variable arguments using ``...``:\n\n.. code-block:: quirrel\n\n    function sum(first: number, ...: number): number {\n        local total = first\n        foreach (v in vargv) total += v\n        return total\n    }\n\nLambda/Anonymous Functions\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nType annotations apply to lambdas using the ``@`` syntax:\n\n.. code-block:: quirrel\n\n    let multiply = @(x: int, y: int): int x * y\n\nVariable Type Annotations\n-------------------------\n\nLocal and Let Bindings\n~~~~~~~~~~~~~~~~~~~~~~\n\nAnnotate variables at declaration site:\n\n.. code-block:: quirrel\n\n    local count: int = 0\n    let pi: float = 3.14159\n    local config: table|array = {timeout = 30}\n\nType checks occur on assignment:\n\n.. code-block:: quirrel\n\n    local id: int = \"not a number\"  // Runtime type error\n\nDestructuring with Types\n------------------------\n\nObject Destructuring\n~~~~~~~~~~~~~~~~~~~~\n\nAnnotate individual properties during destructuring:\n\n.. code-block:: quirrel\n\n    local { name: string, age: int|null = 25 } = userData\n\n    // With explicit type unions\n    local { x: int, y: string|int|null } = point\n\nArray Destructuring\n~~~~~~~~~~~~~~~~~~~\n\nSpecify types for array elements:\n\n.. code-block:: quirrel\n\n    local [first: int, second: string] = [42, \"hello\"]\n\n    // Mixed annotated/unannotated elements\n    local [head: int, value1, value2] = [1, 2, 3]\n\n    // Complex unions in arrays\n    local [value: (int | null), flag: bool] = [null, true]\n\nNested Destructuring in Parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFunctions can destructure parameters with full type annotations:\n\n.. code-block:: quirrel\n\n    function createUser([name: string, age: int], {active: bool = true}) {\n        // ...\n    }\n\n    function process(\n        [handler: function|null = null, config: table],\n        {timeout: int|float = 5.0},\n        ...\n    ) {\n        // ...\n    }\n\nRuntime Type Checking Behavior\n------------------------------\n\nQuirrel performs **dynamic type validation** at these points:\n\n1. **Function calls** - Parameters are checked against declared types before execution\n2. **Return statements** - Return values are validated against the function's return type\n3. **Assignments** - Values are checked when assigned to typed variables\n4. **Destructuring** - Extracted values are validated against property/element types\n\nAll checks occur at runtime with immediate exceptions on mismatch:\n\n.. code-block:: quirrel\n\n    function strict(x: int): int { return x }\n\n    strict(\"wrong\")  // Throws: type mismatch in parameter 'x'\n\n\nBest Practices\n--------------\n\n- Type checks add minor runtime overhead; avoid in ultra-hot loops if unneeded\n- Use ``number`` instead of ``int|float`` for numeric parameters accepting both types\n- Use ``any`` sparingly—only when truly necessary for dynamic behavior\n- Combine defaults with nullable types for ergonomic optional parameters:\n\n  .. code-block:: quirrel\n\n      function fetch(url: string, timeout: float|null = 30.0) { ... }\n"
  },
  {
    "path": "doc/source/reference/language/weak_references.rst",
    "content": ".. _weak_references:\n\n\n========================\nWeak References\n========================\n\n.. index::\n    single: Weak References\n\n\nThe weak references allows the programmers to create references to objects without\ninfluencing the lifetime of the object itself.\nIn quirrel Weak references are first-class objects created through the built-in method obj.weakref().\nAll types except null implement the weakref() method; however in bools, integers, and floats the method\nsimply returns the object itself(this because this types are always passed by value).\nWhen a weak references is assigned to a container (table slot,array,class or\ninstance) is treated differently than other objects; When a container slot that hold a weak\nreference is fetched, it always returns the value pointed by the weak reference instead of the weak\nreference object. This allow the programmer to ignore the fact that the value handled is weak.\nWhen the object pointed by weak reference is destroyed, the weak reference is automatically set to null.\n\n::\n\n    let t = {}\n    let a = [\"first\",\"second\",\"third\"]\n    //creates a weakref to the array and assigns it to a table slot\n    t.thearray <- a.weakref()\n\nThe table slot 'thearray' contains a weak reference to an array.\nThe following line prints \"first\", because tables(and all other containers) always return\nthe object pointed by a weak ref\n\n::\n\n    print(t.thearray[0])\n\nthe only strong reference to the array is owned by the local variable 'a', so\nbecause the following line assigns a integer to 'a' the array is destroyed.\n\n::\n\n    a = 123\n\nWhen an object pointed by a weak ref is destroyed the weak ref is automatically set to null,\nso the following line will print \"null\".\n\n::\n\n    print(typeof(t.thearray))\n\n-----------------------------------\nHandling weak references explicitly\n-----------------------------------\n\nIf a weak reference is assigned to a local variable, then is treated as any other value.\n\n::\n\n    let t = {}\n    let weakobj = t.weakref()\n\nthe following line prints \"weakref\".\n\n::\n\n    print(typeof(weakobj))\n\nthe object pointed by the weakref can be obtained through the built-in method weakref.ref().\n\nThe following line prints \"table\".\n\n::\n\n    print(typeof(weakobj.ref()))\n"
  },
  {
    "path": "doc/source/reference/language.rst",
    "content": ".. _thelanguage:\n\n***************************\n  The language\n***************************\nProject source code is available at https://github.com/GaijinEntertainment/quirrel\n\n.. toctree::\n   language/lexical_structure.rst\n   language/datatypes.rst\n   language/statements.rst\n   language/expressions.rst\n   language/tables.rst\n   language/arrays.rst\n   language/functions.rst\n   language/classes.rst\n   language/generators.rst\n   language/constants_and_enumerations.rst\n   language/destructuring_assignment.rst\n   language/type_annotations.rst\n   language/string_interpolation.rst\n   language/threads.rst\n   language/weak_references.rst\n   language/metamethods.rst\n   language/builtin_functions.rst\n   language/compiler_directives.rst\n   language/limitations.rst\n"
  },
  {
    "path": "doc/source/repl/index.rst",
    "content": ".. _repl:\n\n######################################\n  Try Quirrel online\n######################################\n\n.. raw:: html\n\n  <script>\n    function loadCss(url) {\n      var link = document.createElement(\"link\")\n      link.type = \"text/css\"\n      link.rel = \"stylesheet\"\n      link.href = url\n      document.getElementsByTagName(\"head\")[0].appendChild(link)\n    }\n    loadCss(\"../_static/repl-rst.css\")\n  </script>\n\n  <div id=\"repl-root\">\n    <div class=\"editor-container container-source\">\n      <div class=\"editor-header\">\n        <span>Source code</span>\n        <button id=\"btn-run\">Run (Ctrl+Enter)</button>\n      </div>\n      <pre id=\"source-editor\" class=\"editor-area\"></pre>\n    </div>\n    <div class=\"editor-container container-output\">\n      <div class=\"editor-header\">\n        <span>Result</span>\n      </div>\n      <pre id=\"output\" class=\"output\"></pre>\n    </div>\n  </div>\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.14/ace.js\"></script>\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js\"></script>\n\n  <script>\n    // Setup editor\n    const sourceEditor = ace.edit(\"source-editor\", {minLines:32, maxLines:32})\n    sourceEditor.setShowPrintMargin(false)\n    sourceEditor.setValue(localStorage.getItem('sourceCode') || 'println(\"Hello, Quirrel!\")')\n    sourceEditor.moveCursorTo(0, 0)\n\n\n    function execute() {\n      const sourceCode = sourceEditor.getValue()\n      localStorage.setItem('sourceCode', sourceCode)\n      const result = Module.runScript(sourceCode)\n      $('#output').text(result)\n    }\n\n    $('#btn-run').on('click', execute)\n\n    document.addEventListener('keyup', (e)=>{\n      if (e.key === \"Enter\" && e.ctrlKey) {\n        execute()\n        e.preventDefault()\n      }\n    }, false)\n\n    // Show page\n    $('#repl-root').css({'display': 'block'})\n\n    // WebAssembly\n    var Module = {\n      onRuntimeInitialized: function() {\n        // Initialize here\n      }\n    }\n\n  </script>\n\n  <script src=\"../_static/sqjsrepl.js\"></script>\n\n\nProject source code is available at https://github.com/GaijinEntertainment/quirrel\n\nCopyright (c) 2003-2016 Alberto Demichelis\nCopyright (c) 2016-2024 Gaijin Games KFT\n"
  },
  {
    "path": "doc/source/rfcs/README.md",
    "content": "# RFC process\n\n## Background\n\nWhenever Quirrel language changes its syntax or semantics (including behavior of builtin libraries), we need to consider many implications of the changes.\n\nWhenever new syntax is introduced, we need to ask:\n\n- Is it backwards compatible?\n- Is it easy for machines and humans to parse?\n- Does it follow 'Zen of Quirrel' (based on Zen of Python?)\n- Does it create grammar ambiguities for current and future syntax?\n- Is it stylistically coherent with the rest of the language?\n- Does it present challenges with editor integration like autocomplete?\n- Will it affect performance?\n\nFor changes in semantics, we should be asking:\n\n- Is behavior easy to understand and non-surprising?\n- Can it be implemented performantly today?\n- Is it compatible with type checking and other forms of static analysis?\n\nFor new standard library functions, we should be asking:\n\n- Is the new functionality used/useful often enough in existing code?\n- Does the standard library implementation carry important performance benefits that can't be achieved in user code?\n- Is the behavior general and unambiguous, as opposed to solving a problem / providing an interface that's too specific?\n- Is the function interface amenable to type checking / linting?\n\nIn addition to these questions, we also need to consider that every addition carries a cost, and too many features will result in a language that is harder to learn, harder to implement and ensure consistent implementation quality throughout, slower, etc. In addition, any language is greater than the sum of its parts and features often have non-intuitive interactions with each other.\n\nSince reversing these decisions is incredibly costly and can be impossible due to backwards compatibility implications, all user facing changes to Quirrel language and core libraries must go through an RFC process.\n\n## Process\n\nThere is no any special process for RFC review at the moment.\n\n## Implementation\n\nWhen an RFC gets merged, the feature *can* be implemented; however, there's no set timeline for that implementation. In some cases implementation may land in a matter of days after an RFC is merged, in some it may take months.\n\nTo avoid having permanently stale RFCs, in rare cases Quirrel team can *remove* a previously merged RFC when the landscape is believed to change enough for a feature like this to warrant further discussion.\n\nWhen an RFC is implemented and the implementation is enabled via feature flags, RFC should be updated to include \"**Status**: Implemented\" at the top level (before *Summary* section).\n"
  },
  {
    "path": "doc/source/rfcs/STATUS.md",
    "content": "﻿# RFCs\n\nThis document tracks RFCs, both implemented and not implemented (implemented RFC should eventually go way from here).\n\n\n## Deprecate clone operator and replace it with .clone method\n\n**Status**: Implemented, as optional behavior currently. Can be specified by #forbid-clone-operator or #allow-clone-operator\n\n\n## assignments in 'if' (let and local)\n\n**Status**: Implemented\n\n\n## Replace let with const\n\nReplace 'let' for immutables with 'const' keyword\nor make them aliases.\n\n`const` and `let` for simple types works the same from coder PoV.\n`let` and `const` declarations for simple types (integer, float, string, null, boolean) can be optimized (we do know in compile time what is it).\nFor other types const should work as 'binding' (like `let` do now).\n\n**Status**: Waiting for implementation\n\n\n## Add .hasindex(<index>) for instances, classes, tables, arrays and strings.\n\nShould behave as 'in' operator, but exists only for types that can have 'index', and should have correct check of arguments type\n(arrays and strings can have only integer as index)\n\n**Status**: Waiting for implementation\n\n## Add .hasvalue(<value>) for tables and arrays.\n\nThe same as 'contains' for arrays. To make it more consistent with findvalue() and findindex() and hasindex()\n\n**Status**: Waiting for implementation\n\n\n## Add for and foreach in ranges\n\nSyntax like:\n  ```\n  for (range:integer)\n  for (start_of_range:integer, end_of_range:integer)\n  foreach (i in range:integer)\n  ```\n\nWill allow to make code faster and safer than with for(local i=0; i<range; i++)\n\n**Status**: Needs implementation\n\n\n## Return back _inherited and _newmember metamethods for classes, or implement some other way to validate children classes\n\n**Status**: Not going to be implemented. _lock method is much more powerful and useful.\n\n## Keyworded arguments for function calls, like Python\n\n  `function foo(a=1, b=2){}`\n  `foo(b=3) //the same as foo(1, 3), but much safer`\n\nShould work almost the same as kwarg() function from functools.nut do or how python allow function calls.\nAs quirrel function has in it's infos information about default arguments, it can be called.\n\n**Status**: Needs implementation and detailed rfc\n\n\n## Forward declaration for bindings\n\n```\n  local a\n  function b(){\n    a()\n  }\n  a = function(){}\n  let a\n```\n\nThe idea is to be able convert local variable into binding, make it safer to use, but still allow to have forward declarations\n\n**Status**: Needs implementation and detailed rfc\n\n\n## Destructors in classes\n\nSpecial functions that would be called just before garbage collections, like __del__ in Python\n\n```\n  let cache = {}\n\n  let class = Foo {\n    constuctor(){\n      cache[this] <- true\n    }\n    destructor(){\n      cache.$delete(this)\n    }\n  }\n```\n\n**Status**: Needs implementation and detailed rfc\n\n\n## delete operator for bindings and locals, or unbind global function\n\nClear namespace, like 'del' operator in Python\n\n  function(){\n    let a = heavy_function()\n    if (a) {\n     let {field} = a\n     del a // (or unbind(a)) will clear namespace from 'a'\n     let a = do_something_heavy(field)\n   }\n  }\n\n**Status**: Needs implementation and detailed rfc\n\n\n## Keyworded optional arguments for function calls, like Python\n\n  function bar(***){\n    foreach(k, v in kvargs)\n      println($\"{k}={v}\")\n  }\n\n  bar(a=1, b=2, c=3)\n\n**Status**: Needs implementation and detailed rfc\n\n\n## Remove :: operator\n\nUse getroottable() or write your own wrapper for shorter syntax\n\n**Status**: Needs implementation and detailed rfc\n\n## NaN-tagging\n\n**Status**: Needs implementation and detailed rfc\n\n## Incremental GC\n\n**Status**: Needs implementation and detailed rfc\n\n## Expression folding\n\n**Status**: Needs implementation and detailed rfc\n\n## Insert-ordered tables (like in Python)\n\n**Status**: Needs implementation and detailed rfc\n\n## Spread operator\n\nlike https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax\n\n**Status**: Needs implementation and detailed rfc\n\n## AST optimizations\n\n- loop unrolling\n- filter + map folding, dead-code elimation\n- Hoisting immutable variables\n\n**Status**: Needs detailed rfc\n"
  },
  {
    "path": "doc/source/stdlib/index.rst",
    "content": ".. _stdlib:\n\n######################################\n  Quirrel |version| Standard Library\n######################################\n\nProject source code is available at https://github.com/GaijinEntertainment/quirrel\n\nCopyright (c) 2003-2016 Alberto Demichelis\nCopyright (c) 2016-2025 Gaijin Games KFT\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n\n.. toctree::\n   :maxdepth: 1\n   :numbered:\n\n   introduction.rst\n   stdiolib.rst\n   stdiostreamlib.rst\n   stdmathlib.rst\n   stdsystemlib.rst\n   stddatetimelib.rst\n   stdstringlib.rst\n   stdauxlib.rst\n   stddebuglib.rst\n\n"
  },
  {
    "path": "doc/source/stdlib/introduction.rst",
    "content": ".. _stdlib_introduction:\n\n============\nIntroduction\n============\n\nThe squirrel standard libraries consist in a set of modules implemented in C++.\nWhile are not essential for the language, they provide a set of useful services that are\ncommonly used by a wide range of applications(file I/O, regular expressions, etc...),\nplus they offer a foundation for developing additional libraries.\n\nAll libraries are implemented through the squirrel API and the ANSI C runtime library.\nThe modules are organized in the following way:\n\n* I/O : input and output\n* IOstream : binary buffers manipilation\n* math : basic mathematical routines\n* system : system access function\n* string : string formatting and manipulation\n* aux : auxiliary functions\n\nThe libraries can be registered independently,except for the IO library that depends from the iostreamlib.\n"
  },
  {
    "path": "doc/source/stdlib/stdauxlib.rst",
    "content": ".. _stdlib_stdauxlib:\n\n===============\nThe Aux library\n===============\n\nThe aux library implements default handlers for compiler and runtime errors and a stack dumping.\n\n+++++++++++\nC API\n+++++++++++\n\n.. _sqstd_seterrorhandlers:\n\n.. c:function:: void sqstd_seterrorhandlers(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\n    initialize compiler and runtime error handlers, the handlers\n    use the print function set through(:ref:`sq_setprintfunc <sq_setprintfunc>`) to output\n    the error.\n\n.. _sqstd_printcallstack:\n\n.. c:function:: void sqstd_printcallstack(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\n    prints the call stack and stack contents. the function\n    uses the error printing function set through(:ref:`sq_setprintfunc <sq_setprintfunc>`) to output\n    the stack dump.\n\n.. _sqstd_formatcallstackstring:\n\n.. c:function:: void sqstd_formatcallstackstring(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n\n    Prints the call stack and stack contents to the string and pushes resulting string\n    to the stack. Produces the same output as (:ref:`sqstd_printcallstack <sqstd_printcallstack>`)\n    but without using print function.\n"
  },
  {
    "path": "doc/source/stdlib/stddatetimelib.rst",
    "content": ".. _stdlib_stddatetimelib:\n\n====================\nThe Datetime library\n====================\n\nThe datetime library date and time manipulation facilities\n\n--------------\nQuirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n.. sq:function:: clock()\n\n    returns a float representing the number of seconds elapsed since the start of the process\n\n.. sq:function:: date([time [, format]])\n\n    returns a table containing a date/time split into the slots:\n\n+-------------+----------------------------------------+\n| sec         | Seconds after minute (0 - 59).         |\n+-------------+----------------------------------------+\n| min         | Minutes after hour (0 - 59).           |\n+-------------+----------------------------------------+\n| hour        | Hours since midnight (0 - 23).         |\n+-------------+----------------------------------------+\n| day         | Day of month (1 - 31).                 |\n+-------------+----------------------------------------+\n| month       | Month (0 - 11; January = 0).           |\n+-------------+----------------------------------------+\n| year        | Year (current year).                   |\n+-------------+----------------------------------------+\n| wday        | Day of week (0 - 6; Sunday = 0).       |\n+-------------+----------------------------------------+\n| yday        | Day of year (0 - 365; January 1 = 0).  |\n+-------------+----------------------------------------+\n\nif `time` is omitted the current time is used.\n\nif `format` can be 'l' local time or 'u' UTC time, if omitted is defaulted as 'l'(local time).\n\n.. sq:function:: time()\n\n    returns the number of seconds elapsed since midnight 00:00:00, January 1, 1970.\n\n    the result of this function can be formatted through the function `date()`\n\n--------------\nC API\n--------------\n\n.. _sqstd_register_datetimelib:\n\n.. c:function:: SQRESULT sqstd_register_datetimelib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function expects a table on top of the stack where to register the global library functions.\n\n    initialize and register the datetime library in the given VM.\n"
  },
  {
    "path": "doc/source/stdlib/stddebuglib.rst",
    "content": ".. _stdlib_stddebuglib:\n\n========================\nThe Debug library\n========================\n\nthe library implements some basic debug routines.\n\n--------------\nQuirrel API\n--------------\n\n\n.. sq:function:: getbuildinfo(x)\n\nreturns table containing information on VM build parameters.\n\n  * **version** - string values describing the version of VM and compiler.\n  * **charsize** - size in bytes of the internal VM representation for characters(1 for ASCII builds 2 for UNICODE builds).\n  * **intsize** - size in bytes of the internal VM representation for integers(4 for 32bits builds 8 for 64bits builds).\n  * **floatsize** - size in bytes of the internal VM representation for floats(4 for single precision builds 8 for double precision builds).\n\n\n.. sq:function:: seterrorhandler(func)\n\nsets the runtime error handler\n\n\n.. sq:function:: setdebughook(hook_func)\n\nsets the debug hook\n\nhook_func should have follow signature: ::\n\n   hook_func(hook_type:integer, source_file:string, line_num:integer, func_name:string)\n\nhook_type can be 'l' - line, 'r' - return, 'c' - call or 'x' for VM shutdown\n\ncall of debughook for each line performed only when debuginfo is enabled\n\n\n.. sq:function:: getstackinfos(level)\n\nreturns the stack informations of a given call stack level. returns a table formatted as follow: ::\n\n    {\n        func=\"DoStuff\", //function name\n        src=\"test.nut\", //source file\n        line=10,        //line number\n        locals = {      //a table containing the local variables\n            a=10,\n            testy=\"I'm a string\"\n        }\n    }\n\nlevel = 0 is getstackinfos() itself! level = 1 is the current function, level = 2 is the caller of the current function, and so on.\nIf the stack level doesn't exist the function returns null.\n\n.. sq:function:: format_call_stack_string()\n\nCollects the call stack and returns the information about functions being executed and local variables as a string.\n\n.. sq:function:: getlocals([level=1], [include_internal=false])\n\nReturns a table containing the local variables of a given call stack level.\n(level = 1 is the current function, level = 2 is the caller of the current function, and so on).\nIf the stack level doesn't exist the function returns null.\nIf include_internal is true, the table will also contain the internal variables (``foreach`` iterators, ``this`` and ``vargv``).\nVery similar to ``getstackinfos()``, added for convenience.\n\n\n.. sq:function:: collectgarbage()\n\n    Runs the garbage collector and returns the number of reference cycles found (and deleted). This function only works on garbage collector builds.\n\n\n.. sq:function:: resurrectunreachable()\n\nRuns the garbage collector and returns an array containing all unreachable object found. If no unreachable object is found, null is returned instead. This function is meant to help debugging reference cycles. This function only works on garbage collector builds.\n\n"
  },
  {
    "path": "doc/source/stdlib/stdiolib.rst",
    "content": ".. _stdlib_stdiolib:\n\n========================\nThe Input/Output library\n========================\n\nthe i/o library implements basic input/output routines.\n\n--------------\nQuirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n\n.. sq:data:: stderr\n\n    File object bound on the os *standard error* stream\n\n.. sq:data:: stdin\n\n    File object bound on the os *standard input* stream\n\n.. sq:data:: stdout\n\n    File object bound on the os *standard output* stream\n\n\n++++++++++++++\nThe file class\n++++++++++++++\n\n    The file object implements a stream on a operating system file.\n\n.. sq:class:: file(path, patten)\n\n    It's constructor imitates the behaviour of the C runtime function fopen for eg. ::\n\n        local myfile = file(\"test.xxx\",\"wb+\");\n\n    creates a file with read/write access in the current directory.\n\n.. sq:function:: file.close()\n\n    closes the file.\n\n.. sq:function:: file.eos()\n\n    returns a non null value if the read/write pointer is at the end of the stream.\n\n.. sq:function:: file.flush()\n\n    flushes the stream.return a value != null if succeeded, otherwise returns null\n\n.. sq:function:: file.len()\n\n    returns the length of the stream\n\n.. sq:function:: file.readblob(size)\n\n    :param int size: number of bytes to read\n\n    read n bytes from the stream and returns them as blob\n\n.. sq:function:: file.readn(type)\n\n    :param int type: type of the number to read\n\n    reads a number from the stream according to the type parameter.\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| parameter    | return description                                                             |  return type         |\n+==============+================================================================================+======================+\n| 'l'          | processor dependent, 32bits on 32bits processors, 64bits on 64bits processors  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'i'          | 32bits number                                                                  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 's'          | 16bits signed integer                                                          |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'w'          | 16bits unsigned integer                                                        |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'c'          | 8bits signed integer                                                           |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'b'          | 8bits unsigned integer                                                         |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'f'          | 32bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'd'          | 64bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n\n.. sq:function:: file.resize(size)\n\n    :param int size: the new size of the blob in bytes\n\n    resizes the blob to the specified `size`\n\n.. sq:function:: file.seek(offset [,origin])\n\n    :param int offset: indicates the number of bytes from `origin`.\n    :param int origin: origin of the seek\n\n                        +--------------+-------------------------------------------+\n                        |  'b'         |  beginning of the stream                  |\n                        +--------------+-------------------------------------------+\n                        |  'c'         |  current location                         |\n                        +--------------+-------------------------------------------+\n                        |  'e'         |  end of the stream                        |\n                        +--------------+-------------------------------------------+\n\n    Moves the read/write pointer to a specified location.\n\n.. note:: If origin is omitted the parameter is defaulted as 'b'(beginning of the stream).\n\n.. sq:function:: file.tell()\n\n    returns the read/write pointer absolute position\n\n.. sq:function:: file.writeblob(src)\n\n    :param blob src: the source blob containing the data to be written\n\n    writes a blob in the stream\n\n.. sq:function:: file.writen(n, type)\n\n    :param number n: the value to be written\n    :param int type: type of the number to write\n\n    writes a number in the stream formatted according to the `type` pamraeter\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+\n| parameter    | return description                                                             |\n+==============+================================================================================+\n| 'i'          | 32bits number                                                                  |\n+--------------+--------------------------------------------------------------------------------+\n| 's'          | 16bits signed integer                                                          |\n+--------------+--------------------------------------------------------------------------------+\n| 'w'          | 16bits unsigned integer                                                        |\n+--------------+--------------------------------------------------------------------------------+\n| 'c'          | 8bits signed integer                                                           |\n+--------------+--------------------------------------------------------------------------------+\n| 'b'          | 8bits unsigned integer                                                         |\n+--------------+--------------------------------------------------------------------------------+\n| 'f'          | 32bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n| 'd'          | 64bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n\n\n--------------\nC API\n--------------\n\n.. _sqstd_register_iolib:\n\n.. c:function:: SQRESULT sqstd_register_iolib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initialize and register the io library in the given VM.\n\n++++++++++++++\nFile Object\n++++++++++++++\n\n.. c:function:: SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file, SQBool owns)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQFILE file: the stream that will be rapresented by the file object\n    :param SQBool owns: if different true the stream will be automatically closed when the newly create file object is destroyed.\n    :returns: an SQRESULT\n\n    creates a file object bound to the SQFILE passed as parameter\n    and pushes it in the stack\n\n.. c:function:: SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE* file)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: and index in the stack\n    :param SQFILE* file: A pointer to a SQFILE handle that will store the result\n    :returns: an SQRESULT\n\n    retrieve the pointer of a stream handle from an arbitrary\n    position in the stack.\n\n++++++++++++++++++++++++++++++++\nScript loading and serialization\n++++++++++++++++++++++++++++++++\n\n.. c:function:: SQRESULT sqstd_loadfile(HSQUIRRELVM v, const char* filename, SQBool printerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param char* filename: path of the script that has to be loaded\n    :param SQBool printerror: if true the compiler error handler will be called if a error occurs\n    :returns: an SQRESULT\n\n    Compiles a squirrel script or loads a precompiled one an pushes it as closure in the stack.\n    When squirrel is compiled in Unicode mode the function can handle different character encodings,\n    UTF8 with and without prefix and UCS-2 prefixed(both big endian an little endian).\n    If the source stream is not prefixed UTF8 encoding is used as default.\n\n.. c:function:: SQRESULT sqstd_dofile(HSQUIRRELVM v, const char* filename, SQBool retval, SQBool printerror)\n\n    :param HSQUIRRELVM v: the target VM\n    :param char* filename: path of the script that has to be loaded\n    :param SQBool retval: if true the function will push the return value of the executed script in the stack.\n    :param SQBool printerror: if true the compiler error handler will be called if a error occurs\n    :returns: an SQRESULT\n    :remarks: the function expects a table on top of the stack that will be used as 'this' for the execution of the script. The 'this' parameter is left untouched in the stack.\n\n    Compiles a squirrel script or loads a precompiled one and executes it.\n    Optionally pushes the return value of the executed script in the stack.\n    When squirrel is compiled in unicode mode the function can handle different character encodings,\n    UTF8 with and without prefix and UCS-2 prefixed(both big endian an little endian).\n    If the source stream is not prefixed, UTF8 encoding is used as default. ::\n\n        sq_pushroottable(v); //push the root table(were the globals of the script will are stored)\n        sqstd_dofile(v, \"test.nut\", SQFalse, SQTrue);// also prints syntax errors if any\n\n.. c:function:: SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v, const char* filename)\n\n    :param HSQUIRRELVM v: the target VM\n    :param char* filename: destination path of serialized closure\n    :returns: an SQRESULT\n\n    serializes the closure at the top position in the stack as bytecode in\n    the file specified by the parameter filename. If a file with the\n    same name already exists, it will be overwritten.\n\n"
  },
  {
    "path": "doc/source/stdlib/stdiostreamlib.rst",
    "content": ".. _stdlib_stdbloblib:\n\n====================\nThe IOstream library\n====================\nThe iostream library implements binary data manipulations routines. The library is\nbased on `blob objects` that represent a buffer of arbitrary\nbinary data.\n\n---------------\nQuirrel API\n---------------\n\n+++++++++++++++\nGlobal symbols\n+++++++++++++++\n\n.. sq:function:: castf2i(f)\n\n    casts a float to a int\n\n.. sq:function:: casti2f(n)\n\n    casts a int to a float\n\n.. sq:function:: swap2(n)\n\n    swap the byte order of a number (like it would be a 16bits integer)\n\n.. sq:function:: swap4(n)\n\n    swap the byte order of an integer\n\n.. sq:function:: swapfloat(n)\n\n    swaps the byteorder of a float\n\n++++++++++++++++++\nThe blob class\n++++++++++++++++++\n\nThe blob object is a buffer of arbitrary binary data. The object behaves like\na file stream, it has a read/write pointer and it automatically grows if data\nis written out of his boundary.\nA blob can also be accessed byte by byte through the `[]` operator.\n\n.. sq:class:: blob(size)\n\n    :param int size: initial size of the blob\n\n    returns a new instance of a blob class of the specified size in bytes\n\n.. sq:function:: blob.eos()\n\n    returns a non null value if the read/write pointer is at the end of the stream.\n\n.. sq:function:: blob.flush()\n\n    flushes the stream.return a value != null if succeded, otherwise returns null\n\n.. sq:function:: blob.len()\n\n    returns the length of the stream\n\n.. sq:function:: blob.readblob(size)\n\n    :param int size: number of bytes to read\n\n    read n bytes from the stream and returns them as blob\n\n.. sq:function:: blob.readn(type)\n\n    :param int type: type of the number to read\n\n    reads a number from the stream according to the type parameter.\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| parameter    | return description                                                             |  return type         |\n+==============+================================================================================+======================+\n| 'l'          | processor dependent, 32bits on 32bits processors, 64bits on 64bits processors  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'i'          | 32bits number                                                                  |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 's'          | 16bits signed integer                                                          |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'w'          | 16bits unsigned integer                                                        |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'c'          | 8bits signed integer                                                           |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'b'          | 8bits unsigned integer                                                         |  integer             |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'f'          | 32bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n| 'd'          | 64bits float                                                                   |  float               |\n+--------------+--------------------------------------------------------------------------------+----------------------+\n\n.. sq:function:: blob.resize(size)\n\n    :param int size: the new size of the blob in bytes\n\n    resizes the blob to the specified `size`\n\n.. sq:function:: blob.seek(offset [,origin])\n\n    :param int offset: indicates the number of bytes from `origin`.\n    :param int origin: origin of the seek\n\n                        +--------------+-------------------------------------------+\n                        |  'b'         |  beginning of the stream                  |\n                        +--------------+-------------------------------------------+\n                        |  'c'         |  current location                         |\n                        +--------------+-------------------------------------------+\n                        |  'e'         |  end of the stream                        |\n                        +--------------+-------------------------------------------+\n\n    Moves the read/write pointer to a specified location.\n\n.. note:: If origin is omitted the parameter is defaulted as 'b'(beginning of the stream).\n\n.. sq:function:: blob.swap2()\n\n    swaps the byte order of the blob content as it would be an array of `16bits integers`\n\n.. sq:function:: blob.swap4()\n\n    swaps the byte order of the blob content as it would be an array of `32bits integers`\n\n.. sq:function:: blob.tell()\n\n    returns the read/write pointer absolute position\n\n.. sq:function:: blob.as_string()\n\n    creates string from blob\n\n.. sq:function:: blob.writeblob(src)\n\n    :param blob src: the source blob containing the data to be written\n\n    writes a blob in the stream\n\n.. sq:function:: blob.writestring(text)\n\n    :param string text: the source string containing the data to be written\n\n    writes a string in the stream\n\n.. sq:function:: blob.readobject()\n\n    deserialize an object from the stream\n\n.. sq:function:: blob.writeobject(obj)\n\n    :param obj object: the source object containing the data to be written\n\n    serialize an object in the stream\n\n.. sq:function:: blob.writen(n, type)\n\n    :param number n: the value to be written\n    :param int type: type of the number to write\n\n    writes a number in the stream formatted according to the `type` parameter\n\n    `type` can have the following values:\n\n+--------------+--------------------------------------------------------------------------------+\n| parameter    | return description                                                             |\n+==============+================================================================================+\n| 'i'          | 32bits number                                                                  |\n+--------------+--------------------------------------------------------------------------------+\n| 's'          | 16bits signed integer                                                          |\n+--------------+--------------------------------------------------------------------------------+\n| 'w'          | 16bits unsigned integer                                                        |\n+--------------+--------------------------------------------------------------------------------+\n| 'c'          | 8bits signed integer                                                           |\n+--------------+--------------------------------------------------------------------------------+\n| 'b'          | 8bits unsigned integer                                                         |\n+--------------+--------------------------------------------------------------------------------+\n| 'f'          | 32bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n| 'd'          | 64bits float                                                                   |\n+--------------+--------------------------------------------------------------------------------+\n\n\n------\nC API\n------\n\n.. _sqstd_register_bloblib:\n\n.. c:function:: SQRESULT sqstd_register_bloblib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function expects a table on top of the stack where to register the global library functions.\n\n    initializes and registers the blob library in the given VM.\n\n.. _sqstd_getblob:\n\n.. c:function:: SQRESULT sqstd_getblob(HSQUIRRELVM v, SQInteger idx, SQUserPointer* ptr)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: and index in the stack\n    :param SQUserPointer* ptr: A pointer to the userpointer that will point to the blob's payload\n    :returns: an SQRESULT\n\n    retrieve the pointer of a blob's payload from an arbitrary\n    position in the stack.\n\n.. _sqstd_getblobsize:\n\n.. c:function:: SQInteger sqstd_getblobsize(HSQUIRRELVM v, SQInteger idx)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger idx: and index in the stack\n    :returns: the size of the blob at `idx` position\n\n    retrieves the size of a blob's payload from an arbitrary\n    position in the stack.\n\n.. _sqstd_createblob:\n\n.. c:function:: SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger size:  the size of the blob payload that has to be created\n    :returns: a pointer to the newly created blob payload\n\n    creates a blob with the given payload size and pushes it in the stack.\n"
  },
  {
    "path": "doc/source/stdlib/stdmathlib.rst",
    "content": ".. _stdlib_stdmathlib:\n\n================\nThe Math library\n================\n\nthe math lib provides basic mathematic routines. The library mimics the\nC runtime library implementation.\n\n------------\nQuirrel API\n------------\n\n+++++++++++++++\nGlobal Symbols\n+++++++++++++++\n\n.. sq:function:: abs(x)\n\n    returns the absolute value of `x` as an integer\n\n.. sq:function:: acos(x)\n\n    returns the arccosine of `x`\n\n.. sq:function:: asin(x)\n\n    returns the arcsine of `x`\n\n.. sq:function:: atan(x)\n\n    returns the arctangent of `x`\n\n.. sq:function:: atan2(x,y)\n\n    returns the arctangent of  `x/y`\n\n.. sq:function:: ceil(x)\n\n    returns a float value representing the smallest integer that is greater than or equal to `x`\n\n.. sq:function:: cos(x)\n\n    returns the cosine of `x`\n\n.. sq:function:: exp(x)\n\n    returns the exponential value of the float parameter `x`\n\n.. sq:function:: fabs(x)\n\n    returns the absolute value of `x` as a float\n\n.. sq:function:: floor(x)\n\n    returns a float value representing the largest integer that is less than or equal to `x`\n\n.. sq:function:: log(x)\n\n    returns the natural logarithm of `x`\n\n.. sq:function:: log10(x)\n\n    returns the logarithm base-10 of `x`\n\n.. sq:function:: pow(x,y)\n\n    returns `x` raised to the power of `y`\n\n.. sq:function:: rand()\n\n    returns a pseudorandom integer in the range 0 to `RAND_MAX`\n\n.. sq:function:: sin(x)\n\n    returns the sine of `x`\n\n.. sq:function:: sqrt(x)\n\n    returns the square root of `x`\n\n.. sq:function:: srand(seed)\n\n    sets the starting point for generating a series of pseudorandom integers\n\n.. sq:function:: tan(x)\n\n    returns the tangent of `x`\n\n.. sq:function:: min(x, y, [z], [w], ...)\n\n    returns minimal value of all arguments\n\n.. sq:function:: max(x, y, [z], [w], ...)\n\n    returns maximal value of all arguments\n\n.. sq:function:: clamp(x, min_val, max_val)\n\n    returns value limited by provided min-max range\n\n.. sq:data:: RAND_MAX\n\n    the maximum value that can be returned by the `rand()` function\n\n.. sq:data:: PI\n\n    The numeric constant pi (3.141592) is the ratio of the circumference of a circle to its diameter\n\n------------\nC API\n------------\n\n.. _sqstd_register_mathlib:\n\n.. c:function:: SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initializes and register the math library in the given VM.\n\n"
  },
  {
    "path": "doc/source/stdlib/stdstringlib.rst",
    "content": ".. _stdlib_stdstringlib:\n\n==================\nThe String library\n==================\n\nthe string lib implements string formatting and regular expression matching routines.\n\n--------------\nQuirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n.. sq:function:: endswith(str, cmp)\n\n    returns `true` if the end of the string `str`  matches a the string `cmp` otherwise returns `false`\n\n.. sq:function:: escape(str)\n\n    Returns a string with backslashes before characters that need to be escaped(`\\\",\\a,\\b,\\t,\\n,\\v,\\f,\\r,\\\\,\\\",\\',\\0,\\xnn`).\n\n.. sq:function:: format(formatstr, ...)\n\n    Returns a string formatted according `formatstr` and the optional parameters following it.\n    The format string follows the same rules as the `printf` family of\n    standard C functions( the \"*\" is not supported). ::\n\n        e.g.\n        sq> print(format(\"%s %d 0x%02X\\n\",\"this is a test :\",123,10));\n        this is a test : 123 0x0A\n\n.. sq:function:: printf(formatstr, ...)\n\n    Just like calling `print(format(formatstr` as in the example above, but is more convenient AND more efficient. ::\n\n        e.g.\n        sq> printf(\"%s %d 0x%02X\\n\",\"this is a test :\",123,10);\n        this is a test : 123 0x0A\n\n.. note::  The following functions are also available as string :ref:`type methods <builtin_type_classes>`.\n\n.. sq:function:: lstrip(str)\n\n    Strips white-space-only characters that might appear at the beginning of the given string\n    and returns the new stripped string.\n\n.. sq:function:: rstrip(str)\n\n    Strips white-space-only characters that might appear at the end of the given string\n    and returns the new stripped string.\n\n.. js:function:: split_by_chars(str, separators [, skipempty])\n\n    returns an array of strings split at each point where a separator character occurs in `str`.\n    The separator is not returned as part of any array element.\n    The parameter `separators` is a string that specifies the characters as to be used for the splitting.\n    The parameter `skipempty` is a boolean (default false). If `skipempty` is true, empty strings are not added to array.\n\n    ::\n\n        eg.\n        let a = split_by_chars(\"1.2-3;;4/5\", \".-/;\")\n        // the result will be  [1,2,3,,4,5]\n        or\n        let b = split_by_chars(\"1.2-3;;4/5\", \".-/;\", true)\n        // the result will be  [1,2,3,4,5]\n\n\n.. sq:function:: startswith(str, cmp)\n\n    returns `true` if the beginning of the string `str` matches the string `cmp`; otherwise returns `false`\n\n.. sq:function:: strip(str)\n\n    Strips white-space-only characters that might appear at the beginning or end of the given string and returns the new stripped string.\n\n++++++++++++++++++\nThe regexp class\n++++++++++++++++++\n\n.. sq:class:: regexp(pattern)\n\n    The regexp object represents a precompiled regular expression pattern. The object is created\n    through `regexp(pattern)`.\n\n\n+---------------------+--------------------------------------+\n|      `\\\\`           |  Quote the next metacharacter        |\n+---------------------+--------------------------------------+\n|      `^`            |  Match the beginning of the string   |\n+---------------------+--------------------------------------+\n|      `.`            |  Match any character                 |\n+---------------------+--------------------------------------+\n|      `$`            |  Match the end of the string         |\n+---------------------+--------------------------------------+\n|      `|`            |  Alternation                         |\n+---------------------+--------------------------------------+\n|      `(subexp)`     |  Grouping (creates a capture)        |\n+---------------------+--------------------------------------+\n|      `(?:subexp)`   |  No Capture Grouping (no capture)    |\n+---------------------+--------------------------------------+\n|      `[]`           |  Character class                     |\n+---------------------+--------------------------------------+\n\n**GREEDY CLOSURES**\n\n+---------------------+---------------------------------------------+\n|      `*`            |  Match 0 or more times                      |\n+---------------------+---------------------------------------------+\n|      `+`            |  Match 1 or more times                      |\n+---------------------+---------------------------------------------+\n|      `?`            |  Match 1 or 0 times                         |\n+---------------------+---------------------------------------------+\n|      `{n}`          |  Match exactly n times                      |\n+---------------------+---------------------------------------------+\n|      `{n,}`         |  Match at least n times                     |\n+---------------------+---------------------------------------------+\n|      `{n,m}`        |  Match at least n but not more than m times |\n+---------------------+---------------------------------------------+\n\n**ESCAPE CHARACTERS**\n\n+---------------------+--------------------------------------+\n|      `\\\\t`          |  tab (HT, TAB)                       |\n+---------------------+--------------------------------------+\n|      `\\\\n`          |  newline (LF, NL)                    |\n+---------------------+--------------------------------------+\n|      `\\\\r`          | return (CR)                          |\n+---------------------+--------------------------------------+\n|      `\\\\f`          |  form feed (FF)                      |\n+---------------------+--------------------------------------+\n\n**PREDEFINED CLASSES**\n\n+---------------------+--------------------------------------+\n|      `\\\\l`          |  lowercase next char                 |\n+---------------------+--------------------------------------+\n|      `\\\\u`          |  uppercase next char                 |\n+---------------------+--------------------------------------+\n|      `\\\\a`          |  letters                             |\n+---------------------+--------------------------------------+\n|      `\\\\A`          |  non letters                         |\n+---------------------+--------------------------------------+\n|      `\\\\w`          |  alphanumeric `[_0-9a-zA-Z]`         |\n+---------------------+--------------------------------------+\n|      `\\\\W`          |  non alphanumeric `[^_0-9a-zA-Z]`    |\n+---------------------+--------------------------------------+\n|      `\\\\s`          |  space                               |\n+---------------------+--------------------------------------+\n|      `\\\\S`          |  non space                           |\n+---------------------+--------------------------------------+\n|      `\\\\d`          |  digits                              |\n+---------------------+--------------------------------------+\n|      `\\\\D`          |  non digits                          |\n+---------------------+--------------------------------------+\n|      `\\\\x`          |  hexadecimal digits                  |\n+---------------------+--------------------------------------+\n|      `\\\\X`          |  non hexadecimal digits              |\n+---------------------+--------------------------------------+\n|      `\\\\c`          |  control characters                  |\n+---------------------+--------------------------------------+\n|      `\\\\C`          |  non control characters              |\n+---------------------+--------------------------------------+\n|      `\\\\p`          |  punctuation                         |\n+---------------------+--------------------------------------+\n|      `\\\\P`          |  non punctuation                     |\n+---------------------+--------------------------------------+\n|      `\\\\b`          |  word boundary                       |\n+---------------------+--------------------------------------+\n|      `\\\\B`          |  non word boundary                   |\n+---------------------+--------------------------------------+\n\n\n.. sq:function:: regexp.capture(str [, start])\n\n    returns an array of tables containing two indexes (\"begin\" and \"end\") of\n    the first match of the regular expression in the string `str`.\n    An array entry is created for each captured sub expressions. If no match occurs returns null.\n    The search starts from the index `start`\n    of the string; if `start` is omitted the search starts from the beginning of the string.\n\n    The first element of the returned array(index 0) always contains the complete match.\n\n    ::\n\n        local ex = regexp(@\"(\\d+) ([a-zA-Z]+)(\\p)\");\n        local string = \"stuff 123 Test;\";\n        local res = ex.capture(string);\n        foreach(i,val in res)\n        {\n            println(format(\"match number[%02d] %s\",\n                    i,string.slice(val.begin,val.end))); //prints \"Test\"\n        }\n\n        ...\n        will print\n        match number[00] 123 Test;\n        match number[01] 123\n        match number[02] Test\n        match number[03] ;\n\n.. sq:function:: regexp.match(str)\n\n    returns a true if the regular expression matches the string\n    `str`, otherwise returns false.\n\n.. sq:function:: regexp.search(str [, start])\n\n    returns a table containing two indexes (\"begin\" and \"end\") of the first match of the regular expression in\n    the string `str`, otherwise if no match occurs returns null. The search starts from the index `start`\n    of the string; if `start` is omitted the search starts from the beginning of the string.\n\n    ::\n\n        local ex = regexp(\"[a-zA-Z]+\");\n        local string = \"123 Test;\";\n        local res = ex.search(string);\n        print(string.slice(res.begin,res.end)); //prints \"Test\"\n\n-------------\nC API\n-------------\n\n.. _sqstd_register_stringlib:\n\n.. c:function:: SQRESULT sqstd_register_stringlib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initialize and register the string library in the given VM.\n\n+++++++++++++\nFormatting\n+++++++++++++\n\n.. c:function:: SQRESULT sqstd_format(HSQUIRRELVM v, SQInteger nformatstringidx, SQInteger* outlen, char** output)\n\n    :param HSQUIRRELVM v: the target VM\n    :param SQInteger nformatstringidx: index in the stack of the format string\n    :param SQInteger* outlen: a pointer to an integer that will be filled with the length of the newly created string\n    :param char** output: a pointer to a string pointer that will receive the newly created string\n    :returns: an SQRESULT\n    :remarks: the newly created string is allocated in the scratchpad memory.\n\n\n    creates a new string formatted according to the object at position `nformatstringidx` and the optional parameters following it.\n    The format string follows the same rules as the `printf` family of\n    standard C functions( the \"*\" is not supported).\n\n++++++++++++++++++\nRegular Expessions\n++++++++++++++++++\n\n.. c:function:: SQRex* sqstd_rex_compile(SQAllocCtx alloc_ctx, const char *pattern, const char ** error)\n\n    :param SQAllocCtx alloc_ctx VM memory allocation context handle\n    :param char* pattern: a pointer to a zero terminated string containing the pattern that has to be compiled.\n    :param char** error: a pointer to a string pointer that will be set with an error string in case of failure.\n    :returns: a pointer to the compiled pattern\n\n    compiles an expression and returns a pointer to the compiled version.\n    in case of failure returns NULL.The returned object has to be deleted\n    through the function sqstd_rex_free().\n\n.. c:function:: void sqstd_rex_free(SQRex * exp)\n\n    :param SQRex* exp: the expression structure that has to be deleted.\n\n    deletes a expression structure created with sqstd_rex_compile()\n\n.. c:function:: SQBool sqstd_rex_match(SQRex * exp,const char * text)\n\n    :param SQRex* exp: a compiled expression\n    :param char* text: the string that has to be tested\n    :returns: SQTrue if successful otherwise SQFalse\n\n    returns SQTrue if the string specified in the parameter text is an\n    exact match of the expression, otherwise returns SQFalse.\n\n.. c:function:: SQBool sqstd_rex_search(SQRex * exp, const char * text, const char ** out_begin, const char ** out_end)\n\n    :param SQRex* exp: a compiled expression\n    :param char* text: the string that has to be tested\n    :param char** out_begin: a pointer to a string pointer that will be set with the beginning of the match\n    :param char** out_end: a pointer to a string pointer that will be set with the end of the match\n    :returns: SQTrue if successful otherwise SQFalse\n\n    searches the first match of the expression in the string specified in the parameter text.\n    if the match is found returns SQTrue and the sets out_begin to the beginning of the\n    match and out_end at the end of the match; otherwise returns SQFalse.\n\n.. c:function:: SQBool sqstd_rex_searchrange(SQRex * exp, const char * text_begin, const char * text_end, const char ** out_begin, const char ** out_end)\n\n    :param SQRex* exp: a compiled expression\n    :param char* text_begin:  a pointer to the beginnning of the string that has to be tested\n    :param char* text_end: a pointer to the end of the string that has to be tested\n    :param char** out_begin: a pointer to a string pointer that will be set with the beginning of the match\n    :param char** out_end: a pointer to a string pointer that will be set with the end of the match\n    :returns: SQTrue if successful otherwise SQFalse\n\n    searches the first match of the expression in the string delimited\n    by the parameter text_begin and text_end.\n    if the match is found returns SQTrue and sets out_begin to the beginning of the\n    match and out_end at the end of the match; otherwise returns SQFalse.\n\n.. c:function:: SQInteger sqstd_rex_getsubexpcount(SQRex * exp)\n\n    :param SQRex* exp: a compiled expression\n    :returns: the number of sub expressions matched by the expression\n\n    returns the number of sub expressions matched by the expression\n\n.. c:function:: SQBool sqstd_rex_getsubexp(SQRex * exp, SQInteger n, SQRexMatch *subexp)\n\n    :param SQRex* exp: a compiled expression\n    :param SQInteger n: the index of the submatch(0 is the complete match)\n    :param SQRexMatch* a: pointer to structure that will store the result\n    :returns: the function returns SQTrue if n is a valid index; otherwise SQFalse.\n\n    retrieve the begin and and pointer to the length of the sub expression indexed\n    by n. The result is passed through the struct SQRexMatch.\n"
  },
  {
    "path": "doc/source/stdlib/stdsystemlib.rst",
    "content": ".. _stdlib_stdsystemlib:\n\n==================\nThe System library\n==================\n\nThe system library exposes operating system facilities like environment variables,\nprocess execution and file operations\n\n--------------\nQuirrel API\n--------------\n\n++++++++++++++\nGlobal Symbols\n++++++++++++++\n\n\n.. sq:function:: getenv(varaname)\n\n    Returns a string containing the value of the environment variable `varname`\n\n.. sq:function:: remove(path)\n\n    deletes the file specified by `path`\n\n.. sq:function:: rename(oldname, newname)\n\n    renames the file or directory specified by `oldname` to the name given by `newname`\n\n.. sq:function:: system(cmd)\n\n    executes the string `cmd` through the os command interpreter.\n\n--------------\nC API\n--------------\n\n.. _sqstd_register_systemlib:\n\n.. c:function:: SQRESULT sqstd_register_systemlib(HSQUIRRELVM v)\n\n    :param HSQUIRRELVM v: the target VM\n    :returns: an SQRESULT\n    :remarks: The function aspects a table on top of the stack where to register the global library functions.\n\n    initialize and register the system library in the given VM.\n"
  },
  {
    "path": "helpers/keyValueFile.h",
    "content": "#pragma once\n\n#include <string.h>\n#include <string>\n#include <vector>\n#include <fstream>\n#include <streambuf>\n\n\n//file example:\n//\n//  ; comment\n//  include ../some_file.inc\n//  boolean_value = yes   ; comment\n//  code = fn1(); fn2();  ; comment\n//\n//  ; use '\\' for concatination with the next line\n//  multiline = line1 \\\n//              line1 \\  ; valid comment\n//              line1 \\\n//              line1\n//\n//  list = value1  ; call getValuesList(\"list\") to get all these values in std::vector\n//  list = value2\n//  list = value3  value4 value5\n//  list = value6\n//\n//\n\nclass KeyValueFile\n{\npublic:\n  typedef void (*PrintErrorFunc)(const char *);\n  PrintErrorFunc printErrorFunc = nullptr;\n\n  struct StringKeyValue\n  {\n    std::string key;\n    std::string value;\n  };\n\nprivate:\n  std::string fileName;\n  std::vector<StringKeyValue> kv;\n  int includeDepth = 0;\n\n  bool isUtf8Bom(const char * it)\n  {\n    return (\n      (unsigned char)(*it++) == 0xef &&\n      (unsigned char)(*it++) == 0xbb &&\n      (unsigned char)(*it)   == 0xbf\n    );\n  }\n\n  bool isSpace(char c) const\n  {\n    return c == ' ' || c == '\\t';\n  }\n\n  std::string trimStr(const std::string & s)\n  {\n    int from = 0;\n    int to = int(s.length()) - 1;\n    while (to > 0 && isSpace(s[to]))\n      to--;\n    while (from <= to && isSpace(s[from]))\n      from++;\n    if (to < from)\n      return std::string(\"\");\n    return std::string(&(s[from]), to - from + 1);\n  }\n\n  void errorParam(const char * msg, const char * key_name) const\n  {\n    if (printErrorFunc)\n    {\n      std::string err = std::string(\"ERROR: \") + msg + \", at file '\" + fileName +  \"', key '\" + std::string(key_name) + \"'\\n\";\n      printErrorFunc(err.c_str());\n    }\n  }\n\n  bool includeFile(const char * inc_file_name, int include_depth)\n  {\n    if (include_depth >= 16)\n    {\n      if (printErrorFunc)\n        printErrorFunc(\n          (std::string(\"ERROR: Maximum include depth exceeded on file '\") + inc_file_name + \"'\\n\").c_str());\n      return false;\n    }\n\n    int len = int(fileName.length()) - 1;\n    while (len >= 0)\n    {\n      if (fileName[len] == '\\\\' || fileName[len] == '/')\n        break;\n      len--;\n    }\n\n    std::string combinedFileName(fileName.c_str(), len + 1);\n    combinedFileName += inc_file_name;\n\n    KeyValueFile kvFile;\n    kvFile.includeDepth = include_depth + 1;\n    kvFile.printErrorFunc = printErrorFunc;\n\n    bool ok = kvFile.loadFromFile(combinedFileName.c_str());\n\n    if (ok)\n      for (auto && value : kvFile.kv)\n        kv.push_back(value);\n\n    return ok;\n  }\n\npublic:\n\n  bool loadFromFile(const char * file_name)\n  {\n    if (!file_name)\n      return false;\n\n    std::ifstream stream(file_name);\n    if (stream.fail())\n    {\n      if (printErrorFunc)\n        printErrorFunc(\n          (std::string(\"ERROR: Cannot open file '\") + file_name + \"'\\n\").c_str());\n      return false;\n    }\n\n    std::string buf((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());\n\n    return loadFromString(buf.c_str(), file_name);\n  }\n\n\n  bool loadFromString(const char * data, const char * debug_file_name = \"\")\n  {\n    fileName = debug_file_name;\n\n    if (!data)\n      return false;\n\n    if (isUtf8Bom(data))\n      data += 3;\n    int len = int(strlen(data));\n\n    StringKeyValue x;\n    bool comment = false;\n    bool readKey = true;\n    bool eqFound = false;\n    bool error = false;\n    bool include = false;\n    int line = 1;\n\n    for (int i = 0; i <= len; i++)\n    {\n      char c = data[i];\n\n      if (c == '\\\\')\n      {\n        if (i == len - 1)\n          i++;\n        else\n        {\n          bool commentAfterConcat = false;\n          for (int j = i + 1; j < len; j++)\n          {\n            if (data[j] == ';' && isSpace(data[j - 1]))\n              commentAfterConcat = true;\n\n            if (!commentAfterConcat && data[j] > ' ')\n              break;\n\n            bool concat = false;\n            if (data[j] == 0x0d && data[j + 1] == 0x0a)\n            {\n              line++;\n              i = j + 2;\n              concat = true;\n            }\n            else if (data[j] == 0x0a)\n            {\n              line++;\n              i = j + 1;\n              concat = true;\n            }\n\n            if (concat)\n            {\n              if (comment)\n                if (printErrorFunc)\n                  printErrorFunc((std::string(\"ERROR: Line concatenation inside comment. At file '\") +\n                    fileName + \"' line \" + std::to_string(line - 1) + \"\\n\").c_str());\n\n              if (data[i] > ' ' && data[i] != ';')\n                if (printErrorFunc)\n                  printErrorFunc((\n                    std::string(\"ERROR: The next line after the line concatenation symbol '\\\\' must be started with space. At file '\") +\n                    fileName + \"' line \" + std::to_string(line) + \"\\n\").c_str());\n\n              c = data[i];\n              break;\n            }\n          }\n        }\n      }\n\n      if (c == 0x0d || c == 0x0a || c == 0)\n      {\n        x.key = trimStr(x.key);\n        x.value = trimStr(x.value);\n        if (!x.key.empty() && !x.value.empty() && eqFound && !include)\n        {\n          //printf(\"%s = \\\"%s\\\"\\n\", x.key.c_str(), x.value.c_str());\n          kv.push_back(x);\n        }\n        else if (!x.key.empty())\n        {\n          if (include)\n          {\n            if (!debug_file_name || !debug_file_name[0])\n            {\n              if (printErrorFunc)\n                printErrorFunc(\n                  (std::string(\"ERROR: File name must be passed to loadFromString() when you are using 'include'. At file '\") +\n                    fileName + \"' line \" + std::to_string(line) + \"\\n\").c_str());\n              error = true;\n            }\n            else\n            {\n              bool ok = includeFile(x.value.c_str(), includeDepth);\n              error |= !ok;\n            }\n          }\n          else if (!eqFound)\n          {\n            if (printErrorFunc)\n              printErrorFunc(\n                (std::string(\"ERROR: Expected '=' at file '\") + fileName + \"' line \" + std::to_string(line) + \"\\n\").c_str());\n            error = true;\n          }\n          else if (x.value.empty())\n          {\n            if (printErrorFunc)\n              printErrorFunc(\n                (std::string(\"ERROR: Expected value after '=' at file '\") + fileName + \"' line \" + std::to_string(line) + \"\\n\").c_str());\n            error = true;\n          }\n        }\n\n        comment = false;\n        readKey = true;\n        eqFound = false;\n        include = false;\n        x.key.clear();\n        x.value.clear();\n\n        if (c == 0x0a)\n          line++;\n      }\n\n      if (c == ';' && (i == 0 || isSpace(data[i - 1]) || data[i - 1] == 0x0a))\n        comment = true;\n\n      if (comment)\n        continue;\n\n      if (readKey)\n      {\n        if (!isSpace(c) && c > ' ' && c != '=')\n          x.key += c;\n        else if (!x.key.empty())\n        {\n          readKey = false;\n          if (c == '=')\n            eqFound = true;\n\n          if (x.key == \"include\")\n            include = true;\n        }\n      }\n      else\n      {\n        if (c == '=' && !eqFound)\n          eqFound = true;\n        else if ((eqFound && c >= ' ') || include)\n          x.value += c;\n      }\n    }\n\n    return !error;\n  }\n\n\n  int count() const\n  {\n    return int(kv.size());\n  }\n\n\n  const char * getStr(const char * key, const char * default_value = \"\") const\n  {\n    if (!key)\n      return default_value;\n\n    const char *res = default_value;\n\n    for (int i = 0; i < int(kv.size()); i++)\n      if (!strcmp(key, kv[i].key.c_str()))\n      {\n        if (res != default_value)\n          errorParam(\"More than one key found\", key);\n\n        res = kv[i].value.c_str();\n      }\n\n    return res;\n  }\n\n\n  bool getBool(const char * key, bool default_value) const\n  {\n    if (!key)\n      return default_value;\n\n    for (int i = 0; i < int(kv.size()); i++)\n      if (!strcmp(key, kv[i].key.c_str()))\n      {\n        if (kv[i].value.empty())\n          errorParam(\"Value is empty\", key);\n        const char * v = kv[i].value.c_str();\n        bool isTrue = !strcmp(v, \"1\") || !strcmp(v, \"yes\") || !strcmp(v, \"true\");\n        bool isFalse = !strcmp(v, \"0\") || !strcmp(v, \"no\") || !strcmp(v, \"false\");\n        if (!isTrue && !isFalse)\n          errorParam(\"Invalid boolean value, expected yes,true,1 or no,false,0\", key);\n\n        return isTrue;\n      }\n\n    return default_value;\n  }\n\n\n  std::vector<std::string> getValuesList(const char * key) const // separated by spaces\n  {\n    std::vector<std::string> res;\n\n    for (auto && x : kv)\n      if (!strcmp(key, x.key.c_str()))\n      {\n        const char * s = x.value.c_str();\n        int len = int(x.value.length());\n        int i = 0;\n        while (i < len)\n        {\n          while (i < len && (isSpace(s[i]) || s[i] < ' '))\n            i++;\n\n          int wordStart = i;\n\n          while (i < len && s[i] > ' ')\n            i++;\n\n          if (i != wordStart)\n            res.push_back(std::string(s + wordStart, i - wordStart));\n        }\n      }\n\n    return res;\n  }\n\n\n  const StringKeyValue & keyValue(int index) const\n  {\n    return kv[index];\n  }\n\n\n  const std::string getFileName() const\n  {\n    return fileName;\n  }\n};\n"
  },
  {
    "path": "include/sq_char_class.h",
    "content": "#pragma once\n\ninline bool sq_isalnum(int c)\n{\n    unsigned char uc = c;\n    return (uc >= 'a' && uc <= 'z') || (uc >= 'A' && uc <= 'Z') || (uc >= '0' && uc <= '9');\n}\n\ninline bool sq_isalpha(int c)\n{\n    unsigned char uc = c;\n    return (uc >= 'A' && uc <= 'Z') || (uc >= 'a' && uc <= 'z');\n}\n\ninline bool sq_isblank(int c)\n{\n    unsigned char uc = c;\n    return uc == ' ' || uc == '\\t';\n}\n\ninline bool sq_iscntrl(int c)\n{\n    unsigned char uc = c;\n    return uc <= 31 || uc == 127;\n}\n\ninline bool sq_isdigit(int c)\n{\n    unsigned char uc = c;\n    return uc >= '0' && uc <= '9';\n}\n\ninline bool sq_isgraph(int c)\n{\n    unsigned char uc = c;\n    return uc >= 33 && uc <= 126;\n}\n\ninline bool sq_islower(int c)\n{\n    unsigned char uc = c;\n    return uc >= 'a' && uc <= 'z';\n}\n\ninline bool sq_isprint(int c)\n{\n    unsigned char uc = c;\n    return uc >= 32 && uc <= 126;\n}\n\ninline bool sq_ispunct(int c)\n{\n    unsigned char uc = c;\n    return (uc >= 33 && uc <= 47) || (uc >= 58 && uc <= 64) || (uc >= 91 && uc <= 96) || (uc >= 123 && uc <= 126);\n}\n\ninline bool sq_isspace(int c)\n{\n    unsigned char uc = c;\n    return uc == ' ' || uc == '\\t' || uc == '\\n' || uc == '\\v' || uc == '\\f' || uc == '\\r';\n}\n\ninline bool sq_isupper(int c)\n{\n    unsigned char uc = c;\n    return uc >= 'A' && uc <= 'Z';\n}\n\ninline bool sq_isxdigit(int c)\n{\n    unsigned char uc = c;\n    return (uc >= '0' && uc <= '9') || (uc >= 'A' && uc <= 'F') || (uc >= 'a' && uc <= 'f');\n}\n\ninline int sq_toupper(int c)\n{\n    if (c < 'a' || c > 'z')\n        return c;\n    return c + 'A' - 'a';\n}\n\ninline int sq_tolower(int c)\n{\n    if (c < 'A' || c > 'Z')\n        return c;\n    return c + 'a' - 'A';\n}\n\n"
  },
  {
    "path": "include/sqconfig.h",
    "content": "#ifndef _SQ64\n#define _SQ64 // always use 64 bit Integers (even on 32 bit platform)\n#endif\n\n#define __STDC_FORMAT_MACROS // Linux/Adnroid won't define PRId* macroses without this\n#include <stdint.h>\n#include <inttypes.h>\n\n#ifdef _SQ64\n    typedef int64_t  SQInteger;\n    typedef uint64_t SQUnsignedInteger;\n    typedef uint64_t SQHash; /*should be the same size of a pointer*/\n#else\n    typedef intptr_t SQInteger;\n    typedef uintptr_t SQUnsignedInteger;\n    typedef uintptr_t SQHash; /*should be the same size of a pointer*/\n#endif\n\ntypedef int SQInt32;\ntypedef unsigned int SQUnsignedInteger32;\n\n\n#ifdef SQUSEDOUBLE\n    typedef double SQFloat;\n#else\n    typedef float SQFloat;\n#endif\n\n#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64)\n    typedef int64_t SQRawObjectVal; //must be 64bits\n    #define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; }\n#else\n    typedef SQUnsignedInteger SQRawObjectVal; //is 32 bits on 32 bits builds and 64 bits otherwise\n    #define SQ_OBJECT_RAWINIT()\n#endif\n\n#ifndef SQ_ALIGNMENT // SQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and its value shall be power of 2.\n    #if defined(SQUSEDOUBLE) || defined(_SQ64)\n        #define SQ_ALIGNMENT 8\n    #else\n        #define SQ_ALIGNMENT 4\n    #endif\n#endif\n\ntypedef void* SQUserPointer;\ntypedef SQUnsignedInteger SQBool;\ntypedef SQInteger SQRESULT;\n\n#if defined __EMSCRIPTEN__\n#define scsprintf   snprintf\n#elif _MSC_VER\n#define scsprintf   _snprintf\n#else\n#define scsprintf   snprintf\n#endif\n#ifdef _SQ64\n#ifdef _MSC_VER\n#define scstrtol    _strtoi64\n#else\n#define scstrtol    strtoll\n#endif\n#else\n#define scstrtol    strtol\n#endif\n\n#ifdef _SQ64\n    #define _PRINT_INT_PREC \"ll\"\n    #define _PRINT_INT_FMT \"%\" PRId64\n#else\n    #define _PRINT_INT_FMT \"%d\"\n#endif\n#define SQ_CHECK_THREAD_LEVEL_NONE 0\n#define SQ_CHECK_THREAD_LEVEL_FAST 1\n#define SQ_CHECK_THREAD_LEVEL_DEEP 2\n\n#ifndef SQ_CHECK_THREAD\n#define SQ_CHECK_THREAD SQ_CHECK_THREAD_LEVEL_NONE\n#endif\n\n// doc strings and native function declaration strings\n#ifndef SQ_STORE_DOC_OBJECTS\n#define SQ_STORE_DOC_OBJECTS 1\n#endif\n\n#define MIN_SQ_INTEGER SQInteger(1ULL << (sizeof(SQInteger) * 8 - 1))\n"
  },
  {
    "path": "include/sqext.h",
    "content": "/*\n * Squirrel API extensions\n * Copyright (C) 2023  Gaijin Games KFT.  All rights reserved\n */\n#ifndef _SQEXT_H_\n#define _SQEXT_H_\n\n#include \"squirrel.h\"\n\n\nSQUIRREL_API SQRESULT sq_ext_getfuncinfo(HSQOBJECT obj, SQFunctionInfo *fi);\nSQUIRREL_API SQRESULT sq_ext_get_array_floats(HSQOBJECT obj, int start, int count, float * dest);\nSQUIRREL_API int sq_ext_get_array_int(HSQOBJECT obj, int index, int def = 0);\nSQUIRREL_API float sq_ext_get_array_float(HSQOBJECT obj, int index, float def = 0.f);\n\n\n#endif /*_SQEXT_H_*/\n"
  },
  {
    "path": "include/sqio.h",
    "content": "#ifndef _SQASTIO_H_\n#define _SQASTIO_H_ 1\n\n#include <stdint.h>\n#include <iostream>\n#include <stdio.h>\n\n#include \"squirrel.h\"\n\nclass InputStream {\nprotected:\n  virtual uint8_t readByte() = 0;\n\n  int64_t readVarint();\n  uint64_t readVaruint();\npublic:\n\n  virtual ~InputStream() {}\n\n  virtual size_t pos() = 0;\n  virtual void seek(size_t) = 0;\n\n  int8_t readInt8();\n  int16_t readInt16();\n  int32_t readInt32();\n  int64_t readInt64();\n  intptr_t readIntptr();\n\n  uint8_t readUInt8();\n  uint16_t readUInt16();\n  uint32_t readUInt32();\n  uint64_t readUInt64();\n  uintptr_t readUIntptr();\n\n  SQInteger readSQInteger() {\n#ifdef _SQ64\n    return readInt64();\n#else\n    return readIntptr();\n#endif // _SQ64\n  }\n\n  SQUnsignedInteger readSQUnsignedInteger() {\n#ifdef _SQ64\n    return readUInt64();\n#else\n    return readUIntptr();\n#endif // _SQ64\n  }\n\n  SQFloat readSQFloat() {\n\n#ifdef SQUSEDOUBLE\n    int32_t t = readInt32();\n    return *(SQFloat *)&t;\n#else\n    int64_t t = readInt64();\n    return *(SQFloat *)&t;\n#endif // SQUSEDOUBLE\n  }\n\n  uint64_t readRawUInt64();\n};\n\nclass StdInputStream : public InputStream {\n  std::istream &i;\npublic:\n\n  StdInputStream(std::istream &s) : i(s) {}\n\n  uint8_t readByte();\n  size_t pos();\n  void seek(size_t);\n};\n\nclass FileInputStream : public InputStream {\n  FILE *file;\npublic:\n\n  FileInputStream(const char *fileName);\n  ~FileInputStream();\n\n  bool valid() const { return file != NULL; }\n\n  uint8_t readByte();\n  size_t pos();\n  void seek(size_t);\n};\n\nclass MemoryInputStream : public InputStream {\n\n  const uint8_t *buffer;\n  const size_t size;\n  size_t ptr;\n\npublic:\n\n  MemoryInputStream(const uint8_t *b, const size_t s) : buffer(b), size(s), ptr(0) {}\n\n  uint8_t readByte();\n  size_t pos();\n  void seek(size_t);\n};\n\n\nclass OutputStream {\nprotected:\n  virtual void writeByte(uint8_t) = 0;\n\n  void writeVarint(int64_t);\n  void writeVaruint(uint64_t);\n\npublic:\n\n  virtual ~OutputStream() {}\n\n  virtual size_t pos() = 0;\n  virtual void seek(size_t pos) = 0;\n\n  void writeInt8(int8_t);\n  void writeInt16(int16_t);\n  void writeInt32(int32_t);\n  void writeInt64(int64_t);\n  void writeIntptr(intptr_t);\n\n  void writeUInt8(uint8_t);\n  void writeUInt16(uint16_t);\n  void writeUInt32(uint32_t);\n  void writeUInt64(uint64_t);\n  void writeUIntptr(uintptr_t);\n\n  void writeSQInteger(SQInteger i) {\n#ifdef _SQ64\n    writeInt64(i);\n#else\n    writeIntptr(i);\n#endif // _SQ64\n  }\n\n  void writeSQUnsignedInteger(SQUnsignedInteger u) {\n#ifdef _SQ64\n    writeUInt64(u);\n#else\n    writeUIntptr(u);\n#endif // _SQ64\n  }\n\n  void writeSQFloat(SQFloat f) {\n#ifdef SQUSEDOUBLE\n    writeInt32(*((int32_t*)&f));\n#else\n    writeInt64(*((int64_t*)&f));\n#endif // SQUSEDOUBLE\n  }\n\n  void writeString(const char *s);\n  void writeChar(char c);\n\n  void writeRawUInt64(uint64_t v);\n};\n\nclass StdOutputStream : public OutputStream {\n  std::ostream &o;\npublic:\n\n  StdOutputStream(std::ostream &s) : o(s) {}\n\n  void writeByte(uint8_t);\n  size_t pos();\n  void seek(size_t);\n};\n\nclass FileOutputStream : public OutputStream {\n  FILE *file;\n  bool close;\npublic:\n\n  FileOutputStream(FILE *f) : file(f), close(false) {}\n  FileOutputStream(const char *filename);\n  ~FileOutputStream();\n\n  bool valid() const { return file != NULL; }\n\n  void writeByte(uint8_t);\n  size_t pos();\n  void seek(size_t);\n};\n\nclass MemoryOutputStream : public OutputStream {\n  uint8_t *_buffer;\n  size_t _size;\n  size_t ptr;\n\n  void resize(size_t);\n\npublic:\n\n  MemoryOutputStream() : _buffer(NULL), _size(0), ptr(0) {}\n  ~MemoryOutputStream();\n\n  void writeByte(uint8_t);\n  size_t pos();\n  void seek(size_t);\n\n  const uint8_t *buffer() const { return _buffer; }\n};\n\n#endif // !_SQASTIO_H_\n"
  },
  {
    "path": "include/sqstdaux.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_AUXLIB_H_\n#define _SQSTD_AUXLIB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API void sqstd_seterrorhandlers(HSQUIRRELVM v);\nSQUIRREL_API void sqstd_printcallstack(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sqstd_formatcallstackstring(HSQUIRRELVM v);\n\nSQUIRREL_API SQRESULT sqstd_throwerrorf(HSQUIRRELVM v,const char *err,...);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /* _SQSTD_AUXLIB_H_ */\n"
  },
  {
    "path": "include/sqstdblob.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTDBLOB_H_\n#define _SQSTDBLOB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size);\nSQUIRREL_API SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr);\nSQUIRREL_API SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx);\n\nSQUIRREL_API SQRESULT sqstd_register_bloblib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTDBLOB_H_*/\n\n"
  },
  {
    "path": "include/sqstddatetime.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_DATETIMELIB_H_\n#define _SQSTD_DATETIMELIB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQRESULT sqstd_register_datetimelib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /* _SQSTD_DATETIMELIB_H_ */\n"
  },
  {
    "path": "include/sqstddebug.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_DEBUG_H_\n#define _SQSTD_DEBUG_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQRESULT sqstd_register_debuglib(HSQUIRRELVM v);\n\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif // _SQSTD_DEBUG_H_\n"
  },
  {
    "path": "include/sqstdio.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTDIO_H_\n#define _SQSTDIO_H_\n\n#ifdef __cplusplus\n\n#define SQSTD_STREAM_TYPE_TAG 0x80000000\n\nstruct SQStream {\n    SQStream() = default;\n    SQStream(const SQStream&) = default;\n    SQStream(SQStream&&) = default;\n    SQStream& operator=(const SQStream&) = default;\n    SQStream& operator=(SQStream&&) = default;\n    virtual ~SQStream() {}\n    virtual SQInteger Read(void *buffer, SQInteger size) = 0;\n    virtual SQInteger Write(const void *buffer, SQInteger size) = 0;\n    virtual SQInteger Flush() = 0;\n    virtual SQInteger Tell() = 0;\n    virtual SQInteger Len() = 0;\n    virtual SQInteger Seek(SQInteger offset, SQInteger origin) = 0;\n    virtual bool IsValid() = 0;\n    virtual bool EOS() = 0;\n};\n\nextern \"C\" {\n#endif\n\n#define SQ_SEEK_CUR 0\n#define SQ_SEEK_END 1\n#define SQ_SEEK_SET 2\n\ntypedef void* SQFILE;\n\nSQUIRREL_API SQFILE sqstd_fopen(const char *,const char *);\nSQUIRREL_API SQInteger sqstd_fread(SQUserPointer, SQInteger, SQInteger, SQFILE);\nSQUIRREL_API SQInteger sqstd_fwrite(const SQUserPointer, SQInteger, SQInteger, SQFILE);\nSQUIRREL_API SQInteger sqstd_fseek(SQFILE , SQInteger , SQInteger);\nSQUIRREL_API SQInteger sqstd_ftell(SQFILE);\nSQUIRREL_API SQInteger sqstd_fflush(SQFILE);\nSQUIRREL_API SQInteger sqstd_fclose(SQFILE);\nSQUIRREL_API SQInteger sqstd_feof(SQFILE);\n\nSQUIRREL_API SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own);\nSQUIRREL_API SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file);\n\n//compiler helpers\nSQUIRREL_API SQRESULT sqstd_loadfile(HSQUIRRELVM v,const char *filename,SQBool printerror);\nSQUIRREL_API SQRESULT sqstd_dofile(HSQUIRRELVM v,const char *filename,SQBool retval,SQBool printerror);\nSQUIRREL_API SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const char *filename);\n\nSQUIRREL_API SQRESULT sqstd_init_streamclass(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sqstd_register_iolib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTDIO_H_*/\n\n"
  },
  {
    "path": "include/sqstdmath.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_MATH_H_\n#define _SQSTD_MATH_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTD_MATH_H_*/\n"
  },
  {
    "path": "include/sqstdstring.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_STRING_H_\n#define _SQSTD_STRING_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef unsigned int SQRexBool;\ntypedef struct SQRex SQRex;\ntypedef struct SQAllocContextT * SQAllocContext;\n\ntypedef struct {\n    const char *begin;\n    SQInteger len;\n} SQRexMatch;\n\nSQUIRREL_API SQRex *sqstd_rex_compile(SQAllocContext ctx, const char *pattern,const char **error);\nSQUIRREL_API void sqstd_rex_free(SQRex *exp);\nSQUIRREL_API SQBool sqstd_rex_match(SQRex* exp,const char* text);\nSQUIRREL_API SQBool sqstd_rex_search(SQRex* exp,const char* text, const char** out_begin, const char** out_end);\nSQUIRREL_API SQBool sqstd_rex_searchrange(SQRex* exp,const char* text_begin,const char* text_end,const char** out_begin, const char** out_end);\nSQUIRREL_API SQInteger sqstd_rex_getsubexpcount(SQRex* exp);\nSQUIRREL_API SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp);\n\nSQUIRREL_API SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,char **output);\n\nSQUIRREL_API void sqstd_pushstringf(HSQUIRRELVM v,const char *s,...);\n\nSQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /*_SQSTD_STRING_H_*/\n"
  },
  {
    "path": "include/sqstdsystem.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_SYSTEMLIB_H_\n#define _SQSTD_SYSTEMLIB_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSQUIRREL_API SQRESULT sqstd_register_command_line_args(HSQUIRRELVM v, int argc, char ** argv);\nSQUIRREL_API SQRESULT sqstd_register_systemlib(HSQUIRRELVM v);\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\n#endif /* _SQSTD_SYSTEMLIB_H_ */\n"
  },
  {
    "path": "include/squirrel.h",
    "content": "/*\nCopyright (c) 2003-2017 Alberto Demichelis\nCopyright (c) 2016-2023 by Gaijin Games KFT\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n#ifndef _SQUIRREL_H_\n#define _SQUIRREL_H_\n\n#ifdef _SQ_CONFIG_INCLUDE\n#include _SQ_CONFIG_INCLUDE\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#else\n#include <stdbool.h>\n#endif\n#include <string.h> // memset\n\n#ifndef SQUIRREL_API\n#define SQUIRREL_API extern\n#endif\n\n#if (defined(_WIN64) || defined(_LP64))\n#ifndef _SQ64\n#define _SQ64\n#endif\n#endif\n\n\n#define SQTrue  (1)\n#define SQFalse (0)\n\nstruct SQVM;\nstruct SQTable;\nstruct SQArray;\nstruct SQString;\nstruct SQClosure;\nstruct SQGenerator;\nstruct SQNativeClosure;\nstruct SQUserData;\nstruct SQFunctionProto;\nstruct SQRefCounted;\nstruct SQClass;\nstruct SQInstance;\nstruct SQDelegable;\nstruct SQOuter;\n\nclass OutputStream;\nclass Arena;\n\nclass KeyValueFile;\n\nnamespace SQCompilation\n{\n  struct SqASTData;\n}\n\n#include \"sqconfig.h\"\n#include <stdio.h>\n\n#define SQUIRREL_VERSION_NUMBER_MAJOR 4\n#define SQUIRREL_VERSION_NUMBER_MINOR 20\n#define SQUIRREL_VERSION_NUMBER_PATCH 0\n\n#define SQ_STRINGIFY_HELPER(x) #x\n#define SQ_STRINGIFY(x) SQ_STRINGIFY_HELPER(x)\n\n#define SQUIRREL_VERSION \\\n    SQ_STRINGIFY(SQUIRREL_VERSION_NUMBER_MAJOR) \".\" \\\n    SQ_STRINGIFY(SQUIRREL_VERSION_NUMBER_MINOR) \".\" \\\n    SQ_STRINGIFY(SQUIRREL_VERSION_NUMBER_PATCH)\n\n#define SQUIRREL_COPYRIGHT  \"Copyright (C) 2003-2016 Alberto Demichelis; 2016-2025 Gaijin Games KFT\"\n\n\n#define SQ_VMSTATE_IDLE         0\n#define SQ_VMSTATE_RUNNING      1\n#define SQ_VMSTATE_SUSPENDED    2\n\n#define SQUIRREL_EOB 0\n#define SQ_BYTECODE_STREAM_TAG  0xFAFA\n\n#define SQOBJECT_REF_COUNTED    0x08000000\n#define SQOBJECT_NUMERIC        0x04000000\n#define SQOBJECT_DELEGABLE      0x02000000\n\n#define SQOBJ_FLAG_IMMUTABLE    0x01\n\n#define SQ_MATCHTYPEMASKSTRING (-99999)\n\n#define _RT_MASK 0x00FFFFFF\n#define _RAW_TYPE(type) ((type)&_RT_MASK)\n\n#define _RT_NULL            0x00000001\n#define _RT_INTEGER         0x00000002\n#define _RT_FLOAT           0x00000004\n#define _RT_BOOL            0x00000008\n#define _RT_STRING          0x00000010\n#define _RT_TABLE           0x00000020\n#define _RT_ARRAY           0x00000040\n#define _RT_USERDATA        0x00000080\n#define _RT_CLOSURE         0x00000100\n#define _RT_NATIVECLOSURE   0x00000200\n#define _RT_GENERATOR       0x00000400\n#define _RT_USERPOINTER     0x00000800\n#define _RT_THREAD          0x00001000\n#define _RT_FUNCPROTO       0x00002000\n#define _RT_CLASS           0x00004000\n#define _RT_INSTANCE        0x00008000\n#define _RT_WEAKREF         0x00010000\n#define _RT_OUTER           0x00020000\n#define _RT_FREE_TABLE_SLOT 0x80000000\n\ntypedef enum tagSQObjectType{\n    OT_NULL =           0, // Note: checking typemask for _RT_NULL is non-obvious and is implemented in a special manner\n    OT_INTEGER =        (_RT_INTEGER|SQOBJECT_NUMERIC),\n    OT_FLOAT =          (_RT_FLOAT|SQOBJECT_NUMERIC),\n    OT_BOOL =           (_RT_BOOL),\n    OT_STRING =         (_RT_STRING|SQOBJECT_REF_COUNTED),\n    OT_TABLE =          (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),\n    OT_ARRAY =          (_RT_ARRAY|SQOBJECT_REF_COUNTED),\n    OT_USERDATA =       (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),\n    OT_CLOSURE =        (_RT_CLOSURE|SQOBJECT_REF_COUNTED),\n    OT_NATIVECLOSURE =  (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED),\n    OT_GENERATOR =      (_RT_GENERATOR|SQOBJECT_REF_COUNTED),\n    OT_USERPOINTER =    _RT_USERPOINTER,\n    OT_THREAD =         (_RT_THREAD|SQOBJECT_REF_COUNTED) ,\n    OT_FUNCPROTO =      (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only\n    OT_CLASS =          (_RT_CLASS|SQOBJECT_REF_COUNTED),\n    OT_INSTANCE =       (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE),\n    OT_WEAKREF =        (_RT_WEAKREF|SQOBJECT_REF_COUNTED),\n    OT_OUTER =          (_RT_OUTER|SQOBJECT_REF_COUNTED), //internal usage only\n    OT_FREE_TABLE_SLOT = _RT_FREE_TABLE_SLOT //internal usage only\n}SQObjectType;\n\ntypedef uint8_t SQObjectFlags;\n\n#define ISREFCOUNTED(t) ((t)&SQOBJECT_REF_COUNTED)\n\n\ntypedef union tagSQObjectValue\n{\n    struct SQTable *pTable;\n    struct SQArray *pArray;\n    struct SQClosure *pClosure;\n    struct SQOuter *pOuter;\n    struct SQGenerator *pGenerator;\n    struct SQNativeClosure *pNativeClosure;\n    struct SQString *pString;\n    struct SQUserData *pUserData;\n    SQInteger nInteger;\n    SQFloat fFloat;\n    SQUserPointer pUserPointer;\n    struct SQFunctionProto *pFunctionProto;\n    struct SQRefCounted *pRefCounted;\n    struct SQDelegable *pDelegable;\n    struct SQVM *pThread;\n    struct SQClass *pClass;\n    struct SQInstance *pInstance;\n    struct SQWeakRef *pWeakRef;\n    SQRawObjectVal raw;\n}SQObjectValue;\n\n\ntypedef struct tagSQObject\n{\n    SQObjectType _type;\n    SQObjectFlags _flags;\n    SQObjectValue _unVal;\n}SQObject;\n\ntypedef struct  tagSQMemberHandle{\n    SQInteger _index;\n    uint8_t _static;\n    uint8_t _isNativeField;\n}SQMemberHandle;\n\ntypedef struct tagSQStackInfos{\n    const char* funcname;\n    const char* source;\n    SQInteger line;\n}SQStackInfos;\n\ntypedef enum tagSQMessageSeverity{\n    SEV_HINT,\n    SEV_WARNING,\n    SEV_ERROR,\n}SQMessageSeverity;\n\ntypedef struct SQVM* HSQUIRRELVM;\ntypedef SQObject HSQOBJECT;\ntypedef SQMemberHandle HSQMEMBERHANDLE;\ntypedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);\ntypedef SQInteger (*SQRELEASEHOOK)(HSQUIRRELVM vm,SQUserPointer,SQInteger size);\ntypedef void (*SQCOMPILERERROR)(HSQUIRRELVM,SQMessageSeverity /*severity*/,const char * /*desc*/,const char * /*source*/,SQInteger /*line*/,SQInteger /*column*/, const char * /*extra info*/);\ntypedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const char * ,...);\ntypedef void (*SQDEBUGHOOK)(HSQUIRRELVM /*v*/, SQInteger /*type*/, const char * /*sourcename*/, SQInteger /*line*/, const char * /*funcname*/);\ntypedef void (*SQCOMPILELINEHOOK)(HSQUIRRELVM /*v*/, const char * /*sourcename*/, SQInteger /*line*/);\ntypedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger);\ntypedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger);\ntypedef SQInteger (*SQGETTHREAD)();\ntypedef void (*SQSQCALLHOOK)(HSQUIRRELVM);\ntypedef bool (*SQWATCHDOGHOOK)(HSQUIRRELVM, bool kick);\n\ntypedef SQInteger (*SQLEXREADFUNC)(SQUserPointer);\n\ntypedef struct tagSQRegFunction{\n    const char *name;\n    SQFUNCTION f;\n    SQInteger nparamscheck;\n    const char *typemask;\n    const char *docstring;\n    bool pure;\n    bool nodiscard;\n}SQRegFunction;\n\ntypedef struct tagSQRegFunctionFromStr{\n    SQFUNCTION f;\n    const char *declstring;\n    const char *docstring;\n}SQRegFunctionFromStr;\n\ntypedef struct tagSQFunctionInfo {\n    SQUserPointer funcid;\n    const char *name;\n    const char *source;\n    SQInteger line;\n}SQFunctionInfo;\n\n#define BIT(n) (1ULL << (n))\n\nenum CompilationOptions : SQUnsignedInteger {\n  CO_CLOSURE_HOISTING_OPT = BIT(1)\n};\n\n#undef BIT\n\ntypedef struct tagSQCompilerMessage {\n  int intId;\n  const char* textId;\n  int line;\n  int column;\n  int columnsWidth;\n  const char* message;\n  const char* fileName;\n  bool isError;\n} SQCompilerMessage;\n\ntypedef void (*SQ_COMPILER_DIAG_CB)(HSQUIRRELVM v, const SQCompilerMessage *msg);\n\ntypedef struct tagSQModuleImportSlot {\n    const char *name;\n    const char *alias; // null if not specified\n    int line;\n    int column;\n} SQModuleImportSlot;\n\ntypedef struct tagSQModuleImport {\n    const char *name;\n    const char *alias; // null if not specified\n    int numSlots;\n    SQModuleImportSlot *slots;\n    int line;\n    int nameColumn;\n    int aliasColumn;\n} SQModuleImport;\n\n\n/*vm*/\nSQUIRREL_API HSQUIRRELVM sq_open(SQInteger initialstacksize);\nSQUIRREL_API HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize);\nSQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v);\nSQUIRREL_API HSQOBJECT sq_geterrorhandler(HSQUIRRELVM v);\nSQUIRREL_API void sq_close(HSQUIRRELVM v);\nSQUIRREL_API void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p);\nSQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v);\nSQUIRREL_API void sq_setsharedforeignptr(HSQUIRRELVM v,SQUserPointer p);\nSQUIRREL_API SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v);\nSQUIRREL_API void sq_setvmreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook);\nSQUIRREL_API SQRELEASEHOOK sq_getvmreleasehook(HSQUIRRELVM v);\nSQUIRREL_API void sq_setsharedreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook);\nSQUIRREL_API SQRELEASEHOOK sq_getsharedreleasehook(HSQUIRRELVM v);\nSQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc, SQPRINTFUNCTION errfunc);\nSQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v);\nSQUIRREL_API SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool invoke_err_handler,SQBool throwerror);\nSQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_registerbaselib(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_registertypeslib(HSQUIRRELVM v);\n\n/*compiler*/\nSQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v, const char *s, SQInteger size, const char *sourcename, SQBool raiseerror, const HSQOBJECT *bindings = nullptr);\n\nSQUIRREL_API SQCompilation::SqASTData *sq_parsetoast(HSQUIRRELVM v, const char *s, SQInteger size, const char *sourcename, SQBool preserveComments, SQBool raiseerror);\nSQUIRREL_API SQRESULT sq_translateasttobytecode(HSQUIRRELVM v, SQCompilation::SqASTData *astData, const HSQOBJECT *bindings, const char *s, SQInteger size, SQBool raiseerror);\nSQUIRREL_API void sq_analyzeast(HSQUIRRELVM v, SQCompilation::SqASTData *astData, const HSQOBJECT *bindings, const char *s, SQInteger size);\nSQUIRREL_API void sq_checktrailingspaces(HSQUIRRELVM v, const char *sourceName, const char *s, SQInteger size);\nSQUIRREL_API SQRESULT sq_getimports(HSQUIRRELVM v, SQCompilation::SqASTData *astData, SQInteger *num, SQModuleImport **imports);\nSQUIRREL_API void sq_freeimports(HSQUIRRELVM v, SQInteger num, SQModuleImport *imports);\n\n\nSQUIRREL_API void sq_dumpast(HSQUIRRELVM v, SQCompilation::SqASTData *astData, bool nodesLocation, OutputStream *s);\nSQUIRREL_API void sq_dumpbytecode(HSQUIRRELVM v, HSQOBJECT obj, OutputStream *s, int instruction_index = -1);\n\nSQUIRREL_API void sq_reset_static_memos(HSQUIRRELVM v, HSQOBJECT func);\n\nSQUIRREL_API SQCompilation::SqASTData *sq_allocateASTData(HSQUIRRELVM v);\nSQUIRREL_API void sq_releaseASTData(HSQUIRRELVM v, SQCompilation::SqASTData *astData);\n\nSQUIRREL_API void sq_setcompilationoption(HSQUIRRELVM v, enum CompilationOptions co, bool value);\nSQUIRREL_API bool sq_checkcompilationoption(HSQUIRRELVM v, enum CompilationOptions co);\nSQUIRREL_API void sq_enablevartrace(HSQUIRRELVM v, SQBool enable);\nSQUIRREL_API SQBool sq_isvartracesupported();\nSQUIRREL_API void sq_lineinfo_in_expressions(HSQUIRRELVM v, SQBool enable);\nSQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable);\nSQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);\nSQUIRREL_API void sq_setcompilerdiaghandler(HSQUIRRELVM v, SQ_COMPILER_DIAG_CB f);\nSQUIRREL_API SQCOMPILERERROR sq_getcompilererrorhandler(HSQUIRRELVM v);\n\n/*stack operations*/\nSQUIRREL_API void sq_push(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop);\nSQUIRREL_API void sq_poptop(HSQUIRRELVM v);\nSQUIRREL_API void sq_remove(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQInteger sq_gettop(HSQUIRRELVM v);\nSQUIRREL_API void sq_settop(HSQUIRRELVM v,SQInteger newtop);\nSQUIRREL_API SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize);\nSQUIRREL_API SQInteger sq_cmp(HSQUIRRELVM v);\nSQUIRREL_API bool sq_cmpraw(HSQUIRRELVM v, HSQOBJECT &lhs, HSQOBJECT &rhs, SQInteger &res);\nSQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx);\n\n/*object creation handling*/\nSQUIRREL_API SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size);\nSQUIRREL_API void sq_newtable(HSQUIRRELVM v);\nSQUIRREL_API void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity);\nSQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size);\nSQUIRREL_API SQRESULT sq_new_closure_slot_from_decl_string(HSQUIRRELVM v, SQFUNCTION func, SQUnsignedInteger nfreevars, const char *function_decl, const char *docstring);\nSQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars);\nSQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const char *typemask);\nSQUIRREL_API SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const char *s,SQInteger len);\nSQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f);\nSQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n);\nSQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b);\nSQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p);\nSQUIRREL_API void sq_pushnull(HSQUIRRELVM v);\nSQUIRREL_API void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread);\nSQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx);\nSQUIRREL_API SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b);\nSQUIRREL_API SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const char **c,SQInteger *size);\nSQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const char **c);\nSQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);\nSQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);\nSQUIRREL_API SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b);\nSQUIRREL_API SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread);\nSQUIRREL_API SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p);\nSQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag);\nSQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag);\nSQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag);\nSQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);\nSQUIRREL_API SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API char *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize);\nSQUIRREL_API SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi);\nSQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars);\nSQUIRREL_API SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const char *name);\nSQUIRREL_API SQRESULT sq_setnativeclosuredocstring(HSQUIRRELVM v,SQInteger idx,const char *docstring);\nSQUIRREL_API SQRESULT sq_setobjectdocstring(HSQUIRRELVM v, const HSQOBJECT *obj, const char *docstring);\nSQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p);\nSQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag);\nSQUIRREL_API SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize);\nSQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase);\nSQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle);\nSQUIRREL_API SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle);\nSQUIRREL_API SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle);\n\n/*native fields: direct access to C++ struct fields in inline userdata*/\n#define SQNFT_FLOAT32  0\n#define SQNFT_FLOAT64  1\n#define SQNFT_INT32    2\n#define SQNFT_INT64    3\n#define SQNFT_BOOL     4\nSQUIRREL_API SQRESULT sq_registernativefield(HSQUIRRELVM v, SQInteger classidx,\n    const char *name, SQInteger offset, SQInteger fieldtype);\n\n/*object manipulation*/\nSQUIRREL_API void sq_pushroottable(HSQUIRRELVM v);\nSQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v);\nSQUIRREL_API void sq_pushconsttable(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_setconsttable(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic); //-V1071\nSQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); //-V1071\nSQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\nSQUIRREL_API SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic);\nSQUIRREL_API SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval);\nSQUIRREL_API SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize);\nSQUIRREL_API SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx);\nSQUIRREL_API SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos);\nSQUIRREL_API SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);\nSQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx);\nSQUIRREL_API SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx,SQBool freemem = SQTrue);\nSQUIRREL_API SQRESULT sq_freeze(HSQUIRRELVM v, SQInteger idx);\nSQUIRREL_API SQRESULT sq_freeze_inplace(HSQUIRRELVM v, SQInteger idx);\nSQUIRREL_API SQRESULT sq_mark_pure_inplace(HSQUIRRELVM v, SQInteger idx);\nSQUIRREL_API bool sq_is_pure_function(HSQOBJECT *func);\n\n\n/*calls*/\nSQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool invoke_err_handler);\nSQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool invoke_err_handler);\nSQUIRREL_API const char *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);\nSQUIRREL_API SQRESULT sq_getcallee(HSQUIRRELVM v);\nSQUIRREL_API const char *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);\nSQUIRREL_API void sq_throwparamtypeerror(HSQUIRRELVM v, SQInteger nparam, SQInteger typemask, SQInteger type);\nSQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const char *err);\n// see also: sqstd_throwerrorf(HSQUIRRELVM v,const char *err,...)\nSQUIRREL_API SQRESULT sq_throwobject(HSQUIRRELVM v);\nSQUIRREL_API void sq_reseterror(HSQUIRRELVM v);\nSQUIRREL_API void sq_getlasterror(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams);\n\n/*raw object handling*/\nSQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po);//-V1071\nSQUIRREL_API void sq_pushobj(HSQUIRRELVM v,const HSQOBJECT *po);\n#ifdef __cplusplus\nstatic inline void sq_pushobject(HSQUIRRELVM v, const HSQOBJECT &o) { return sq_pushobj(v, &o); }\n#else\nstatic inline void sq_pushobject(HSQUIRRELVM v, HSQOBJECT o) { return sq_pushobj(v, &o); }\n#endif\nSQUIRREL_API void sq_addref_refcounted(HSQUIRRELVM v,HSQOBJECT *po);\nSQUIRREL_API SQBool sq_release_refcounted(HSQUIRRELVM v,HSQOBJECT *po);\nSQUIRREL_API SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po);\nstatic inline void sq_resetobject(HSQOBJECT *po)\n{\n#ifdef __cplusplus\n  static_assert((int)OT_NULL == 0);\n#endif\n  memset(po, 0, sizeof(*po));\n}\nSQUIRREL_API const char *sq_objtostring(const HSQOBJECT *o);\nSQUIRREL_API SQBool sq_objtobool(const HSQOBJECT *o);\nSQUIRREL_API SQBool sq_obj_is_true(const HSQOBJECT *o);\nSQUIRREL_API SQInteger sq_objtointeger(const HSQOBJECT *o);\nSQUIRREL_API SQFloat sq_objtofloat(const HSQOBJECT *o);\nSQUIRREL_API SQUserPointer sq_objtouserpointer(const HSQOBJECT *o);\nSQUIRREL_API SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag);\nSQUIRREL_API SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po);\nSQUIRREL_API const char* sq_objtypestr(SQObjectType tp);\nSQUIRREL_API SQRESULT sq_obj_get(HSQUIRRELVM v, const HSQOBJECT *obj, const HSQOBJECT *slot,\n                                    HSQOBJECT *out, bool raw);\n\nSQUIRREL_API SQBool sq_obj_cmp(HSQUIRRELVM v, const HSQOBJECT *a, const HSQOBJECT *b, SQInteger *res);\nSQUIRREL_API bool sq_obj_is_equal(HSQUIRRELVM v, const HSQOBJECT *a, const HSQOBJECT *b);\n\nSQUIRREL_API bool sq_fast_equal_by_value_deep(const HSQOBJECT *a, const HSQOBJECT *b, int depth);\n\nSQUIRREL_API SQRESULT sq_obj_getuserdata(const HSQOBJECT *obj, SQUserPointer *p, SQUserPointer *typetag);\nSQUIRREL_API SQInteger sq_obj_getsize(const HSQOBJECT *obj);\nSQUIRREL_API SQRESULT sq_obj_getinstanceup(const HSQOBJECT *obj, SQUserPointer *p,\n                                           SQUserPointer typetag);\nSQUIRREL_API SQRESULT sq_obj_set(HSQUIRRELVM v, const HSQOBJECT *obj,\n                                 const HSQOBJECT *key, const HSQOBJECT *val,\n                                 bool raw);\nSQUIRREL_API SQRESULT sq_obj_newslot(HSQUIRRELVM v, const HSQOBJECT *obj,\n                                     const HSQOBJECT *key, const HSQOBJECT *val,\n                                     bool bstatic);\nSQUIRREL_API void sq_getregistrytableobj(HSQUIRRELVM v, HSQOBJECT *out);\n\nSQUIRREL_API SQBool sq_tracevar(HSQUIRRELVM v, const HSQOBJECT * container, const HSQOBJECT * key, char * buf, int buf_size);\n\n/*GC*/\nSQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v);\nSQUIRREL_API SQRESULT sq_resurrectunreachable(HSQUIRRELVM v);\n\n/*serialization*/\nSQUIRREL_API SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up);\nSQUIRREL_API SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up);\n\nSQUIRREL_API SQRESULT sq_limitthreadaccess(HSQUIRRELVM vm, int64_t tid);\nSQUIRREL_API bool sq_canaccessfromthisthread(HSQUIRRELVM vm);\n\ntypedef struct SQAllocContextT * SQAllocContext;\nSQUIRREL_API SQAllocContext sq_getallocctx(HSQUIRRELVM v);\n\n/*mem allocation*/\nSQUIRREL_API void *sq_malloc(SQAllocContext ctx, SQUnsignedInteger size);\nSQUIRREL_API void *sq_realloc(SQAllocContext ctx, void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize);\nSQUIRREL_API void sq_free(SQAllocContext ctx, void *p,SQUnsignedInteger size);\n\n/*debug*/\nSQUIRREL_API SQRESULT sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si);\nSQUIRREL_API void sq_setdebughook(HSQUIRRELVM v);\nSQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook);\nSQUIRREL_API SQGETTHREAD sq_set_thread_id_function(HSQUIRRELVM v, SQGETTHREAD func);\nSQUIRREL_API SQSQCALLHOOK sq_set_sq_call_hook(HSQUIRRELVM v, SQSQCALLHOOK hook);\nSQUIRREL_API SQCOMPILELINEHOOK sq_set_compile_line_hook(HSQUIRRELVM v, SQCOMPILELINEHOOK hook);\nSQUIRREL_API void sq_forbidglobalconstrewrite(HSQUIRRELVM v, SQBool on);\n\n/*watchdog*/\nSQUIRREL_API SQWATCHDOGHOOK sq_set_watchdog_hook(HSQUIRRELVM v, SQWATCHDOGHOOK hook);\nSQUIRREL_API void sq_kick_watchdog(HSQUIRRELVM v);\nSQUIRREL_API SQInteger sq_set_watchdog_timeout_msec(HSQUIRRELVM v, SQInteger timeout);\n\n/*static analysis*/\nSQUIRREL_API void sq_resetanalyzerconfig();\nSQUIRREL_API bool sq_loadanalyzerconfig(const char *configFileName);\nSQUIRREL_API bool sq_loadanalyzerconfigblk(const KeyValueFile &config);\n\nSQUIRREL_API bool sq_setdiagnosticstatebyname(const char *diagId, bool val);\nSQUIRREL_API bool sq_setdiagnosticstatebyid(int32_t id, bool val);\nSQUIRREL_API void sq_printwarningslist(FILE *ostream);\nSQUIRREL_API void sq_enablesyntaxwarnings(bool on);\nSQUIRREL_API void sq_checkglobalnames(HSQUIRRELVM v);\nSQUIRREL_API void sq_mergeglobalnames(const HSQOBJECT *bindings);\n\n\n/*UTILITY MACRO*/\n#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC)\n#define sq_istable(o) ((o)._type==OT_TABLE)\n#define sq_isarray(o) ((o)._type==OT_ARRAY)\n#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO)\n#define sq_isclosure(o) ((o)._type==OT_CLOSURE)\n#define sq_isgenerator(o) ((o)._type==OT_GENERATOR)\n#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE)\n#define sq_isstring(o) ((o)._type==OT_STRING)\n#define sq_isinteger(o) ((o)._type==OT_INTEGER)\n#define sq_isfloat(o) ((o)._type==OT_FLOAT)\n#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER)\n#define sq_isuserdata(o) ((o)._type==OT_USERDATA)\n#define sq_isthread(o) ((o)._type==OT_THREAD)\n#define sq_isnull(o) ((o)._type==OT_NULL)\n#define sq_isclass(o) ((o)._type==OT_CLASS)\n#define sq_isinstance(o) ((o)._type==OT_INSTANCE)\n#define sq_isbool(o) ((o)._type==OT_BOOL)\n#define sq_isweakref(o) ((o)._type==OT_WEAKREF)\n#define sq_type(o) ((o)._type)\n#define sq_objflags(o) ((o)._flags)\n\n#define SQ_OK (0)\n#define SQ_ERROR (-1)\n\n#define SQ_FAILED(res) ((res)<0)\n#define SQ_SUCCEEDED(res) ((res)>=0)\n\n#if defined(__GNUC__) || defined(__clang__)\n# define SQ_UNUSED_ARG(x) x __attribute__((__unused__))\n#else\n# define SQ_UNUSED_ARG(x)\n#endif\n\n#ifdef __cplusplus\n} /*extern \"C\"*/\n#endif\n\nstatic inline void sq_addref(HSQUIRRELVM v,HSQOBJECT *po)\n{\n  if (ISREFCOUNTED(sq_type(*po)))\n    sq_addref_refcounted(v, po);\n}\n\nstatic inline SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)\n{\n  return !ISREFCOUNTED(sq_type(*po)) || sq_release_refcounted(v, po);\n}\n\n/*\n  Removed SQObjectPtr overload to forbid dangerous cast to SQObjectPtr.\n  Passing SQObjectPtr instead of SQObject to some quirrel API functions can cause\n  unwanted call of extra Release() which may lead to memory corruption.\n  This function is explicitly deleted to prevent such errors.\n*/\nstruct SQObjectPtr;\nSQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx, SQObjectPtr *po) = delete;\nSQUIRREL_API SQRESULT sq_obj_get(HSQUIRRELVM v, const HSQOBJECT *obj, const HSQOBJECT *slot,\n                                    SQObjectPtr *out, bool raw) = delete;\n\n#endif /*_SQUIRREL_H_*/\n"
  },
  {
    "path": "internal/sq_safe_shift.h",
    "content": "#pragma once\n#ifndef SQ_SAFE_SHIFT_H\n#define SQ_SAFE_SHIFT_H\n\n#include <sqconfig.h>\n\n#include <limits>\n#include <type_traits>\n\nstatic constexpr unsigned SQ_INTEGER_BITS = std::numeric_limits<SQUnsignedInteger>::digits;\nstatic constexpr unsigned SQ_INTEGER_MASK = SQ_INTEGER_BITS - 1;\n\n\ninline SQInteger sq_safe_shift_left(SQInteger x, SQInteger y)\n{\n    SQUnsignedInteger ux = (SQUnsignedInteger)x;\n    SQUnsignedInteger uy = (SQUnsignedInteger)y;\n    SQUnsignedInteger neg = uy >> (SQ_INTEGER_BITS - 1);\n    SQUnsignedInteger neg_mask = ~neg + 1u;  // == -neg without C4146\n    SQUnsignedInteger sh  = (uy ^ neg_mask) + neg;\n\n    SQUnsignedInteger overflow = ~SQUnsignedInteger(sh >= SQ_INTEGER_BITS) + 1u;\n\n    SQUnsignedInteger l = ux << (sh & SQ_INTEGER_MASK);\n    SQUnsignedInteger r = ux >> (sh & SQ_INTEGER_MASK);\n\n    // Arithmetic sign extension for reversed right shift (negative y)\n    SQUnsignedInteger sign = ~SQUnsignedInteger(x < 0) + 1u;\n    SQUnsignedInteger sign_ext = sign ^ (sign >> (sh & SQ_INTEGER_MASK));\n    r |= sign_ext;\n\n    SQUnsignedInteger res = (l & ~neg_mask) | (r & neg_mask);\n\n    // On overflow: 0 for left shift (positive y), sign-fill for reversed right shift (negative y)\n    SQUnsignedInteger fill = sign & neg_mask & overflow;\n    res = (res & ~overflow) | fill;\n\n    return (SQInteger)res;\n}\n\n\ninline SQInteger sq_safe_shift_right(SQInteger x, SQInteger y)\n{\n    SQUnsignedInteger ux = (SQUnsignedInteger)x;\n    SQUnsignedInteger uy = (SQUnsignedInteger)y;\n\n    SQUnsignedInteger neg = uy >> (SQ_INTEGER_BITS - 1);\n    SQUnsignedInteger neg_mask = ~neg + 1u;\n    SQUnsignedInteger sh  = (uy ^ neg_mask) + neg;\n\n    SQUnsignedInteger overflow = ~SQUnsignedInteger(sh >= SQ_INTEGER_BITS) + 1u;\n\n    SQUnsignedInteger r = ux >> (sh & SQ_INTEGER_MASK);\n    SQUnsignedInteger l = ux << (sh & SQ_INTEGER_MASK);\n\n    // Arithmetic sign extension: fill top sh bits of r with sign bit\n    SQUnsignedInteger sign = ~SQUnsignedInteger(x < 0) + 1u;\n    SQUnsignedInteger sign_ext = sign ^ (sign >> (sh & SQ_INTEGER_MASK));\n    r |= sign_ext;\n\n    SQUnsignedInteger dir = (r & ~neg_mask) | (l & neg_mask);\n\n    SQUnsignedInteger fill = sign & overflow;\n\n    return (SQInteger)((dir & ~overflow) | fill);\n}\n\n\ninline SQInteger sq_safe_unsigned_shift_right(SQInteger x, SQInteger y)\n{\n    SQUnsignedInteger ux = (SQUnsignedInteger)x;\n    SQUnsignedInteger uy = (SQUnsignedInteger)y;\n\n    SQUnsignedInteger neg = uy >> (SQ_INTEGER_BITS - 1);\n    SQUnsignedInteger neg_mask = ~neg + 1u;\n    SQUnsignedInteger sh  = (uy ^ neg_mask) + neg;\n\n    SQUnsignedInteger overflow = ~SQUnsignedInteger(sh >= SQ_INTEGER_BITS) + 1u;\n\n    SQUnsignedInteger r = ux >> (sh & SQ_INTEGER_MASK);\n    SQUnsignedInteger l = ux << (sh & SQ_INTEGER_MASK);\n\n    SQUnsignedInteger res = (r & ~neg_mask) | (l & neg_mask);\n\n    res &= ~overflow;\n\n    return (SQInteger)res;\n}\n\n#endif // SQ_SAFE_SHIFT_H\n"
  },
  {
    "path": "internal/sqstringlib.h",
    "content": "#pragma once\n\n#include <squirrel.h>\n\nSQInteger _sq_string_strip_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\nSQInteger _sq_string_lstrip_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\nSQInteger _sq_string_rstrip_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\nSQInteger _sq_string_split_by_chars_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\nSQInteger _sq_string_escape_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\nSQInteger _sq_string_startswith_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\nSQInteger _sq_string_endswith_impl(HSQUIRRELVM v, SQInteger arg_stack_start);\n"
  },
  {
    "path": "scripts/samples/ackermann.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\n\nlet {max} = require(\"math\")\n\nfunction Ack(M, N) {\n    if (M == 0) return N + 1\n    if (N == 0) return Ack(M-1, 1)\n    return Ack(M - 1, Ack(M, (N-1)))\n}\n\nlocal n\n\nif(vargv.len()!=0) {\n  n = max(1, vargv[0].tointeger())\n} else {\n  n = 1\n}\n\nprintln($\"n={n}\")\nprintln($\"Ack(3,{n}):{Ack(3, n)}\")\n"
  },
  {
    "path": "scripts/samples/array.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\nlocal n, i, k\n\nif (vargv.len()!=0) {\n  n = ::max(1, vargv[0].tointeger())\n} else {\n  n = 1\n}\n\nlet x = array(n)\nlet y = array(n)\n\nfor (i = 0; i < n; i+=1) {\n  x[i] = i + 1\n  y[i] = 0\n}\n\nfor (k = 0 ; k < n; k+=1) {\n  for (i = n-1; i >= 0; i-=1) {\n    y[i] = y[i]+ x[i]\n  }\n}\n\nprintln($\"{y[0]} {y[n-1]}\")\n\n"
  },
  {
    "path": "scripts/samples/class.nut",
    "content": "class BaseVector {\n    constructor(...)     {\n        if (vargv.len() >= 3) {\n            this.x = vargv[0]\n            this.y = vargv[1]\n            this.z = vargv[2]\n        }\n    }\n\n    x = 0\n    y = 0\n    z = 0\n}\n\nclass Vector3(BaseVector) {\n    function _add(other) {\n        local cls = this.getclass()\n        if (other instanceof cls)\n            return cls(this.x+other.x, this.y+other.y, this.z+other.z)\n        else\n            throw \"wrong parameter\"\n    }\n\n    function Print() {\n        println($\"{this.x}, {this.y}, {this.z}\")\n    }\n}\n\nlet v0 = Vector3(1,2,3)\nlet v1 = Vector3(11,12,13)\nlet v2 = v0 + v1\nv2.Print()\n"
  },
  {
    "path": "scripts/samples/fibonacci.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\n\nfunction fib(n) {\n    if (n < 2) return 1\n    return fib(n-2) + fib(n-1)\n}\n\nlocal n = vargv.len()!=0 ? vargv[0].tointeger() : 1\n\nprintln(fib(n))\n"
  },
  {
    "path": "scripts/samples/flow.nut",
    "content": "#allow-switch-statement\n\nlet {min, max} = require(\"math\")\n\nif (min(100,200) > max(50,20))\n    println(\"I'm useless statement just to show up the if/else\")\nelse\n    println(\"squirrel!!\")\n\nprint(\"\\n\")\n\nfunction typy(obj) {\n    switch(typeof obj) {\n        case \"integer\":\n        case \"float\":\n            return \"is a number\"\n        case \"table\":\n        case \"array\":\n            return \"is a container\"\n        default:\n            return \"is other stuff\"\n    }\n}\n\nlet a=1, b={}\nfunction c(a,b){return a+b}\n\nprintln($\"a {typy(a)}\")\nprintln($\"b {typy(b)}\")\nprintln($\"c {typy(c)}\")\n"
  },
  {
    "path": "scripts/samples/generators.nut",
    "content": "/*\n*Random number function from The Great Computer Language shootout\n*converted to a generator func\n*/\n\nfunction gen_random(max) {\n    local last=42\n    local IM = 139968\n    local IA = 3877\n    local IC = 29573\n    for (;;) {  //loops forever\n        last = (last * IA + IC) % IM\n        yield (max * last / IM)\n    }\n}\n\nlet randtor = gen_random(100)\n\nprintln(\"RAND NUMBERS\")\n\nfor (local i=0;i<10;i+=1)\n    println($\"> {resume randtor}\")\n\nprintln(\"FIBONACCI\")\n\nfunction fiboz(n) {\n    local prev=0\n    local curr=1\n    yield 1\n\n    for (local i=0;i<n-1;++i) {\n        let res=prev+curr\n        prev=curr\n        curr=res\n        yield curr\n    }\n    return prev+curr\n}\n\nforeach (val in fiboz(10)) {\n    println($\"> {val}\")\n}\n"
  },
  {
    "path": "scripts/samples/hello.nut",
    "content": "println(\"Hello World!\")\n"
  },
  {
    "path": "scripts/samples/list.nut",
    "content": "/*translation of the list test from The Great Computer Language Shootout\n*/\n\nfunction compare_arr(a1,a2) {\n    foreach(i,val in a1)\n        if(val!=a2[i])\n          return null\n    return 1\n}\n\nfunction test() {\n    let size=10000\n    let l1 = array(size)\n    for (local i=0; i<size; ++i)\n      l1[i]=i\n    let l2=clone l1\n    let  l3=[]\n\n    l2.reverse()\n    while(l2.len()>0)\n        l3.append(l2.pop())\n    while(l3.len()>0)\n        l2.append(l3.pop())\n    l1.reverse()\n\n    if (compare_arr(l1,l2))\n        return l1.len()\n    return null\n}\n\nlet n = vargv.len()!=0?vargv[0].tointeger():1\n\nfor(local i=0;i<n;++i) {\n    if(!test()) {\n        println(\"failed\")\n        return\n    }\n}\n\nprintln(\"oki doki\")\n"
  },
  {
    "path": "scripts/samples/loops.nut",
    "content": "let arr=[\"one\",\"two\",\"three\"]\n\nprint(\"FOREACH\\n\")\n\nforeach (i,val in arr) {\n    println($\"index [{i}]={val}\")\n}\n\nprintln(\"FOR\")\n\nlocal i\nfor(i=0;i<arr.len();++i){\n    println($\"index [{i}]={arr[i]}\")\n}\n\nprintln(\"WHILE\")\n\ni=0\nwhile(i<arr.len()) {\n    println($\"index [{i}]={arr[i]}\")\n    ++i\n}\n\nprintln(\"DO WHILE\");\n\ni=0\ndo {\n    println($\"index [{i}]={arr[i]}\")\n    ++i\n}while(i<arr.len())\n"
  },
  {
    "path": "scripts/samples/matrix.nut",
    "content": "/*\n*\n* Original Javascript version by David Hedbor(http://www.bagley.org/~doug/shootout/)\n*\n*/\nconst SIZE=30\n\nfunction mkmatrix(rows, cols) {\n  local count = 1\n  let m = array(rows)\n  for (local i = 0; i < rows; ++i) {\n    m[i] = array(cols)\n    for (local j = 0; j < cols; ++j) {\n      ++count\n      m[i][j] = count\n    }\n  }\n  return m\n}\n\nfunction mmult(rows, cols, m1, m2, m3) {\n  for (local i = 0; i < rows; ++i) {\n    for (local j = 0; j < cols; ++j) {\n      local val = 0\n      for (local k = 0; k < cols; ++k) {\n        val += m1[i][k] * m2[k][j]\n      }\n      m3[i][j] = val\n    }\n  }\n  return m3\n}\n\nlet n = vargv.len()!=0?vargv[0].tointeger():1\n\nlet m1 = mkmatrix(SIZE, SIZE)\nlet m2 = mkmatrix(SIZE, SIZE)\nlet mm = mkmatrix(SIZE, SIZE)\n\nfor (local i = 0; i < n; i+=1) {\n  mmult(SIZE, SIZE, m1, m2, mm)\n}\n\nprintln(mm[0][0]+\" \"+mm[2][3]+\" \"+mm[3][2]+\" \"+mm[4][4])\n"
  },
  {
    "path": "scripts/samples/metamethods.nut",
    "content": "class Vector {\n    x = 0\n    y = 0\n    z = 0\n    constructor(x, y, z) {\n        this.x = x\n        this.y = y\n        this.z = z\n    }\n    function _add(n) {\n        return this.getclass()(this.x+n.x, this.y+n.y, this.z+n.z)\n    }\n\n    function _sub(n) {\n        return this.getclass()(this.x-n.x, this.y-n.y, this.z-n.z)\n    }\n\n    function _div(n) {\n        return this.getclass()(this.x/n.x, this.y/n.y, this.z/n.z)\n    }\n\n    function _mul(n) {\n        return this.getclass()(this.x*n.x, this.y*n.y, this.z*n.z)\n    }\n\n    function _modulo(n) {\n        return this.getclass()(this.x%n, this.y%n, this.z%n)\n    }\n    \n    function _typeof() {\n        return \"Vector\"\n    }\n}\n\n\n////////////////////////////////////////////////////////////\n\nlet v1=Vector(1.5,2.5,3.5)\nlet v2=Vector(1.5,2.5,3.5)\n\nlocal r=v1+v2\n\nforeach(i,val in r) {\n    println($\"{i} = {val}\")\n}\n\nr=v1*v2\n\nforeach(i,val in r) {\n    println($\"{i} = {val}\")\n}\n\nr=v1/v2\n\nforeach(i,val in r) {\n    println($\"{i} = {val}\")\n}\n\nr=v1-v2\n\nforeach(i,val in r) {\n    println($\"{i} = {val}\")\n}\n\nr=v1%2\n\nforeach(i,val in r) {\n    println($\"{i} = {val}\")\n}\n\nif (typeof v1==\"Vector\")\n    println(\"<SUCCEEDED>\")\nelse\n    println(\"<FAILED>\")\n"
  },
  {
    "path": "scripts/samples/methcall.nut",
    "content": "/*translation of the methcall test from The Great Computer Language Shootout\n*/\n\nlet datetime = require(\"datetime\")\n\nclass Toggle {\n    bool=null\n\n    constructor(startstate) {\n        this.bool = startstate\n    }\n\n    function value() {\n        return this.bool\n    }\n\n    function activate() {\n        this.bool = !this.bool\n        return this\n    }\n}\n\n\nclass NthToggle(Toggle) {\n    count_max=null\n    count=0\n\n    constructor(start_state, max_counter) {\n        base.constructor(start_state)\n        this.count_max = max_counter\n    }\n\n    function activate() {\n        ++this.count\n        if (this.count >= this.count_max) {\n          base.activate()\n          this.count = 0\n        }\n        return this\n    }\n}\n\n\n\nlocal function main() {\n    let n = vargv.len()!=0?vargv[0].tointeger():1\n\n    local val = 1\n    let  toggle = Toggle(val)\n    local i = n\n    while(i--) {\n      val = toggle.activate().value()\n    }\n    println(toggle.value() ? \"true\" : \"false\")\n\n    val = 1\n    local ntoggle = NthToggle(val, 3)\n    i = n\n    while(i--) {\n      val = ntoggle.activate().value()\n    }\n    println(ntoggle.value() ? \"true\" : \"false\")\n\n}\n\nlet start=datetime.clock()\nmain()\nprintln(\"TIME=\"+(datetime.clock()-start))\n"
  },
  {
    "path": "scripts/samples/module_1.nut",
    "content": "function foo() {\n  return \"<call from module>\"\n}\n\nreturn foo\n"
  },
  {
    "path": "scripts/samples/module_2.nut",
    "content": "let exports = {\n  bar = \"BAR\"\n  baz = \"BAZ\"\n}\n\nreturn exports\n"
  },
  {
    "path": "scripts/samples/module_demo.nut",
    "content": "let foo = require(\"module_1.nut\")\nlet {bar, baz} = require(\"module_2.nut\")\n\nprintln($\"foo() result = {foo()}\")\nprintln($\"bar = {bar}, baz = {baz}\")\n"
  },
  {
    "path": "scripts/samples/regex.nut",
    "content": "let string = require(\"string\")\n\n{\n  let ex = string.regexp(\"[a-zA-Z]+\")\n  let s = \"123 Test; strlen(str);\"\n  let res = ex.search(s)\n  println(s.slice(res.begin,res.end)) //prints \"Test\"\n}\n\n{\n  let ex = string.regexp(@\"\\m()\");\n  let s = \"123 Test; doSomething(str, getTemp(), (a+(b/c)));\"\n  let res = ex.search(s)\n  println(s.slice(res.begin,res.end)) //prints \"(...)\"\n}"
  },
  {
    "path": "scripts/samples/tailstate.nut",
    "content": "local state1, state2, state3\n\nstate1 = function state1() {\n    suspend(\"state1\")\n    return state2()\n}\n\nstate2 = function state2() {\n    suspend(\"state2\")\n    return state3()\n}\n\nstate3 = function state3() {\n    suspend(\"state3\")\n    return state1()\n}\n\nlet statethread = newthread(state1)\n\nprintln(statethread.call())\n\nfor (local i = 0; i < 10000; i++)\n    println(statethread.wakeup())\n"
  },
  {
    "path": "scripts/std/analyzer.nut",
    "content": "\nfunction dynamic_content(o) {\n  assert(type(o) == \"table\", $\"expected table in dynamic_content(), got '{type(o)}'\")\n  o.__dynamic_content__ <- true\n  return o\n}\n\nreturn { dynamic_content }\n"
  },
  {
    "path": "scripts/std/functools.nut",
    "content": "local abs = @(v) v> 0 ? v.tointeger() : -v.tointeger()\n\nlocal callableTypes = [\"function\",\"table\",\"instance\"]\nlocal function isCallable(v) {\n  return callableTypes.indexof(::type(v)) != null && (v.getfuncinfos() != null)\n}\n/*\n+ partial:\n  partial(f(x,y,z), 1) == @(y,z) f(1,y,z)\n  partial(f(x,y,z), 1, 2) == @(z) f(1,2,z)\n  partial(f(x,y,z), 1, 2, 3) == @() f(1,2,3) or f(1,2,3)\n*/\nlocal function partial(func, ...){\n  ::assert(isCallable(func), \"partial can be applied only to functions as first arguments\")\n  local infos = func.getfuncinfos()\n  local argsnum = infos.parameters.len()-1\n  local isvargved = infos.varargs==1\n  local pargs = vargv\n  local pargslen = pargs.len()\n  if ( (pargslen == argsnum) && !isvargved) {\n    return function(){\n      return func.acall([null].extend(pargs))\n    }\n  }\n  if ( (pargslen <= argsnum) || isvargved) {\n    return function(...){\n      return func.acall([null].extend(pargs).extend(vargv))\n    }\n  }\n  ::assert(false, @() $\"function '{infos.name}' cannot be partial with more arguments({pargslen}) that it accepts({argsnum})\")\n  return func\n}\n\n/*\n kwarg function:\n  foo(x,y,z)\n  kwarg(foo)==@(p) (foo(p?.x, p?.y, p?.z))\n  foo(x,y,z=2)\n  kwarg(foo)==@(p) (foo(p?.x, p?.y, p?.z ?? 2))\n*/\nlocal function kwarg(func){\n  ::assert(isCallable(func), \"kwarg can be applied only to functions as first arguments\")\n  local infos = func.getfuncinfos()\n  local funcargs = infos.parameters.slice(1)\n  local defargs = infos.defparams\n  local argsnum = funcargs.len()\n  local isvargved = infos.varargs==1\n  local kfuncargs = {}\n  local mandatoryparams = []\n  local defparamsStartFrom = argsnum-defargs.len()\n  foreach (idx, arg in funcargs) {\n    if (idx >= defparamsStartFrom) {\n      kfuncargs[arg] <- defargs[idx-defparamsStartFrom]\n    }\n    else{\n      kfuncargs[arg] <-null\n      mandatoryparams.append(arg)\n    }\n  }\n  return !isvargved\n    ? function(params=kfuncargs){\n        ::assert([\"table\", \"class\",\"instance\"].indexof(::type(params))!=null, @() $\"param of function can be only hashable (table, class, instance), found:'{::type(params)}'\")\n        local keys = params.keys()\n        local nonManP = mandatoryparams.filter(@(p) keys.indexof(p) == null)\n        ::assert(nonManP.len()==0, @() \"not all mandatory parameters provided: {0}\".subst(nonManP.len()==1 ? $\"'{nonManP[0]}'\" : nonManP.reduce(@(a,b) $\"{a},'{b}'\")))\n        params = kfuncargs.__merge(params)\n        local posarguments = funcargs.map(@(kv) params[kv])\n        return func.acall([this].extend(posarguments))\n      }\n    : function(params, ...){\n        ::assert([\"table\", \"class\",\"instance\"].indexof(::type(params))!=null, @() $\"param of function can be only hashable (table, class, instance), found:'{::type(params)}'\")\n        local keys = params.keys()\n        local nonManP = mandatoryparams.filter(@(p) keys.indexof(p) == null)\n        ::assert(nonManP.len()==0, @() \"not all mandatory parameters provided: {0}\".subst(nonManP.len()==1 ? $\"'{nonManP[0]}'\" : nonManP.reduce(@(a,b) $\"{a},'{b}'\")))\n        local posarguments = funcargs.map(@(kv) params[kv])\n        return func.acall([this].extend(posarguments).extend(vargv))\n      }\n}\n\n/*\n kwpartial\n  local function foo(a,b,c){(a+b)*c}\n  partial(foo, {b=3})(1,5) == (1+3)*5\n  partial(foo, {b=3}, 2)(5) == (2+3)*5\n*/\nlocal function kwpartial(func, partparams, ...){\n  ::assert(isCallable(func), \"partial can be applied only to functions as first arguments\")\n  ::assert([\"table\", \"class\",\"instance\"].indexof(::type(partparams))!=null, \"kwpartial second argument of function can be only hashable (table, class, instance)\")\n  local infos = func.getfuncinfos()\n  local funcargs = infos.parameters.slice(1)\n//  local defargs = infos.defparams\n  local argsnum = funcargs.len()\n  local posfuncargs = {}\n  local partvargs = vargv\n  foreach (p, v in partparams){\n    local posidx = funcargs.indexof(p)\n    if (posidx == null)\n      continue\n    posfuncargs[posidx] <- v\n  }\n  return function(...){\n    local curargs = partvargs.extend(vargv)\n    ::assert(curargs.len()+posfuncargs.len()>=argsnum, @() $\"not enough arguments provided for function '{infos?.name}' to call\")\n    local finalargs = []\n    local provArgIdx = 0\n    for (local i=0; i<argsnum; i++) {\n      if (i in posfuncargs) {\n        finalargs.append(posfuncargs[i])\n      }\n      else {\n        finalargs.append(curargs[provArgIdx])\n        provArgIdx++\n      }\n    }\n    return func.acall([this].extend(finalargs))\n  }\n}\n\n// pipe:\n//  pipe(f,g) =  @(x) f(g(x))\nlocal function pipe(...){\n  local args = vargv.filter(isCallable)\n  ::assert(args.len() == vargv.len() && args.len()>0, \"pipe should be called with functions\")\n  local finfos = args[0].getfuncinfos()\n  local numarg = (finfos.native ? abs(finfos.paramscheck) : finfos.parameters.len()) - 1\n  local isvargved = finfos.native ? finfos.paramscheck < -2 : finfos.varargs==1\n  ::assert(numarg == 1 && !isvargved, \"pipe cannot be applied to vargv function call or multiarguments function call\")\n  return function(x){\n    foreach(v in args)\n      x = v(x)\n    return x\n  }\n}\n\n// compose (reverse to pipe):\n//  compose(f,g) =  @(x) g(f(x))\nlocal function compose(...){\n  local args = vargv.filter(isCallable).reverse()\n  ::assert(args.len() == vargv.len() && args.len()>0, \"compose should be called with functions\")\n\n  local finfos = args[0].getfuncinfos()\n  local numarg = (finfos.native ? abs(finfos.paramscheck) : finfos.parameters.len()) - 1\n  local isvargved = finfos.native ? finfos.paramscheck < -2 : finfos.varargs==1\n  ::assert(numarg == 1 && !isvargved, \"compose cannot be applied to vargv function call or multiarguments function call\")\n  return function(x){\n    foreach(v in args)\n      x = v(x)\n    return x\n  }\n}\n\n/*\n (un)curry:\n  cf = curry(f) == @(x) @(y) @(z) f(x,y,z)\n  f(x,y,z) = cf(x)(y)(z)\n  cf(x) == @(y) @(z) f(x,y,z)\n  local get = curry(function(property, object){ return object?[property] })\n  local map = curry(function(fn, value){ return value.map(fn) })\n\n  local objects = [{ id = 1 }, { id = 2 }, { id = 3 }]\n  local getIDs = map(get(\"id\"))\n\n  log(objects.map(get(\"id\"))) //= [1, 2, 3]\n  log(objects.map(@(v) v?.id)) //= [1, 2, 3]\n  log(getIDs(objects)) //= [1, 2, 3]\n\nalso our curry is (un)curry - so\nlocal sum = curry(@(a,b,c) a+b+c)\nsum(1)(2)(3) == sum(1)(2,3) == sum(1,2,3) == sum(1,2)(3)\nunfortunately returning function are now use vargv, instead of rest of parameters (the same issue goes to partial)\n*/\nlocal function curry(fn) {\n  local finfos = fn.getfuncinfos()\n  ::assert(!finfos.native || finfos.paramscheck >= 0, \"Cannot curry native function with varargs\")\n  local arity = (finfos.native ? finfos.paramscheck : finfos.parameters.len())-1\n\n  return function f1(...) {\n    local args = vargv\n    if (args.len() >= arity) {\n      return fn.acall([this].extend(args))\n    } else {\n      local fone = f1\n      return function(...) {\n        local moreArgs = vargv\n        local newArgs = clone args\n        newArgs.extend(moreArgs)\n        return fone.acall([this].extend(newArgs))\n      }\n    }\n  }\n}\n\n/**\n* memoize(function, [hashFunction])\n  Memoizes a given function by caching the computed result. Useful for speeding up slow-running computations.\n  If passed an optional hashFunction, it will be used to compute the hash key for storing the result, based on the arguments to the original function.\n  The default hashFunction just uses the first argument to the memoized function as the key.\n*/\n\nlocal function memoize(func, hashfunc=null){\n  local cacheDefault = {}\n  local cacheForNull = {}\n  local parameters = func.getfuncinfos().parameters.slice(0)\n  ::assert(parameters.len()>0)\n  hashfunc = hashfunc ?? function(...) {\n    return vargv[0]\n }\n  local function memoizedfunc(...){\n    local args = [null].extend(vargv)\n    local rawHash = hashfunc.acall(args)\n    //index cannot be null. use different cache to avoid collision\n    local hash = rawHash ?? 0\n    local cache = rawHash != null ? cacheDefault : cacheForNull\n    if (hash in cache) {\n      return cache[hash]\n    }\n    local result = func.acall(args)\n    cache[hash] <- result\n    return result\n  }\n  return memoizedfunc\n}\n//the same function as in underscore.js\n//Creates a version of the function that can only be called one time.\n//Repeated calls to the modified function will have no effect, returning the value from the original call.\n//Useful for initialization functions, instead of having to set a boolean flag and then check it later.\nlocal function once(func){\n  local result\n  local called = false\n  local function memoizedfunc(...){\n    if (called)\n      return result\n    local res = func.acall([null].extend(vargv))\n    result = res\n    called = true\n    return res\n  }\n  return memoizedfunc\n}\n\n//the same function as in underscore.js\n//Creates a version of the function that can be called no more than count times.\n//The result of the last function call is memoized and returned when count has been reached.\nlocal function before(count, func){\n  local called = 0\n  local res\n  return function beforeTimes(...){\n    if (called >= count)\n      return res\n    called++\n    res = func.acall([null].extend(vargv))\n    return res\n  }\n}\n\n//the same function as in underscore.js\n//Creates a version of the function that will only be run after being called count times.\n//Useful for grouping asynchronous responses, where you want to be sure that all the async calls have finished, before proceeding.\nlocal function after(count, func){\n  local called = 0\n  return function beforeTimes(...){\n    if (called < count) {\n      called++\n      return\n    }\n    return func.acall([null].extend(vargv))\n  }\n}\n\nreturn {\n  partial = partial\n  pipe = pipe\n  compose = compose\n  kwarg = kwarg\n  kwpartial = kwpartial\n  curry = curry\n  memoize = memoize\n  isCallable = isCallable\n  once = once\n  before = before\n  after = after\n}"
  },
  {
    "path": "sq/CMakeLists.txt",
    "content": "add_executable(sq sq.cpp sq_test_natives.cpp)\n\ntarget_link_libraries(sq squirrel sqstdlib sqmodules quirrel-compiler)\ntarget_include_directories(sq PRIVATE\n  # include/ and sqmodules/ are transitive from linked libraries\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sqrat/include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/squirrel>\" # Needed for sqtypeparser.h\n  )\n"
  },
  {
    "path": "sq/sq.cpp",
    "content": "/*  see copyright notice in squirrel.h */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n#include <ctype.h>\n#include <string>\n#include <vector>\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n#include <crtdbg.h>\n#include <conio.h>\n#endif\n#include <squirrel.h>\n#include <sqstdblob.h>\n#include <sqstdsystem.h>\n#include <sqstddatetime.h>\n#include <sqstdio.h>\n#include <sqstdmath.h>\n#include <sqstdstring.h>\n#include <sqstdaux.h>\n#include <sqmodules.h>\n#include <sqio.h>\n#include <sqstddebug.h>\n#include <compiler/sqtypeparser.h>\n\n#define scvprintf vfprintf\n\n\nstatic SqModules *module_mgr = nullptr;\nstatic DefSqModulesFileAccess file_access;\nstatic bool check_stack_mode = false;\n\n\nvoid PrintVersionInfos();\n\nvoid printfunc(HSQUIRRELVM SQ_UNUSED_ARG(v),const char *s,...)\n{\n    va_list vl;\n    va_start(vl, s);\n    scvprintf(stdout, s, vl);\n    va_end(vl);\n}\n\nstatic FILE *errorStream = stderr;\n\nvoid errorfunc(HSQUIRRELVM SQ_UNUSED_ARG(v),const char *s,...)\n{\n    va_list vl;\n    va_start(vl, s);\n    scvprintf(errorStream, s, vl);\n    va_end(vl);\n}\n\nvoid PrintVersionInfos()\n{\n    fprintf(stdout,\"%s %s (%d bits)\\n\",SQUIRREL_VERSION,SQUIRREL_COPYRIGHT,((int)(sizeof(SQInteger)*8)));\n}\n\nvoid PrintUsage()\n{\n    fprintf(stderr,\"Usage: sq <scriptpath [args]> [options]\\n\"\n        \"Available options are:\\n\"\n        \"  -c                        compiles the file to bytecode (default output 'out.cnut')\\n\"\n        \"  -o <out-file>             specifies output file for the -c option\\n\"\n        \"  -ast-dump [out-file]      dump AST into console or file if specified\\n\"\n        \"  -nodes-location           print AST nodes locations\\n\"\n        \"  -absolute-path            use absolute path when print diangostics\\n\"\n        \"  -bytecode-dump [out-file] dump SQ bytecode into console or file if specified\\n\"\n        \"  -diag-file file           write diagnostics into specified file\\n\"\n        \"  -sa                       enable static analyzer\\n\"\n        \"  --check-stack             check stack after each script execution\\n\"\n        \"  --warnings-list           print all warnings and exit\\n\"\n        \"  --parse-types             parse function types from file\\n\"\n        \"  --D:<diagnostic-name>     disable diagnostic by text id\\n\"\n        \"  -optCH                    enable Closure Hoisting Optimization\\n\"\n        \"  -d                        generates debug infos\\n\"\n        \"  -v                        displays version\\n\"\n        \"  -h                        prints help\\n\");\n}\n\nstatic std::string read_file_ignoring_utf8bom(const char *filename)\n{\n    FILE *f = fopen(filename, \"rb\");\n    if (!f)\n        return std::string();\n\n    int length = 0;\n    fseek(f, 0, SEEK_END);\n    length = ftell(f);\n    fseek(f, 0, SEEK_SET);\n\n    std::string result;\n    result.resize(length + 1);\n    size_t sz = fread(&result[0], 1, length, f);\n    fclose(f);\n    result[sz] = 0;\n\n    static const unsigned char bom[] = {0xEF, 0xBB, 0xBF};\n    if (sz >= 3 && memcmp(result.data(), bom, 3) == 0)\n        result.erase(0, 3);\n\n    return result;\n}\n\nstatic int fill_stack(HSQUIRRELVM v)\n{\n  if (!check_stack_mode)\n    return 0;\n\n  for (int i = 0; i < 8; i++)\n    sq_pushinteger(v, i + 1000000);\n\n  return sq_gettop(v);\n}\n\nstatic bool check_stack(HSQUIRRELVM v, int expected_top)\n{\n  if (!check_stack_mode)\n    return true;\n\n  int top = sq_gettop(v);\n  if (top != expected_top)\n  {\n    fprintf(errorStream, \"ERROR: Stack top is %d, expected %d\\n\", top, expected_top);\n    return false;\n  }\n\n  for (int i = 0; i < 8; i++)\n  {\n    SQInteger val = -1;\n    if (SQ_FAILED(sq_getinteger(v, -8 + i, &val)) || val != i + 1000000)\n    {\n      fprintf(errorStream, \"ERROR: Stack value at %d is %d, expected %d\\n\", -8 + i, int(val), i + 1000000);\n      return false;\n    }\n  }\n\n  return true;\n}\n\nstruct DumpOptions {\n  bool astDump;\n  bool bytecodeDump;\n  bool nodesLocation;\n\n  const char *astDumpFileName;\n  const char *bytecodeDumpFileName;\n};\n\nstatic void dumpAst_callback(HSQUIRRELVM vm, SQCompilation::SqASTData *astData, void *opts)\n{\n    if (opts == NULL)\n      return;\n    DumpOptions *dumpOpt = (DumpOptions *)opts;\n    if (dumpOpt->astDump)\n    {\n        if (dumpOpt->astDumpFileName)\n        {\n            FileOutputStream fos(dumpOpt->astDumpFileName);\n            if (fos.valid())\n            {\n                sq_dumpast(vm, astData, dumpOpt->nodesLocation, &fos);\n            }\n            else\n            {\n                printf(\"Error: cannot open AST dump file '%s'\\n\", dumpOpt->astDumpFileName);\n            }\n        }\n        else\n        {\n            FileOutputStream fos(stdout);\n            sq_dumpast(vm, astData, dumpOpt->nodesLocation, &fos);\n        }\n    }\n}\n\nstatic void dumpBytecodeAst_callback(HSQUIRRELVM vm, HSQOBJECT obj, void *opts)\n{\n    if (opts == NULL)\n      return;\n    DumpOptions *dumpOpt = (DumpOptions *)opts;\n    if (dumpOpt->bytecodeDump)\n    {\n        if (dumpOpt->bytecodeDumpFileName)\n        {\n            FileOutputStream fos(dumpOpt->bytecodeDumpFileName);\n            if (fos.valid())\n            {\n                sq_dumpbytecode(vm, obj, &fos);\n            }\n            else\n            {\n                printf(\"Error: cannot open Bytecode dump file '%s'\\n\", dumpOpt->bytecodeDumpFileName);\n            }\n        }\n        else\n        {\n            FileOutputStream fos(stdout);\n            sq_dumpbytecode(vm, obj, &fos);\n        }\n    }\n}\n\nstatic bool search_sqconfig(const char * initial_file_name, char *buffer, size_t bufferSize)\n{\n  if (!initial_file_name)\n    return false;\n\n  size_t curSize = bufferSize;\n  char *ptr = buffer;\n  const char * slash1 = strrchr(initial_file_name, '\\\\');\n  const char * slash2 = strrchr(initial_file_name, '/');\n  const char * slash = slash1 > slash2 ? slash1 : slash2;\n\n  if (slash) {\n    size_t prefixSize = slash - initial_file_name + 1;\n    if (prefixSize > curSize)\n      return false;\n\n    memcpy(buffer, initial_file_name, prefixSize);\n    curSize -= prefixSize;\n    ptr += prefixSize;\n  }\n\n  static const char configName[] = \".sqconfig\";\n  const size_t configNameSize = (sizeof configName) - 1;\n  static const char upDir[] = \"../\";\n  const size_t upDirSize = (sizeof upDir) - 1;\n\n  char *dirPtr = ptr;\n\n  memcpy(ptr, configName, configNameSize);\n  ptr += configNameSize;\n  curSize -= configNameSize;\n  ptr[0] = '\\0';\n\n  for (int i = 0; i < 16 && curSize > 0; i++) {\n    if (FILE * f = fopen(buffer, \"rt\")) {\n      fclose(f);\n      return true;\n    }\n\n    if (curSize > upDirSize) {\n      memcpy(dirPtr, upDir, upDirSize);\n      dirPtr += upDirSize;\n      curSize -= upDirSize;\n      ptr += upDirSize;\n      memcpy(dirPtr, configName, configNameSize);\n      ptr[0] = '\\0';\n    }\n    else {\n      break;\n    }\n  }\n\n  return false;\n}\n\nstatic bool checkOption(char *argv[], int argc, const char *option, const char *&optArg) {\n  optArg = nullptr;\n  for (int i = 1; i< argc; ++i) {\n    const char *arg = argv[i];\n\n    if (arg[0] == '-' && strcmp(arg + 1, option) == 0) {\n      if ((i + 1) < argc) {\n        const char *arg2 = argv[i + 1];\n        if (arg2[0] != '-') { // not next option\n          optArg = arg2;\n        }\n      }\n      return true;\n    }\n  }\n\n  return false;\n}\n\nbool ends_with(const char * str, const char * suffix)\n{\n    const char * s = strstr(str, suffix);\n    return s && s[strlen(suffix)] == 0;\n}\n\nstatic bool parse_types_from_file(HSQUIRRELVM sqvm, const char *filename)\n{\n    std::string code = read_file_ignoring_utf8bom(filename);\n    if (code.empty())\n        return false;\n\n    const char *c = code.c_str();\n    std::string line;\n    int lineNum = 1;\n\n    while (*c) {\n        if (*c == '\\n' || c[1] == 0) {\n            if (c[1] == 0)\n                line += *c;\n            if (!line.empty()) {\n                printf(\"%s\\n\", line.c_str());\n\n                SQFunctionType t(_ss(sqvm));\n                SQInteger errorPos;\n                SQObjectPtr errorString;\n                if (sq_parse_function_type_string(sqvm, line.c_str(), t, errorPos, errorString)) {\n                    SQObjectPtr s = sq_stringify_function_type(sqvm, t);\n                    printf(\"%s\\n\", _stringval(s));\n                    printf(\"  functionName: %s\\n\", _stringval(t.functionName));\n                    printf(\"  returnTypeMask: 0x%x\\n\", unsigned(t.returnTypeMask));\n                    printf(\"  objectTypeMask: 0x%x\\n\", unsigned(t.objectTypeMask));\n                    printf(\"  ellipsisArgTypeMask: 0x%x\\n\", unsigned(t.ellipsisArgTypeMask));\n                    printf(\"  requiredArgs: %d\\n\", int(t.requiredArgs));\n                    printf(\"  argCount: %d\\n\", int(t.argTypeMask.size()));\n                    printf(\"  pure: %s\\n\", t.pure ? \"true\" : \"false\");\n                    printf(\"  nodiscard: %s\\n\", t.nodiscard ? \"true\" : \"false\");\n                    printf(\"\\n\");\n                }\n                else {\n                    printf(\"ERROR: %s\\n\", _stringval(errorString));\n                    printf(\"at %s:%d:%d\\n\\n\", filename, lineNum, int(errorPos));\n                }\n\n                line.clear();\n            }\n            lineNum++;\n        }\n        else {\n            if (*c != '\\r')\n                line += *c;\n        }\n\n        c++;\n    }\n\n    return true;\n}\n\n\n\n#define _DONE 2\n#define _ERROR 3\n//<<FIXME>> this func is a mess\nint getargs(HSQUIRRELVM v,int argc, char* argv[],SQInteger *retval)\n{\n    assert(module_mgr != nullptr && \"Module manager has to be initialized\");\n    const char *optArg = nullptr;\n    DumpOptions dumpOpt = { 0 };\n    FILE *diagFile = nullptr;\n    int compiles_only = 0;\n    bool static_analysis = checkOption(argv, argc, \"sa\", optArg); // TODO: refact ugly loop below using this function\n    bool parse_types = false;\n\n    if (static_analysis) {\n      sq_enablesyntaxwarnings(true);\n    }\n\n    std::vector<std::string> listOfNutFiles;\n\n    const char * output = NULL;\n    *retval = 0;\n    if(argc>1)\n    {\n        int index=1, exitloop=0;\n\n        while(index < argc && !exitloop)\n        {\n            const char *arg = argv[index];\n            if (arg[0] == '-' && arg[1] == '-')\n                arg++;\n\n            if (strcmp(\"-ast-dump\", arg) == 0)\n            {\n                dumpOpt.astDump = true;\n                if ((index + 1) < argc && argv[index + 1][0] != '-' && !ends_with(argv[index + 1], \".nut\"))\n                    dumpOpt.astDumpFileName = argv[++index];\n            }\n            else if (strcmp(\"-nodes-location\", arg) == 0)\n            {\n                dumpOpt.nodesLocation = true;\n            }\n            else if (strcmp(\"-absolute-path\", arg) == 0)\n            {\n                file_access.useAbsolutePath = true;\n            }\n            else if (strcmp(\"-parse-types\", arg) == 0)\n            {\n                parse_types = true;\n            }\n            else if (strcmp(\"-d\", arg) == 0)\n            {\n                sq_lineinfo_in_expressions(v, 1);\n            }\n            else if (strcmp(\"-diag-file\", arg) == 0)\n            {\n                if (((index + 1) < argc) && argv[index + 1][0] != '-')\n                {\n                    const char *fileName = argv[++index];\n                    diagFile = fopen(fileName, \"wb\");\n                    if (diagFile == NULL)\n                    {\n                        printf(\"Cannot open diagnostic output file '%s'\\n\", fileName);\n                        return _ERROR;\n                    }\n                }\n                else\n                {\n                    printf(\"-diag-file option requires file name to be specified\\n\");\n                    return _ERROR;\n                }\n            }\n            else if (strcmp(\"-bytecode-dump\", arg) == 0)\n            {\n              dumpOpt.bytecodeDump = 1;\n              if (((index + 1) < argc) && argv[index + 1][0] != '-' && !ends_with(argv[index + 1], \".nut\"))\n              {\n                  dumpOpt.bytecodeDumpFileName = argv[++index];\n              }\n            }\n            else if (strcmp(\"-c\", arg) == 0) {\n                compiles_only = 1;\n            }\n            else if (strcmp(\"-o\", arg) == 0) {\n                index++;\n                output = arg;\n            }\n            else if (strcmp(\"-check-stack\", arg) == 0) {\n                check_stack_mode = true;\n            }\n            else if (strcmp(\"-optCH\", arg) == 0) {\n                sq_setcompilationoption(v, CompilationOptions::CO_CLOSURE_HOISTING_OPT, true);\n            }\n            else if (strcmp(\"-v\", arg) == 0 || strcmp(\"--version\", arg) == 0) {\n                PrintVersionInfos();\n                return _DONE;\n            }\n            else if (strcmp(\"-h\", arg) == 0 || strcmp(\"--help\", arg) == 0) {\n                PrintVersionInfos();\n                PrintUsage();\n                return _DONE;\n            }\n            else if (strcmp(\"-sa\", arg) == 0) {\n                static_analysis = true;\n            }\n            else if (static_analysis && strncmp(\"-D:\", arg, 3) == 0) {\n                if (!sq_setdiagnosticstatebyname(&arg[3], false))\n                    printf(\"Unknown warning ID: '%s'\\n\", &arg[3]);\n            }\n            else if (strcmp(arg, \"-warnings-list\") == 0) {\n                sq_printwarningslist(stdout);\n                return _DONE;\n            }\n            else if (arg[0] == '-') {\n                PrintVersionInfos();\n                printf(\"unknown argument '%s'\\n\", arg);\n                PrintUsage();\n                *retval = -1;\n                return _ERROR;\n            }\n            else {\n                listOfNutFiles.emplace_back(std::string(arg));\n            }\n\n            index++;\n        }\n\n        module_mgr->up_data = &dumpOpt;\n        module_mgr->onAST_cb = &dumpAst_callback;\n        module_mgr->onBytecode_cb = &dumpBytecodeAst_callback;\n\n        module_mgr->compilationOptions.doStaticAnalysis = static_analysis;\n\n        if (static_analysis) {\n          sq_setcompilationoption(v, CompilationOptions::CO_CLOSURE_HOISTING_OPT, false);\n        }\n\n        if (diagFile)\n        {\n          errorStream = diagFile;\n        }\n\n        // src file\n\n        if (listOfNutFiles.empty()) {\n            printf(\"Error: expected source file name\\n\");\n            return _ERROR;\n        }\n\n        if (parse_types) {\n            for (const std::string & fn : listOfNutFiles) {\n                if (!parse_types_from_file(v, fn.c_str()))\n                    return _ERROR;\n            }\n            return _DONE;\n        }\n\n        for (const std::string & fn : listOfNutFiles) {\n            const char *filename=fn.c_str();\n\n            if (static_analysis) {\n              sq_resetanalyzerconfig();\n              char buffer[1024];\n              if (search_sqconfig(filename, buffer, sizeof buffer)) {\n                if (!sq_loadanalyzerconfig(buffer)) {\n                  fprintf(errorStream, \"Cannot load .sqconfig file %s\\n\", buffer);\n                  return _ERROR;\n                }\n              }\n            }\n\n            if (compiles_only) {\n                if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,SQTrue))){\n                    const char *outfile = \"out.cnut\";\n                    if(output) {\n                        outfile = output;\n                    }\n                    if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,outfile)))\n                        return _DONE;\n                }\n            }\n            else {\n                int top = fill_stack(v);\n\n                Sqrat::Object exports;\n                SqModules::string errMsg;\n                int retCode = _DONE;\n\n                if (!module_mgr->requireModule(filename, true, static_analysis ? SqModules::__analysis__ : SqModules::__main__, exports, errMsg)) {\n                    retCode = _ERROR;\n                }\n\n                if (retCode == _DONE && sq_isinteger(exports.GetObject())) {\n                    *retval = exports.GetObject()._unVal.nInteger;\n                }\n\n                if (static_analysis) {\n                  sq_checkglobalnames(v);\n                }\n\n                if (retCode != _DONE) {\n                  fprintf(stderr, \"Error [%s]\\n\", errMsg.c_str());\n                }\n\n                if (!check_stack(v, top)) {\n                    fprintf(stderr, \"Stack check failed after execution of '%s'\\n\", filename);\n                    *retval = -3;\n                    retCode = _ERROR;\n                }\n\n                return retCode;\n            }\n\n            //if this point is reached an error occurred\n            {\n                const char *err;\n                sq_getlasterror(v);\n                if(SQ_SUCCEEDED(sq_getstring(v,-1,&err))) {\n                    printf(\"Error [%s]\\n\",err);\n                    *retval = -2;\n                    return _ERROR;\n                }\n            }\n\n        }\n    }\n    else\n    {\n        PrintUsage();\n        *retval = -1;\n        return _ERROR;\n    }\n\n    return _DONE;\n}\n\nint sq_interpreter_main(int argc, char* argv[])\n{\n    SQInteger retval = 0;\n\n    HSQUIRRELVM v = sq_open(1024);\n    sq_setprintfunc(v,printfunc,errorfunc);\n\n    sqstd_seterrorhandlers(v);\n\n    module_mgr = new SqModules(v, &file_access);\n    module_mgr->registerMathLib();\n    module_mgr->registerStringLib();\n    module_mgr->registerSystemLib();\n    module_mgr->registerIoStreamLib();\n    module_mgr->registerIoLib();\n    module_mgr->registerDateTimeLib();\n    module_mgr->registerDebugLib();\n\n    sqstd_register_command_line_args(v, argc, argv);\n\n    extern void register_test_natives(SqModules *);\n    register_test_natives(module_mgr);\n\n    //gets arguments\n    getargs(v, argc, argv, &retval);\n\n    if (errorStream != stderr)\n    {\n      fclose(errorStream);\n    }\n\n    delete module_mgr;\n    sq_close(v);\n\n    return int(retval);\n}\n\n#ifndef SQ_EXCLUDE_DEFAULT_MAIN\nint main(int argc, char* argv[])\n{\n    return sq_interpreter_main(argc, argv);\n}\n#endif\n\n"
  },
  {
    "path": "sq/sq_test_natives.cpp",
    "content": "// Test native module for native field testing.\n// Registers \"test.native\" module with NativeVec class.\n\n#include <sqmodules.h>\n#include <sqrat.h>\n#include <string.h>\n#include <stdio.h>\n\nnamespace\n{\n\nstruct TestNativeVec\n{\n  float x, y, z;\n  int32_t w;\n};\n\nstatic SQInteger nativevec_ctor(HSQUIRRELVM vm)\n{\n  TestNativeVec *self = Sqrat::ClassType<TestNativeVec>::GetInstance(vm, 1);\n  if (!self)\n    return SQ_ERROR;\n  memset(self, 0, sizeof(TestNativeVec));\n  SQInteger top = sq_gettop(vm);\n  if (top >= 2) { SQFloat f; sq_getfloat(vm, 2, &f); self->x = (float)f; }\n  if (top >= 3) { SQFloat f; sq_getfloat(vm, 3, &f); self->y = (float)f; }\n  if (top >= 4) { SQFloat f; sq_getfloat(vm, 4, &f); self->z = (float)f; }\n  if (top >= 5) { SQInteger i; sq_getinteger(vm, 5, &i); self->w = (int32_t)i; }\n  return 0;\n}\n\n} // namespace\n\n\ntemplate<>\nstruct Sqrat::InstanceToString<TestNativeVec>\n{\n  static SQInteger Format(HSQUIRRELVM vm)\n  {\n    TestNativeVec *self = Sqrat::ClassType<TestNativeVec>::GetInstance(vm, 1);\n    if (!self)\n      return SQ_ERROR;\n    char buf[128];\n    snprintf(buf, sizeof(buf), \"NativeVec(%g, %g, %g, %d)\", self->x, self->y, self->z, self->w);\n    sq_pushstring(vm, buf, -1);\n    return 1;\n  }\n};\n\n\nvoid register_test_natives(SqModules *module_mgr)\n{\n  HSQUIRRELVM vm = module_mgr->getVM();\n\n  Sqrat::Class<TestNativeVec> cls(vm, \"NativeVec\");\n  cls\n    .UseInlineUserdata()\n    .SquirrelCtor(nativevec_ctor, 0, \".nnnn\")\n    .NativeVar(\"x\", &TestNativeVec::x)\n    .NativeVar(\"y\", &TestNativeVec::y)\n    .NativeVar(\"z\", &TestNativeVec::z)\n    .NativeVar(\"w\", &TestNativeVec::w);\n\n  Sqrat::Table exports(vm);\n  exports.Bind(\"NativeVec\", cls);\n  module_mgr->addNativeModule(\"test.native\", exports);\n}\n"
  },
  {
    "path": "sqmodules/CMakeLists.txt",
    "content": "set(SQMODULES_SRC \n  sqmodules.cpp\n  helpers.cpp\n  path.cpp\n  deffileaccess.cpp\n)\n\n\nadd_library(sqmodules STATIC ${SQMODULES_SRC})\nadd_library(squirrel::sqmodules ALIAS sqmodules)\n\ntarget_link_libraries(sqmodules sqstdlib squirrel)\ntarget_include_directories(sqmodules PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sqmodules>\"\n  \"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\"\n  PRIVATE\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sqrat/include>\"\n  )\n"
  },
  {
    "path": "sqmodules/deffileaccess.cpp",
    "content": "#include \"sqmodules.h\"\n#include \"path.h\"\n#include \"helpers.h\"\n\n#ifdef _WIN32\n#  include <io.h>\n#else\n#  include <unistd.h>\n#  include <limits.h>\n#  define _access access\n#endif\n\n\n#ifdef _WIN32\n#define MAX_PATH_LENGTH _MAX_PATH\nstatic const char *computeAbsolutePath(const char *resolved_fn, char *buffer, size_t size)\n{\n  return _fullpath(buffer, resolved_fn, size);\n}\n#else // _WIN32\n#define MAX_PATH_LENGTH PATH_MAX\nstatic const char *computeAbsolutePath(const char *resolved_fn, char *buffer, size_t size)\n{\n  (void)size;\n  return realpath(resolved_fn, buffer);\n}\n#endif // _WIN32\n\nvoid DefSqModulesFileAccess::destroy()\n{\n    if (needToDeleteSelf)\n        delete this;\n}\n\n\nSqModules::string DefSqModulesFileAccess::makeRelativeFilename(const char *cur_file, const char *requested_fn)\n{\n  scriptPathBuf.resize(strlen(cur_file) + 2);\n  dd_get_fname_location(&scriptPathBuf[0], cur_file);\n  dd_append_slash_c(&scriptPathBuf[0]);\n  size_t locationLen = strlen(&scriptPathBuf[0]);\n  size_t reqFnLen = strlen(requested_fn);\n  scriptPathBuf.resize(locationLen + reqFnLen + 1);\n  strcpy(&scriptPathBuf[locationLen], requested_fn);\n  dd_simplify_fname_c(&scriptPathBuf[0]);\n  scriptPathBuf.resize(strlen(&scriptPathBuf[0]) + 1);\n\n  return SqModules::string(scriptPathBuf.data());\n}\n\nvoid DefSqModulesFileAccess::resolveFileName(const char *requested_fn, const char *running_script, string &res)\n{\n  res.clear();\n\n  // try relative path first\n  if (running_script)\n  {\n    string scriptPath = makeRelativeFilename(running_script, requested_fn);\n    bool exists = _access(scriptPath.c_str(), 0) == 0;\n    if (exists)\n      res = std::move(scriptPath);\n  }\n\n  if (res.empty())\n  {\n    scriptPathBuf.resize(strlen(requested_fn) + 1);\n    strcpy(&scriptPathBuf[0], requested_fn);\n    dd_simplify_fname_c(&scriptPathBuf[0]);\n    res.insert(res.end(), scriptPathBuf.begin(), scriptPathBuf.begin() + strlen(&scriptPathBuf[0]));\n    scriptPathBuf.clear();\n  }\n\n  if (useAbsolutePath)\n  {\n    char buffer[MAX_PATH_LENGTH] = {0};\n    const char *real_path = computeAbsolutePath(res.c_str(), buffer, sizeof buffer);\n    if (real_path)\n      res = real_path;\n  }\n}\n\nbool DefSqModulesFileAccess::readFile(const string &resolved_fn, const char *requested_fn, vector<char> &buf,\n    string &out_err_msg)\n{\n  FILE* f = fopen(resolved_fn.c_str(), \"rb\");\n  if (!f)\n  {\n    out_err_msg = sqm::format_string(\"Script file %s (%s) not found\", requested_fn, resolved_fn.c_str());\n    return false;\n  }\n\n#ifdef _WIN32\n  long len = _filelength(_fileno(f));\n#else\n  fseek(f, 0, SEEK_END);\n  long len = ftell(f);\n  if (len < 0)\n  {\n    out_err_msg = sqm::format_string(\"Failed to read script file %s\", resolved_fn.c_str());\n    fclose(f);\n    return false;\n  }\n\n  fseek(f, 0, SEEK_SET);\n#endif\n\n  buf.resize(len + 1);\n  if (fread((void *)buf.data(), 1, len, f) != len)\n  {\n    out_err_msg = sqm::format_string(\"Failed to read script file %s (%s)\", requested_fn, resolved_fn.c_str());\n    fclose(f);\n    return false;\n  }\n\n  buf[len] = 0;\n  fclose(f);\n\n  return true;\n}\n"
  },
  {
    "path": "sqmodules/helpers.cpp",
    "content": "#include \"helpers.h\"\n#include <cstdarg>\n\nnamespace sqm\n{\n\nSqModules::string format_string(const char *fmt, ...)\n{\n  va_list ap;\n  va_start(ap, fmt);\n\n  va_list ap_copy;\n  va_copy(ap_copy, ap);\n  int len = vsnprintf(nullptr, 0, fmt, ap_copy);\n  va_end(ap_copy);\n\n  if (len < 0)\n  {\n    va_end(ap);\n    return {};\n  }\n\n  SqModules::string s;\n  s.resize(len + 1);\n  vsnprintf(&s[0], s.size(), fmt, ap);\n  va_end(ap);\n\n  s.resize(len);\n  return s; // no copy due to RVO or move\n}\n\nvoid append_format(SqModules::string &s, const char *fmt, ...)\n{\n  va_list ap;\n  va_start(ap, fmt);\n\n  va_list ap_copy;\n  va_copy(ap_copy, ap);\n  const int len = vsnprintf(nullptr, 0, fmt, ap_copy);\n  va_end(ap_copy);\n\n  if (len < 0)\n  {\n    va_end(ap);\n    return;\n  }\n\n  const size_t old = s.size();\n  s.resize(old + len + 1);\n  vsnprintf(&s[old], len + 1, fmt, ap);\n  va_end(ap);\n\n  s.resize(old + len);\n}\n\n}\n"
  },
  {
    "path": "sqmodules/helpers.h",
    "content": "#pragma once\n\n#include \"sqmodules.h\"\n\nnamespace sqm\n{\n\nSqModules::string format_string(const char *fmt, ...);\nvoid append_format(SqModules::string &s, const char *fmt, ...);\n\n}\n"
  },
  {
    "path": "sqmodules/path.cpp",
    "content": "#include \"path.h\"\n\n#include <algorithm>\n#include <string.h>\n\n#ifndef _WIN32\n#include <strings.h>\n#define _stricmp strcasecmp\n#endif\n\n// file path operations\n\n#define PATH_DELIM '/'\n#define PATH_DELIM_BACK '\\\\'\n#define PATH_DELIM_STR \"/\"\n#define MAX_PATH_LEN 260\n\nvoid dd_simplify_fname_c(char *s)\n{\n  if(!s) return;\n  int i,len=strlen(s);\n\n  // check for URL format to prevent removal of ://\n  if (char *semi = (char*)memchr(s, ':', len > 8 ? 8 : len))\n    if (len > (semi+3-s) && semi[1] == '/' && semi[2] == '/')\n    {\n      len -= int(semi+3-s);\n      s = semi+3;\n    }\n\n  for(;;) {\n    bool ok=false;\n    // remove leading spaces\n    for(i=0;i<len;++i)\n      if(s[i]!=' ' && s[i]!='\\t' && s[i]!='\\n' && s[i]!='\\r') break;\n    if(i>0) {len-=i;memmove(s,s+i,len+1); ok=true;}\n    // remove trailing spaces\n    for(i=len-1;i>=0;--i)\n      if(s[i]!=' ' && s[i]!='\\t' && s[i]!='\\n' && s[i]!='\\r') break;\n    if(i<len-1) {s[len=i+1]=0; ok=true;}\n    // remove quotes\n    for(i=0;i<len;++i) if(s[i]=='\"') break;\n    if(i<len) {\n      int qs=i;\n      for(++i;i<len;++i) if(s[i]=='\"') break;\n      if(i<len) {\n        memmove(s+qs,s+qs+1,len-qs); --len; --i;\n        memmove(s+i,s+i+1,len-i); --len;\n        ok=true;\n      }\n    }\n    if(!ok) break;\n  }\n\n  // replace all back slashes with normal ones\n  for(i=1;i<len;++i)\n    if(s[i]==PATH_DELIM_BACK )\n      s[i]=PATH_DELIM;\n\n  // remove extra slashes\n  for(i=1;i<len;++i) if(s[i]==PATH_DELIM)\n    if(s[i-1]==PATH_DELIM)\n      {memmove(s+i,s+i+1,len-i); --len; --i;}\n\n  // remove extra cur-dirs\n  while (len>1)\n    if (s[0]=='.' && s[1]==PATH_DELIM)\n    {\n      len-=2;\n      memmove(s,s+2,len+1);\n    }\n    else\n      break;\n\n  for(i=1;i<len;++i) if(s[i]=='.' && (s[i-1]==PATH_DELIM || s[i-1]==':'))\n    if(s[i+1]==PATH_DELIM || s[i+1]==0) {\n      int e=1; if(s[i+1]==PATH_DELIM) ++e;\n      len-=e; memmove(s+i,s+i+e,len+1-i);\n      --i;\n    }\n\n  // remove extra up-dirs\n  for (i=2; i<len; ++i) if (s[i-2]==PATH_DELIM && s[i-1]=='.' && s[i]=='.')\n    if (s[i+1]==PATH_DELIM || s[i+1]==0)\n    {\n      int j;\n      for (j=i-3;j>=0;--j) if(s[j]==PATH_DELIM || s[j]==':') break;\n\n      if (++j<i-2)\n      {\n        int e=i+1-j;\n\n        if (e!=5 || s[j]!='.' || s[j+1]!='.')\n        {\n          if (s[i+1]==PATH_DELIM) ++e;\n\n          len-=e; memmove(s+j, s+j+e, len+1-j);\n          i=std::max(j,1);\n        }\n      }\n    }\n}\n\nbool dd_fname_equal(const char *fn1,const char *fn2)\n{\n  if ( !fn1 && !fn2 )\n    return true;\n  if ( !fn1 || !fn2 )\n    return false;\n\n  char s1[MAX_PATH_LEN], s2[MAX_PATH_LEN];\n  strncpy(s1, fn1, MAX_PATH_LEN-1); s1[MAX_PATH_LEN-1] = '\\0';\n  strncpy(s2, fn2, MAX_PATH_LEN-1); s2[MAX_PATH_LEN-1] = '\\0';\n\n  dd_simplify_fname_c ( s1 );\n  dd_simplify_fname_c ( s2 );\n\n  return _stricmp(s1, s2) == 0;\n}\n\n\nvoid dd_append_slash_c(char *fn)\n{\n  if(!fn) return;\n  int l=strlen(fn);\n  if ( l > 0 )\n    if ( fn[l-1] != PATH_DELIM_BACK && fn[l-1] != PATH_DELIM ) {\n      fn[l]=PATH_DELIM;\n      fn[l+1]=0;\n    }\n}\n\n\nchar *dd_get_fname_location(char *buf, const char *filename)\n{\n  strcpy ( buf, filename );\n  dd_simplify_fname_c(buf);\n\n  char* p = strrchr(buf, PATH_DELIM);\n  if ( !p )\n    p = strchr(buf, ':');\n\n  if ( p )\n    p ++;\n  else\n    p = buf;\n\n  *p = '\\0';\n  return buf;\n}\n"
  },
  {
    "path": "sqmodules/path.h",
    "content": "#pragma once\n\nvoid dd_simplify_fname_c(char *s);\nbool dd_fname_equal(const char *fn1, const char *fn2);\nvoid dd_append_slash_c(char *fn);\nchar *dd_get_fname_location(char *buf, const char *filename);\n"
  },
  {
    "path": "sqmodules/span.h",
    "content": "#pragma once\n#include <cstddef>\n#include <type_traits>\n#include <vector>\n#include <cassert>\n#include <sqrat.h>\n\nnamespace sqm\n{\n\ntemplate <typename T>\nclass span {\npublic:\n    typedef T           element_type;\n    typedef typename SQRAT_STD::remove_cv<T>::type\n                        value_type;\n    typedef size_t      size_type;\n    typedef ptrdiff_t   index_type;\n    typedef T*          pointer;\n    typedef T&          reference;\n    typedef const T*    const_pointer;\n    typedef const T&    const_reference;\n    typedef T*          iterator;\n    typedef const T*    const_iterator;\n\n    span() noexcept : ptr_(nullptr), size_(0) {}\n\n    span(pointer ptr, size_type count) : ptr_(ptr), size_(count) {}\n\n    span(pointer first, pointer last)\n        : ptr_(first), size_(static_cast<size_type>(last - first)) {\n        assert(last >= first);\n    }\n\n    template <size_type N>\n    span(T (&arr)[N]) noexcept : ptr_(arr), size_(N) {}\n\n    template <typename U,\n              typename = typename SQRAT_STD::enable_if<!SQRAT_STD::is_const<T>::value &&\n                                                 SQRAT_STD::is_same<U, typename SQRAT_STD::remove_const<T>::type>::value>::type>\n    span(SQRAT_STD::vector<U>& v) noexcept : ptr_(v.data()), size_(v.size()) {}\n\n    template <typename U,\n              typename = typename SQRAT_STD::enable_if<SQRAT_STD::is_same<U, typename SQRAT_STD::remove_const<T>::type>::value>::type>\n    span(const SQRAT_STD::vector<U>& v) noexcept : ptr_(v.data()), size_(v.size()) {}\n\n    template <typename U,\n              typename = typename SQRAT_STD::enable_if<SQRAT_STD::is_same<const U, T>::value>::type>\n    span(const span<U>& other) noexcept : ptr_(other.data()), size_(other.size()) {}\n\n    size_type size() const noexcept { return size_; }\n    size_type size_bytes() const noexcept { return size_ * sizeof(T); }\n    bool empty() const noexcept { return size_ == 0; }\n    pointer data() const noexcept { return ptr_; }\n\n    reference operator[](size_type i) const {\n        return ptr_[i];\n    }\n\n    reference at(size_type i) const {\n        return ptr_[i];\n    }\n\n    reference front() const {\n        return *ptr_;\n    }\n\n    reference back() const {\n        return ptr_[size_ - 1];\n    }\n\n    iterator begin() const noexcept { return ptr_; }\n    iterator end() const noexcept { return ptr_ + size_; }\n    const_iterator cbegin() const noexcept { return ptr_; }\n    const_iterator cend() const noexcept { return ptr_ + size_; }\n\nprivate:\n    pointer   ptr_;\n    size_type size_;\n};\n\ntemplate <typename T>\ninline span<T> make_span(T* ptr, size_t count) { return span<T>(ptr, count); }\n\ntemplate <typename T>\ninline span<T> make_span(T* first, T* last) { return span<T>(first, last); }\n\ntemplate <typename T, size_t N>\ninline span<T> make_span(T (&arr)[N]) { return span<T>(arr); }\n\ntemplate <typename T>\ninline span<T> make_span(SQRAT_STD::vector<T>& v) { return span<T>(v); }\n\ntemplate <typename T>\ninline span<const T> make_span(const SQRAT_STD::vector<T>& v) { return span<const T>(v); }\n\n}\n"
  },
  {
    "path": "sqmodules/sqmodules.cpp",
    "content": "#include \"sqmodules.h\"\n\n#include <sqstdmath.h>\n#include <sqstdstring.h>\n#include <sqstdblob.h>\n#include <sqstddebug.h>\n#include <sqstdio.h>\n#include <sqstdsystem.h>\n#include <sqstddatetime.h>\n#include <sqstdaux.h>\n\n#include <stdlib.h>\n#include <limits.h>\n#include <string.h>\n#include <cstdarg>\n\n#include \"helpers.h\"\n\n#ifndef G_UNUSED\n  #define G_UNUSED(x)    ((void)(x))\n#endif\n\nconst char *SqModules::__main__ = \"__main__\";\nconst char *SqModules::__fn__ = nullptr;\nconst char *SqModules::__analysis__ = \"__analysis__\";\n\n\nusing namespace sqm;\n\nstatic sqm::span<char> skip_bom(sqm::span<char> buf)\n{\n  static constexpr uint8_t utf8_bom[] = {0xef, 0xbb, 0xbf};\n\n  bool isBom = (buf.size() >= sizeof(utf8_bom)) && memcmp(buf.data(), utf8_bom, sizeof(utf8_bom))==0;\n  int utf8MarkOffset = isBom ? sizeof(utf8_bom) : 0;\n  return sqm::make_span<char>(buf.data() + utf8MarkOffset, buf.size() - utf8MarkOffset);\n}\n\n\nstatic SQInteger persist_state(HSQUIRRELVM vm)\n{\n  HSQOBJECT hModuleThis, hSlot, hCtor, hMstate;\n  sq_getstackobj(vm, 1, &hModuleThis);\n  sq_getstackobj(vm, 2, &hSlot);\n  sq_getstackobj(vm, 3, &hCtor);\n  sq_getstackobj(vm, 4, &hMstate);\n\n  Sqrat::Table mstate(hMstate, vm);\n  SQRAT_ASSERTF(mstate.GetType() == OT_TABLE, \"type = %X\", mstate.GetType());\n\n  Sqrat::Object slot(hSlot, vm);\n  if (mstate.RawHasKey(slot))\n  {\n    Sqrat::Object curVal = mstate.GetSlot(slot);\n    sq_pushobject(vm, curVal);\n    return 1;\n  }\n\n  Sqrat::Object ctor(hCtor, vm);\n  Sqrat::Function f(vm, Sqrat::Object(hModuleThis, vm), ctor);\n  auto callRes = f.Eval<Sqrat::Object>();\n  if (!callRes)\n    return sq_throwerror(vm, \"Failed to call initializer\");\n  Sqrat::Object &res = callRes.value();\n\n  SQObjectType tp = res.GetType();\n  bool isMutable = tp == OT_TABLE || tp == OT_ARRAY || tp == OT_USERDATA || tp == OT_CLASS || tp == OT_INSTANCE;\n  if (!isMutable)\n  {\n    if (sq_isstring(hSlot))\n      return sqstd_throwerrorf(vm, \"Persist '%s' is not mutable, probably an error\", sq_objtostring(&hSlot));\n    else\n      return sq_throwerror(vm, \"Persist is not mutable, probably an error\");\n  }\n\n  mstate.SetValue(slot, res);\n\n  sq_pushobject(vm, res);\n  return 1;\n}\n\n\nstatic SQInteger keepref(HSQUIRRELVM vm)\n{\n  // arguments: this, object, ref holder\n  SQRAT_ASSERT(sq_gettype(vm, 3) == OT_ARRAY);\n  sq_push(vm, 2);                                    // push object\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_arrayappend(vm, 3))); // append to ref holder\n\n  sq_push(vm, 2); // push object again\n  return 1;\n}\n\n\nSqModules::SqModules(HSQUIRRELVM vm, ISqModulesFileAccess *file_access)\n  : sqvm(vm), fileAccess(file_access),\n  beforeImportModuleCb(nullptr), up_data(nullptr), onAST_cb(nullptr), onBytecode_cb(nullptr)\n{\n  compilationOptions.raiseError = true;\n  compilationOptions.doStaticAnalysis = false;\n\n  sq_enablesyntaxwarnings(false);\n\n  registerTypesLib();\n  registerModulesLib();\n}\n\n\nSqModules::~SqModules()\n{\n  modules.swap(prevModules);\n  modules.clear();\n\n  callAndClearUnloadHandlers(true);\n\n  prevModules.clear();\n\n  fileAccess->destroy();\n}\n\n\nbool SqModules::checkCircularReferences(const string &resolved_fn, const char *requested_fn, string &out_err_msg)\n{\n  for (const string &scriptFn : runningScripts)\n  {\n    if (scriptFn == resolved_fn)\n    {\n      out_err_msg = format_string(\"Required script %s (%s) is currently being executed, possible circular require() call.\\n\"\n        \"require() stack:\",\n        requested_fn, resolved_fn.c_str());\n\n      for (const string &stackItem : runningScripts)\n        append_format(out_err_msg, \"\\n * %s\", stackItem.c_str());\n\n      return false;\n    }\n  }\n  return true;\n}\n\n\nbool SqModules::compileScriptImpl(const sqm::span<char> buf, const char *resolved_fn, Sqrat::Table &bindings,\n  string &out_err_msg, SQCompilation::SqASTData **return_ast)\n{\n  out_err_msg.clear();\n\n  if (onCompileFile_cb)\n    onCompileFile_cb(sqvm, resolved_fn);\n\n  SQCompilation::SqASTData *ast =\n    sq_parsetoast(sqvm, buf.data(), buf.size(), resolved_fn, compilationOptions.doStaticAnalysis, compilationOptions.raiseError);\n\n  if (return_ast)\n    *return_ast = ast;\n\n  if (!ast)\n    return false;\n\n  if (onAST_cb)\n    onAST_cb(sqvm, ast, up_data);\n\n  SQModuleImport *imports = nullptr;\n  SQInteger numImports = 0;\n  bool importsRes = SQ_SUCCEEDED(sq_getimports(sqvm, ast, &numImports, &imports));\n  SQRAT_ASSERT(importsRes);\n  G_UNUSED(importsRes);\n\n  bool importRes = importModules(resolved_fn, bindings, imports, numImports, out_err_msg);\n  sq_freeimports(sqvm, numImports, imports);\n\n  if (!importRes)\n  {\n    sq_releaseASTData(sqvm, ast);\n    if (return_ast)\n      *return_ast = nullptr;\n    return false;\n  }\n\n  HSQOBJECT hBindings = bindings.GetObject();\n  hBindings._flags = SQOBJ_FLAG_IMMUTABLE;\n\n  if (SQ_FAILED(sq_translateasttobytecode(sqvm, ast, &hBindings, &buf[0], buf.size(), compilationOptions.raiseError)))\n  {\n    sq_releaseASTData(sqvm, ast);\n    if (return_ast)\n      *return_ast = nullptr;\n    return false;\n  }\n\n  if (compilationOptions.doStaticAnalysis && !return_ast)\n  {\n    sq_analyzeast(sqvm, ast, &hBindings, buf.data(), buf.size());\n  }\n\n  if (onBytecode_cb)\n  {\n    HSQOBJECT func;\n    sq_getstackobj(sqvm, -1, &func);\n    onBytecode_cb(sqvm, func, up_data);\n  }\n\n  if (!return_ast)\n    sq_releaseASTData(sqvm, ast);\n  return true;\n}\n\n\nbool SqModules::compileScript(const sqm::span<char> buf, const string &resolved_fn, const char *requested_fn, Sqrat::Table &bindings,\n  Sqrat::Object &script_closure, string &out_err_msg, SQCompilation::SqASTData **return_ast)\n{\n  script_closure.Release();\n\n  string compileErrMsg;\n  if (!compileScriptImpl(buf, resolved_fn.c_str(), bindings, compileErrMsg, return_ast))\n  {\n    out_err_msg = format_string(\"Failed to compile file %s (%s)\", requested_fn, resolved_fn.c_str());\n    if (!compileErrMsg.empty())\n      append_format(out_err_msg, \": %s\", compileErrMsg.c_str());\n    return false;\n  }\n\n  script_closure = Sqrat::Var<Sqrat::Object>(sqvm, -1).value;\n  sq_pop(sqvm, 1);\n\n  return true;\n}\n\n\nSqrat::Table SqModules::setupStateStorage(const char *resolved_fn)\n{\n  SQRAT_ASSERT(sqvm);\n\n  for (const Module &prevMod : prevModules)\n    if (prevMod.fn == resolved_fn)\n      return prevMod.stateStorage;\n\n  return Sqrat::Table(sqvm);\n}\n\nSqModules::Module *SqModules::findModule(const char *resolved_fn)\n{\n  for (Module &m : modules)\n    if (m.fn == resolved_fn)\n      return &m;\n\n  return nullptr;\n}\n\n\nvoid SqModules::bindBaseLib(HSQOBJECT bindings)\n{\n  sq_pushobject(sqvm, bindings);\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_registerbaselib(sqvm)));\n  sq_poptop(sqvm);\n}\n\n\nvoid SqModules::bindRequireApi(HSQOBJECT bindings)\n{\n  sq_pushobject(sqvm, bindings);\n\n  sq_pushstring(sqvm, \"require\", 7);\n  sq_pushuserpointer(sqvm, this);\n  sq_newclosure(sqvm, sqRequire<true>, 1);\n  sq_setnativeclosurename(sqvm, -1, \"require\");\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(sqvm, 2, \".s\")));\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(sqvm, -3)));\n\n  sq_pushstring(sqvm, \"require_optional\", 16);\n  sq_pushuserpointer(sqvm, this);\n  sq_newclosure(sqvm, sqRequire<false>, 1);\n  sq_setnativeclosurename(sqvm, -1, \"require_optional\");\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(sqvm, 2, \".s\")));\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(sqvm, -3)));\n\n  sq_poptop(sqvm); // bindings\n}\n\n\nvoid SqModules::bindModuleApi(HSQOBJECT bindings, Sqrat::Table &state_storage, Sqrat::Array &ref_holder, const char *__name__,\n  const char *__filename__)\n{\n  SQRAT_ASSERT(__name__);\n  SQRAT_ASSERT(__filename__);\n\n  HSQUIRRELVM vm = sqvm;\n\n  sq_pushobject(vm, bindings);\n\n  sq_pushstring(vm, \"persist\", 7);\n  sq_pushobject(vm, state_storage.GetObject());\n  sq_newclosure(vm, persist_state, 1);\n  sq_setnativeclosurename(vm, -1, \"persist\");\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, 3, \".sc\")));\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(vm, -3)));\n\n  sq_pushstring(vm, \"keepref\", 7);\n  sq_pushobject(vm, ref_holder.GetObject());\n  sq_newclosure(vm, keepref, 1);\n  sq_setnativeclosurename(vm, -1, \"keepref\");\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(vm, -3)));\n\n  sq_pushstring(vm, \"__name__\", 8);\n  sq_pushstring(vm, __name__, -1);\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(vm, -3)));\n\n  sq_pushstring(vm, \"__filename__\", 12);\n  sq_pushstring(vm, __filename__, -1);\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(vm, -3)));\n\n  sq_pushstring(vm, \"__static_analysis__\", 19);\n  sq_pushbool(vm, compilationOptions.doStaticAnalysis);\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_rawset(vm, -3)));\n\n  sq_pop(vm, 1); // bindings table\n}\n\n\nbool SqModules::mergeBindings(Sqrat::Table &target, Sqrat::Object &key, Sqrat::Object &value, string &out_err_msg)\n{\n  if (target.RawHasKey(key))\n  {\n    string keyStr = key.Cast<string>();\n    Sqrat::Object current = target.RawGetSlot(key);\n    if (value.IsEqual(current))\n      return true;\n    else\n    {\n      out_err_msg = format_string(\"Duplicate field '%s' in imported bindings\", keyStr.c_str());\n      return false;\n    }\n  }\n  else\n  {\n    target.SetValue(key, value);\n    return true;\n  }\n}\n\n\nbool SqModules::mergeBindings(Sqrat::Table &target, Sqrat::Table &upd, string &out_err_msg)\n{\n  Sqrat::Object::iterator it;\n\n  while (upd.Next(it))\n  {\n    Sqrat::Object key(it.getKey(), sqvm);\n    Sqrat::Object val(it.getValue(), sqvm);\n    if (!mergeBindings(target, key, val, out_err_msg))\n      return false;\n  }\n\n  return true;\n}\n\nbool SqModules::importModules(const char *resolved_fn, Sqrat::Table &bindings_dest, const SQModuleImport *imports, int num_imports,\n  string &out_err_msg)\n{\n  if (!num_imports)\n    return true;\n\n  size_t rsIdx = runningScripts.size();\n  runningScripts.emplace_back(resolved_fn);\n\n  bool success = true;\n  string mergeErrorMsg, requireErrorMsg;\n\n  for (int iImp = 0; iImp < num_imports; ++iImp)\n  {\n    const SQModuleImport &import = imports[iImp];\n    Sqrat::Object exports;\n    string moduleFnStr(import.name);\n\n    if (beforeImportModuleCb && !beforeImportModuleCb(this, moduleFnStr.c_str()))\n    {\n      out_err_msg = format_string(\"%s:%d:%d: Module '%s' is forbidden\", resolved_fn, import.line, import.nameColumn, moduleFnStr.c_str());\n      success = false;\n      break;\n    }\n\n    auto nativeIt = nativeModules.find(import.name);\n    if (nativeIt != nativeModules.end())\n      exports = nativeIt->second;\n    else if (!requireModule(moduleFnStr.c_str(), true, __fn__, exports, requireErrorMsg))\n    {\n      out_err_msg = format_string(\"Import error at %s:%d:%d: %s\", resolved_fn, import.line, import.nameColumn, requireErrorMsg.c_str());\n      success = false;\n      break;\n    }\n\n    if (import.numSlots == 0) // import module as slot\n    {\n      Sqrat::Object key(import.alias ? import.alias : import.name, sqvm);\n      if (!mergeBindings(bindings_dest, key, exports, mergeErrorMsg))\n      {\n        success = false;\n        out_err_msg = format_string(\"%s:%d:%d: %s\", resolved_fn, import.line, import.nameColumn, mergeErrorMsg.c_str());\n      }\n    }\n    else // import fields\n    {\n      if (exports.GetType() != OT_TABLE && exports.GetType() != OT_CLASS)\n      {\n        out_err_msg = format_string(\"%s:%d:%d: module '%s' export is not a table or class\", resolved_fn, import.line, import.nameColumn,\n          moduleFnStr.c_str());\n        success = false;\n        break;\n      }\n\n      Sqrat::Table exportsTbl(exports);\n      for (int iSlot = 0; iSlot < import.numSlots; ++iSlot)\n      {\n        const SQModuleImportSlot &slot = import.slots[iSlot];\n        if (strcmp(slot.name, \"*\") == 0) // import all fields\n        {\n          if (!mergeBindings(bindings_dest, exportsTbl, mergeErrorMsg))\n          {\n            out_err_msg = format_string(\"%s:%d: %s\", resolved_fn, import.line, mergeErrorMsg.c_str());\n            success = false;\n            break;\n          }\n        }\n        else // import single field\n        {\n          Sqrat::Object srcKey(slot.name, sqvm);\n\n          if (!exportsTbl.RawHasKey(srcKey))\n          {\n            out_err_msg = format_string(\"%s:%d:%d no field '%s' in module '%s' exports\", resolved_fn, slot.line, slot.column,\n              sq_objtostring(&srcKey.GetObject()), moduleFnStr.c_str());\n            success = false;\n            break;\n          }\n          else\n          {\n            Sqrat::Object destKey(slot.alias ? slot.alias : slot.name, sqvm);\n            Sqrat::Object val = exports.GetSlot(srcKey);\n            if (!mergeBindings(bindings_dest, destKey, val, mergeErrorMsg))\n            {\n              out_err_msg = format_string(\"%s:%d:%d: %s\", resolved_fn, slot.line, slot.column, mergeErrorMsg.c_str());\n              success = false;\n              break;\n            }\n          }\n        }\n      }\n    }\n    if (!success)\n      break;\n  }\n\n  G_UNUSED(rsIdx);\n  SQRAT_ASSERT(runningScripts.size() == rsIdx + 1);\n  runningScripts.pop_back();\n\n  return success;\n}\n\n\nbool SqModules::requireModule(const char *requested_fn, bool must_exist, const char *__name__, Sqrat::Object &exports,\n  string &out_err_msg)\n{\n  out_err_msg.clear();\n  exports.Release();\n\n  string resolvedFn;\n  fileAccess->resolveFileName(requested_fn, runningScripts.empty() ? nullptr : runningScripts.back().c_str(), resolvedFn);\n\n  if (!checkCircularReferences(resolvedFn, requested_fn, out_err_msg))\n    return false;\n\n  if (beforeImportModuleCb && !beforeImportModuleCb(this, requested_fn))\n  {\n    out_err_msg = format_string(\"Module '%s' is forbidden\", requested_fn);\n    return false;\n  }\n\n  if (Module *found = findModule(resolvedFn.c_str()))\n  {\n    exports = found->exports;\n    return true;\n  }\n\n  vector<char> fileContents;\n  bool readOk = fileAccess->readFile(resolvedFn, requested_fn, fileContents, out_err_msg);\n  if (!readOk)\n    return !must_exist;\n\n  HSQUIRRELVM vm = sqvm;\n  SQInteger prevTop = sq_gettop(sqvm);\n  G_UNUSED(prevTop);\n\n  SQRAT_ASSERT(__fn__ == nullptr);\n  if (__name__ == __fn__)\n    __name__ = resolvedFn.c_str();\n\n  Sqrat::Table stateStorage = setupStateStorage(resolvedFn.c_str());\n  Sqrat::Array refHolder(vm);\n\n  Sqrat::Table bindingsTbl(vm);\n  HSQOBJECT hBindings = bindingsTbl.GetObject();\n\n  bindBaseLib(hBindings);\n  bindModuleApi(hBindings, stateStorage, refHolder, __name__, resolvedFn.c_str());\n  bindRequireApi(hBindings);\n\n  SQRAT_ASSERT(sq_gettop(vm) == prevTop);\n\n  sqm::span<char> sourceCode = skip_bom(sqm::make_span(fileContents));\n\n  if (compilationOptions.doStaticAnalysis)\n    sq_checktrailingspaces(vm, resolvedFn.c_str(), sourceCode.data(), sourceCode.size());\n\n  SQCompilation::SqASTData *astData = nullptr;\n\n  Sqrat::Object scriptClosure;\n  bool compileRes = compileScript(sourceCode, resolvedFn, requested_fn, bindingsTbl, scriptClosure, out_err_msg,\n    compilationOptions.doStaticAnalysis ? &astData : nullptr);\n\n  if (!compileRes)\n  {\n    sq_releaseASTData(vm, astData);\n    SQRAT_ASSERT(sq_gettop(vm) == prevTop);\n    return false;\n  }\n\n  size_t rsIdx = runningScripts.size();\n  G_UNUSED(rsIdx);\n\n  runningScripts.emplace_back(resolvedFn.c_str());\n\n\n  sq_pushobject(vm, scriptClosure.GetObject());\n  sq_pushnull(vm); // module 'this'\n\n  runningScriptClosuresStack.push_back(scriptClosure);\n  SQRESULT callRes = sq_call(vm, 1, true, true);\n  runningScriptClosuresStack.pop_back();\n\n  if (SQ_FAILED(callRes))\n  {\n    SQRAT_ASSERT(runningScripts.size() == rsIdx + 1);\n    runningScripts.pop_back();\n\n    out_err_msg = format_string(\"Failed to run script %s (%s)\", requested_fn, resolvedFn.c_str());\n    sq_pop(vm, 1); // clojure, no return value on error\n    sq_releaseASTData(vm, astData);\n    SQRAT_ASSERT(sq_gettop(vm) == prevTop);\n    return false;\n  }\n\n  HSQOBJECT hExports;\n  sq_getstackobj(vm, -1, &hExports);\n  exports = Sqrat::Object(hExports, vm);\n\n  sq_pop(vm, 2); // retval + closure\n\n  SQRAT_ASSERT(sq_gettop(vm) == prevTop);\n\n  Module module;\n  module.exports = exports;\n  module.fn = resolvedFn;\n  module.stateStorage = stateStorage;\n  module.refHolder = refHolder;\n  module.scriptClosure = scriptClosure;\n  module.__name__ = __name__;\n\n  modules.push_back(module);\n\n  if (compilationOptions.doStaticAnalysis && astData)\n    sq_analyzeast(vm, astData, &hBindings, sourceCode.data(), sourceCode.size());\n\n  SQRAT_ASSERT(runningScripts.size() == rsIdx + 1);\n  runningScripts.pop_back();\n\n  sq_releaseASTData(vm, astData);\n  return true;\n}\n\n\nbool SqModules::reloadModule(const char *fn, bool must_exist, const char *__name__, Sqrat::Object &exports, string &out_err_msg)\n{\n  SQRAT_ASSERT(prevModules.empty());\n\n  modules.swap(prevModules);\n  modules.clear(); // just in case\n\n  callAndClearUnloadHandlers(false);\n\n  string errMsg;\n  bool res = requireModule(fn, must_exist, __name__, exports, out_err_msg);\n\n  prevModules.clear();\n\n  return res;\n}\n\n\nbool SqModules::reloadAll(string &full_err_msg)\n{\n  SQRAT_ASSERT(prevModules.empty());\n  full_err_msg.clear();\n\n  modules.swap(prevModules);\n  modules.clear(); // just in case\n\n  callAndClearUnloadHandlers(false);\n\n  bool res = true;\n  Sqrat::Object exportsTmp;\n  string errMsg;\n  for (const Module &prev : prevModules)\n  {\n    if (!requireModule(prev.fn.c_str(), true, prev.__name__.c_str(), exportsTmp, errMsg))\n    {\n      res = false;\n      append_format(full_err_msg, \"%s: %s\\n\", prev.fn.c_str(), errMsg.c_str());\n    }\n  }\n\n  prevModules.clear();\n\n  return res;\n}\n\n\nbool SqModules::addNativeModule(const char *module_name, const Sqrat::Object &exports, const char *module_doc_string)\n{\n  if (!module_name || !*module_name)\n  {\n    SQRAT_ASSERT(0);\n    return false;\n  }\n\n  auto ins = nativeModules.insert({string(module_name), exports});\n  SQRAT_ASSERT(ins.second && \"Module registered twice\");\n\n  if (module_doc_string && ins.second)\n    sq_setobjectdocstring(exports.GetVM(), &const_cast<Sqrat::Object &>(exports).GetObject(), module_doc_string);\n\n  return ins.second; // false if already registered\n}\n\n\nSqrat::Array SqModules::getNativeModuleNames()\n{\n  Sqrat::Array list(sqvm, nativeModules.size());\n  SQInteger idx = 0;\n  for (auto &nm : nativeModules)\n  {\n    list.SetValue(idx, nm.first.data());\n    ++idx;\n  }\n  return list;\n}\n\nvoid SqModules::getLoadedModules(vector<string> &file_names)\n{\n  file_names.clear();\n  file_names.reserve(modules.size());\n  for (const Module &m : modules)\n    file_names.push_back(m.fn);\n}\n\n\ntemplate <bool must_exist>\nSQInteger SqModules::sqRequire(HSQUIRRELVM vm) // arguments: fileName, mustExist=true\n{\n  SQUserPointer selfPtr = nullptr;\n  if (SQ_FAILED(sq_getuserpointer(vm, -1, &selfPtr)) || !selfPtr)\n    return sq_throwerror(vm, \"No module manager\");\n\n  SqModules *self = reinterpret_cast<SqModules *>(selfPtr);\n  SQRAT_ASSERT(self->sqvm == vm);\n\n  const char *fileName = nullptr;\n  SQInteger fileNameLen = -1;\n  sq_getstringandsize(vm, 2, &fileName, &fileNameLen);\n\n  if (strcmp(fileName, \"quirrel.native_modules\") == 0)\n  {\n    Sqrat::Array list = self->getNativeModuleNames();\n    sq_pushobject(vm, list);\n    return 1;\n  }\n\n  if (self->beforeImportModuleCb && !self->beforeImportModuleCb(self, fileName))\n    return sqstd_throwerrorf(vm, \"Module '%s' is forbidden\", fileName);\n\n  bool searchNative = true, searchScript = true;\n  self->fileAccess->getSearchTargets(fileName, searchNative, searchScript);\n\n  auto nativeIt = searchNative ? self->nativeModules.find(fileName) : self->nativeModules.end();\n  if (nativeIt != self->nativeModules.end())\n  {\n    sq_pushobject(vm, nativeIt->second);\n    return 1;\n  }\n  if (!searchScript)\n  {\n    if (!must_exist)\n    {\n      sq_pushnull(vm);\n      return 1;\n    }\n    else\n      return sqstd_throwerrorf(vm, \"Script module '%s' not found\", fileName);\n  }\n\n  Sqrat::Object exports(vm);\n  string errMsg;\n  if (!self->requireModule(fileName, must_exist, __fn__, exports, errMsg))\n    return sq_throwerror(vm, errMsg.c_str());\n\n  sq_pushobject(vm, exports.GetObject());\n  return 1;\n}\n\n\nvoid SqModules::registerStdLibNativeModule(const char *name, RegFunc reg_func)\n{\n  HSQOBJECT hModule;\n  sq_newtable(sqvm);\n  sq_getstackobj(sqvm, -1, &hModule);\n  reg_func(sqvm);\n  bool regRes = addNativeModule(name, Sqrat::Object(hModule, sqvm));\n  G_UNUSED(regRes);\n  SQRAT_ASSERT(regRes);\n  sq_pop(sqvm, 1);\n}\n\n\nvoid SqModules::registerTypesLib() { registerStdLibNativeModule(\"types\", sq_registertypeslib); }\n\nvoid SqModules::registerMathLib() { registerStdLibNativeModule(\"math\", sqstd_register_mathlib); }\n\nvoid SqModules::registerStringLib() { registerStdLibNativeModule(\"string\", sqstd_register_stringlib); }\n\nvoid SqModules::registerSystemLib() { registerStdLibNativeModule(\"system\", sqstd_register_systemlib); }\n\nvoid SqModules::registerDateTimeLib() { registerStdLibNativeModule(\"datetime\", sqstd_register_datetimelib); }\n\nvoid SqModules::registerDebugLib() { registerStdLibNativeModule(\"debug\", sqstd_register_debuglib); }\n\nvoid SqModules::registerIoStreamLib()\n{\n  HSQOBJECT hModule;\n  sq_resetobject(&hModule);\n  sq_newtable(sqvm);\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(sqvm, -1, &hModule)));\n  SQRAT_VERIFY(SQ_SUCCEEDED(sqstd_init_streamclass(sqvm)));\n  SQRAT_VERIFY(SQ_SUCCEEDED(sqstd_register_bloblib(sqvm)));\n  bool regRes = addNativeModule(\"iostream\", Sqrat::Object(hModule, sqvm));\n  G_UNUSED(regRes);\n  SQRAT_ASSERTF(regRes, \"Failed to init 'iostream' library with module manager\");\n  sq_pop(sqvm, 1);\n}\n\nvoid SqModules::registerIoLib()\n{\n  if (!findNativeModule(\"iostream\"))\n  {\n    // register 'iostream' module containing basestream class and blob\n    registerIoStreamLib();\n  }\n\n  registerStdLibNativeModule(\"io\", sqstd_register_iolib);\n}\n\n\nvoid SqModules::callAndClearUnloadHandlers(bool is_closing)\n{\n  resetStaticMemos();\n\n  for (const Sqrat::Object &f : onModuleUnload)\n  {\n    SQInteger nparams = 0, nfreevars = 0;\n    sq_pushobject(sqvm, f.GetObject());\n    SQRAT_VERIFY(SQ_SUCCEEDED(sq_getclosureinfo(sqvm, -1, &nparams, &nfreevars)));\n    sq_pop(sqvm, 1);\n\n    Sqrat::Function func(sqvm, Sqrat::Object(), f.GetObject());\n    if (nparams == 1)\n      func();\n    else if (nparams == 2)\n      func(is_closing);\n    else\n      SQRAT_ASSERT(0);\n  }\n  onModuleUnload.clear();\n}\n\n\nSQInteger SqModules::register_on_module_unload(HSQUIRRELVM vm)\n{\n  SQInteger nparams = 0, nfreevars = 0;\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_getclosureinfo(vm, 2, &nparams, &nfreevars)));\n  if (nparams != 1 && nparams != 2)\n    return sqstd_throwerrorf(vm, \"Function accepts 'this' + optional argument, but provided function requires %d args\", nparams);\n\n  SqModules *self = nullptr;\n  SQRAT_VERIFY(SQ_SUCCEEDED(sq_getuserpointer(vm, 3, (SQUserPointer *)&self)));\n\n  HSQOBJECT hFunc;\n  sq_getstackobj(vm, 2, &hFunc);\n\n  auto it = SQRAT_STD::find_if(self->onModuleUnload.begin(), self->onModuleUnload.end(),\n    [hFunc](const Sqrat::Object &f) { return f.GetType() == sq_type(hFunc) && f.GetObject()._unVal.raw == hFunc._unVal.raw; });\n  if (it == self->onModuleUnload.end())\n    self->onModuleUnload.push_back(Sqrat::Object(hFunc, vm));\n\n  return 0;\n}\n\nvoid SqModules::resetStaticMemos()\n{\n  for (Module &module : modules)\n    sq_reset_static_memos(sqvm, module.scriptClosure.GetObject());\n\n  for (Module &module : prevModules)\n    sq_reset_static_memos(sqvm, module.scriptClosure.GetObject());\n\n  for (Sqrat::Object &f : runningScriptClosuresStack)\n    sq_reset_static_memos(sqvm, f.GetObject());\n}\n\n\nvoid SqModules::registerModulesLib()\n{\n  Sqrat::Table exports(sqvm);\n\n  sq_pushuserpointer(sqvm, this);\n  Sqrat::Var<Sqrat::Object> selfObj(sqvm, -1);\n  sq_pop(sqvm, 1);\n\n  exports\n    .Func(\n      \"get_native_module_names\", [this]() { return this->getNativeModuleNames(); },\n      \"Returns an array with a list of names of native modules.\")\n    .Func(\n      \"reset_static_memos\", [this]() { return this->resetStaticMemos(); }, \"Reset static memo expressions cache.\")\n    .SquirrelFunc(\"on_module_unload\", register_on_module_unload, 2, \".c\",\n      \"Register module unload callback. \"\n      \"Example: on_module_unload( function(is_app_closing) {println(is_app_closing ? \\\"Closing\\\" : \\\"Soft reloading\\\")} )\",\n      1, &selfObj.value);\n\n  addNativeModule(\"modules\", exports, \"Contains functions to work with modules, like on_module_unload(), get_native_module_names()\");\n}\n"
  },
  {
    "path": "sqmodules/sqmodules.h",
    "content": "#pragma once\n\n#include <squirrel.h>\n#include <sqrat.h>\n\n#if defined(SQRAT_HAS_EASTL)\n#include <EASTL/string.h>\n#include <EASTL/vector.h>\n#include <EASTL/vector_map.h>\n#else\n#include <vector>\n#include <unordered_map>\n#include <string>\n#include <algorithm>\n#endif\n\n#include \"span.h\"\n\n\nnamespace SQCompilation\n{\nstruct SqASTData;\n}\n\nstruct ISqModulesFileAccess\n{\n  template <class T>\n  using vector = SQRAT_STD::vector<T>;\n  using string = Sqrat::string;\n\n  virtual ~ISqModulesFileAccess() {}\n\n  virtual void destroy() = 0;\n\n  virtual void resolveFileName(const char *requested_fn, const char *running_script, string &res) = 0;\n  // when file can't be read, return false and fill out_err_msg\n  virtual bool readFile(const string &resolved_fn, const char *requested_fn, vector<char> &buf, string &out_err_msg) = 0;\n\n  virtual void getSearchTargets(const char * /*fn*/, bool &search_native, bool &search_script)\n  {\n    search_native = true;\n    search_script = true;\n  }\n};\n\nstruct DefSqModulesFileAccess : public ISqModulesFileAccess\n{\n  virtual void destroy() override;\n\n  virtual void resolveFileName(const char *requested_fn, const char *running_script, string &res) override;\n  // when file can't be read, return false and fill out_err_msg\n  virtual bool readFile(const string &resolved_fn, const char *requested_fn, vector<char> &buf, string &out_err_msg) override;\n\n  string makeRelativeFilename(const char *cur_file, const char *requested_fn);\n\n  bool useAbsolutePath = false;\n  vector<char> scriptPathBuf; // cache\n  bool needToDeleteSelf = false;\n};\n\n\nclass SqModules\n{\nprivate:\n  SqModules(const SqModules &) = delete;\n  SqModules(SqModules &&) = delete;\npublic:\n  template <class T>\n  using vector = SQRAT_STD::vector<T>;\n  using string = Sqrat::string;\n\n  typedef bool (*BeforeImportModuleCallback)(SqModules *sq_modules, const char *module_name);\n  typedef void (*SQOnCompileFileCb)(HSQUIRRELVM, const char *);\n\n  struct Module\n  {\n    string fn; // filename resolved to the full path\n    Sqrat::Object exports;\n    Sqrat::Object stateStorage;\n    Sqrat::Array refHolder;\n    Sqrat::Object scriptClosure;\n    string __name__;\n  };\n\n  SqModules(HSQUIRRELVM vm, ISqModulesFileAccess *file_access);\n  ~SqModules();\n\n  HSQUIRRELVM getVM() { return sqvm; }\n\n  // File name may be:\n  // 1) relative to currently running script\n  // 2) relative to base path\n  // Note: accessing files outside of current base paths (via ../../)\n  // can mess things up (breaking load module once rule)\n  // __name__ is put to module this. Use __fn__ constant to use resolved filename or custom string to override\n  bool requireModule(const char *fn, bool must_exist, const char *__name__, Sqrat::Object &exports, string &out_err_msg);\n  // This can also be used for initial module execution\n  bool reloadModule(const char *fn, bool must_exist, const char *__name__, Sqrat::Object &exports, string &out_err_msg);\n\n  bool reloadAll(string &err_msg);\n\n  void resetStaticMemos();\n\n  bool addNativeModule(const char *module_name, const Sqrat::Object &exports, const char *module_doc_string = nullptr);\n\n  void registerTypesLib();\n  void registerMathLib();\n  void registerStringLib();\n  void registerSystemLib();\n  void registerIoStreamLib();\n  void registerIoLib();\n  void registerDateTimeLib();\n  void registerDebugLib();\n  void registerModulesLib();\n\n  template <typename F>\n  void forEachNativeModule(const F &cb); // 'cb' called as cb(const char *module_name, const Sqrat::Object &module)\n  Sqrat::Object *findNativeModule(const char *module_name);\n  void getLoadedModules(vector<string> &file_names);\n\n  void setModuleImportCallback(BeforeImportModuleCallback before_import_module_callback)\n  {\n    beforeImportModuleCb = before_import_module_callback;\n  }\n\n  void bindRequireApi(HSQOBJECT bindings);\n  void bindModuleApi(HSQOBJECT bindings, Sqrat::Table &state_storage, Sqrat::Array &ref_holder, const char *__name__,\n    const char *__filename__);\n  void bindBaseLib(HSQOBJECT bindings);\n\nprivate:\n  // Script API\n  //   require(file_name, must_exist=true)\n  template <bool must_exist>\n  static SQInteger sqRequire(HSQUIRRELVM vm);\n\n  void resolveFileName(const char *fn, string &res);\n  bool checkCircularReferences(const string &resolved_fn, const char *orig_fn, string &out_err_msg);\n  bool readFile(const string &resolved_fn, const char *requested_fn, vector<char> &buf, string &out_err_msg);\n  bool compileScript(const sqm::span<char> buf, const string &resolved_fn, const char *orig_fn, Sqrat::Table &bindings,\n                                    Sqrat::Object &script_closure, string &out_err_msg,\n                                    SQCompilation::SqASTData **return_ast = nullptr);\n  bool compileScriptImpl(const sqm::span<char> buf, const char *resolved_fn, Sqrat::Table &bindings, string &out_err_msg,\n                         SQCompilation::SqASTData **return_ast = nullptr);\n\n  Sqrat::Table setupStateStorage(const char *resolved_fn);\n\n  Module *findModule(const char *resolved_fn);\n\n  typedef SQInteger (*RegFunc)(HSQUIRRELVM);\n  void registerStdLibNativeModule(const char *name, RegFunc);\n\n  Sqrat::Array getNativeModuleNames();\n\n  BeforeImportModuleCallback beforeImportModuleCb;\n\n  bool mergeBindings(Sqrat::Table &target, Sqrat::Object &key, Sqrat::Object &value, string &out_err_msg);\n  bool mergeBindings(Sqrat::Table &target, Sqrat::Table &upd, string &out_err_msg);\n  bool importModules(const char *resolved_fn, Sqrat::Table &bindings_dest, const SQModuleImport *imports, int num_imports,\n    string &out_err_msg);\n\n  static SQInteger register_on_module_unload(HSQUIRRELVM vm);\n  void callAndClearUnloadHandlers(bool is_closing);\n\npublic:\n  static const char *__main__, *__fn__, *__analysis__;\n\n  struct\n  {\n    bool raiseError;\n    bool doStaticAnalysis;\n  } compilationOptions;\n\n  void *up_data;\n  void (*onAST_cb)(HSQUIRRELVM, SQCompilation::SqASTData *, void *);\n  void (*onBytecode_cb)(HSQUIRRELVM, HSQOBJECT, void *);\n  SQOnCompileFileCb onCompileFile_cb = nullptr;\n\nprivate:\n  vector<Module> modules;\n  vector<Module> prevModules; //< for hot reload\n  vector<Sqrat::Object> runningScriptClosuresStack;\n\n#if defined(SQRAT_HAS_EASTL)\n  using NativeModulesMap = eastl::vector_map<string, Sqrat::Object>;\n#else\n  using NativeModulesMap = std::unordered_map<string, Sqrat::Object>;\n#endif\n\n  NativeModulesMap nativeModules;\n\n  vector<string> runningScripts;\n  vector<Sqrat::Object> onModuleUnload;\n  HSQUIRRELVM sqvm = nullptr;\n\n  ISqModulesFileAccess *fileAccess = nullptr;\n};\n\ntemplate <typename F>\ninline void SqModules::forEachNativeModule(const F &cb)\n{\n  for (auto &nm : nativeModules)\n    cb(nm.first.data(), nm.second);\n}\n\ninline Sqrat::Object *SqModules::findNativeModule(const char *module_name)\n{\n  auto it = nativeModules.find(module_name);\n  return (it == nativeModules.end()) ? nullptr : &it->second;\n}\n"
  },
  {
    "path": "sqrat/README.txt",
    "content": "Sqrat - Quirrel Binding Utility\n\n© 2009 Brandon Jones\n© 2011-2014 Li-Cheng (Andy) Tai\n© 2013-2015 Brandon Haffen AKA Wizzard\n© 2016-2019 Gaijin Entertainment\n\n\nSqrat is a C++ binding utility for the quirrel language.\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratAllocator.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratAllocator: Custom Class Allocation/Deallocation\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_ALLOCATOR_H_)\n#define _SQRAT_ALLOCATOR_H_\n\n#include <squirrel.h>\n#include <sqstdaux.h>\n#include <string.h>\n\n#include \"sqratObject.h\"\n#include \"sqratTypes.h\"\n\nnamespace Sqrat {\n\nnamespace vargs\n{\n  template<typename T>\n  T&  extract(Var<T>& var)\n  {\n    return  var.value;\n  }\n\n  template<typename T>\n  T  extract(T&& var)\n  {\n    return  var;\n  }\n\n  template <class C, class Tuple, size_t... Indexes>\n  C *apply_ctor_helper(SQRAT_STD::index_sequence<Indexes...>, Tuple &&args)\n  {\n    (void)args; // 'args' is unused in case of empty 'Indexes'\n    return new C(extract(SQRAT_STD::get<Indexes>(args))...);\n  }\n\n  template <class C, class Tuple>\n  C *apply_ctor(Tuple &&tup)\n  {\n    constexpr auto argsN = SQRAT_STD::tuple_size<SQRAT_STD::decay_t<Tuple>>::value;\n    return apply_ctor_helper<C>(SQRAT_STD::make_index_sequence<argsN>(), tup);\n  }\n\n  template <class C, class Tuple, size_t... Indexes>\n  void apply_placement_ctor_helper(void *mem, SQRAT_STD::index_sequence<Indexes...>, Tuple &&args)\n  {\n    (void)args;\n    new (mem) C(extract(SQRAT_STD::get<Indexes>(args))...);\n  }\n\n  template <class C, class Tuple>\n  void apply_placement_ctor(void *mem, Tuple &&tup)\n  {\n    constexpr auto argsN = SQRAT_STD::tuple_size<SQRAT_STD::decay_t<Tuple>>::value;\n    apply_placement_ctor_helper<C>(mem, SQRAT_STD::make_index_sequence<argsN>(), tup);\n  }\n}\n\ntemplate <class T, bool b>\nstruct NewC\n{\n    T* p;\n    NewC()\n    {\n       p = new T();\n    }\n};\n\ntemplate <class T>\nstruct NewC<T, false>\n{\n    T* p;\n    NewC()\n    {\n       p = 0;\n    }\n};\n\ntemplate<class C>\nclass DefaultAllocator {\n\npublic:\n\n    static SQInteger New(HSQUIRRELVM vm) {\n        if constexpr (SQRAT_STD::is_default_constructible<C>::value && sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT) {\n            C* ptr = nullptr;\n            sq_getinstanceup(vm, 1, (SQUserPointer*)&ptr, nullptr);\n            if (ptr) {\n                new (ptr) C();\n                sq_setreleasehook(vm, 1, &ClassType<C>::DestructInline);\n                return 0;\n            }\n        }\n        ClassType<C>::SetManagedInstance(vm, 1, NewC<C, SQRAT_STD::is_default_constructible<C>::value >().p);\n        return 0;\n    }\n\n    static SQInteger iNew(HSQUIRRELVM vm) {\n        return New(vm);\n    }\n\n    template <typename...A>\n    static SQInteger iNew(HSQUIRRELVM vm) {\n        if (!vargs::check_var_types<A...>(vm, 2))\n            return SQ_ERROR;\n        auto vars = vargs::make_vars<A...>(vm, 2);\n        if constexpr (sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT) {\n            C* ptr = nullptr;\n            sq_getinstanceup(vm, 1, (SQUserPointer*)&ptr, nullptr);\n            if (ptr) {\n                vargs::apply_placement_ctor<C>(ptr, SQRAT_STD::move(vars));\n                sq_setreleasehook(vm, 1, &ClassType<C>::DestructInline);\n                return 0;\n            }\n        }\n        C *inst = vargs::apply_ctor<C>(vars);\n        ClassType<C>::SetManagedInstance(vm, 1, inst);\n        return 0;\n    }\n\npublic:\n\n    // Copy using inline userdata (placement new into SQInstance's inline space)\n    // or heap allocation as fallback for large types.\n    static SQInteger Copy(HSQUIRRELVM vm, SQInteger idx, const void* value) {\n        if constexpr (sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT) {\n            // Inline path: _userpointer already points to inline space from sq_createinstance\n            C* ptr = nullptr;\n            sq_getinstanceup(vm, idx, (SQUserPointer*)&ptr, nullptr);\n            if (ptr) {\n                new (ptr) C(*static_cast<const C*>(value));\n                sq_setreleasehook(vm, idx, &ClassType<C>::DestructInline);\n                return 0;\n            }\n        }\n        // Fallback: heap allocation\n        ClassType<C>::SetManagedInstance(vm, idx, new C(*static_cast<const C*>(value)));\n        return 0;\n    }\n};\n\ntemplate<class C>\nclass NoConstructor {\npublic:\n\n    static SQInteger New(HSQUIRRELVM vm) {\n        return sqstd_throwerrorf(vm, \"Construction of %s is not allowed\", ClassType<C>::ClassName().c_str());\n    }\n\n    static SQInteger Copy(HSQUIRRELVM vm, SQInteger idx, const void* value) {\n        SQRAT_UNUSED(vm);\n        SQRAT_UNUSED(idx);\n        SQRAT_UNUSED(value);\n        return sqstd_throwerrorf(vm, \"Cloning of %s is not allowed\", ClassType<C>::ClassName().c_str());\n    }\n};\n\ntemplate<class C>\nclass CopyOnly {\npublic:\n\n    static SQInteger New(HSQUIRRELVM vm) {\n        return sqstd_throwerrorf(vm, \"Construction of %s is not allowed\", ClassType<C>::ClassName().c_str());\n    }\n\n    static SQInteger Copy(HSQUIRRELVM vm, SQInteger idx, const void* value) {\n        if constexpr (sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT) {\n            C* ptr = nullptr;\n            sq_getinstanceup(vm, idx, (SQUserPointer*)&ptr, nullptr);\n            if (ptr) {\n                new (ptr) C(*static_cast<const C*>(value));\n                sq_setreleasehook(vm, idx, &ClassType<C>::DestructInline);\n                return 0;\n            }\n        }\n        ClassType<C>::SetManagedInstance(vm, idx, new C(*static_cast<const C*>(value)));\n        return 0;\n    }\n};\n\n\ntemplate<class C>\nclass NoCopy {\npublic:\n\n    static SQInteger New(HSQUIRRELVM vm) {\n        ClassType<C>::SetManagedInstance(vm, 1, NewC<C, SQRAT_STD::is_default_constructible<C>::value >().p);\n        return 0;\n    }\n\n    static SQInteger iNew(HSQUIRRELVM vm) {\n        return New(vm);\n    }\n\n    template <typename...A>\n    static SQInteger iNew(HSQUIRRELVM vm) {\n        if (!vargs::check_var_types<A...>(vm, 2))\n            return SQ_ERROR;\n        auto vars = vargs::make_vars<A...>(vm, 2);\n        C *inst = vargs::apply_ctor<C>(vars);\n        ClassType<C>::SetManagedInstance(vm, 1, inst);\n        return 0;\n    }\n\n    static SQInteger Copy(HSQUIRRELVM vm, SQInteger idx, const void* value) {\n        SQRAT_UNUSED(vm);\n        SQRAT_UNUSED(idx);\n        SQRAT_UNUSED(value);\n        return sqstd_throwerrorf(vm, \"Cloning of %s is not allowed\", ClassType<C>::ClassName().c_str());\n    }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratArray.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratArray: Array Binding\n//\n\n//\n// Copyright 2011 Alston Chen\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_ARRAY_H_)\n#define _SQRAT_ARRAY_H_\n\n#include <squirrel.h>\n#include <string.h>\n\n#include \"sqratObject.h\"\n#include \"sqratFunction.h\"\n#include \"sqratGlobalMethods.h\"\n\nnamespace Sqrat {\n\nclass ArrayBase : public Object {\npublic:\n    ArrayBase() {\n    }\n\n    ArrayBase(HSQUIRRELVM v) : Object(v) {\n    }\n\n    ArrayBase(const Object& obj) : Object(obj) {\n    }\n\n    ArrayBase(HSQOBJECT o, HSQUIRRELVM v) : Object(o, v) {\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Binds a Table or Class to the specific element of Array (can be used to facilitate namespaces)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    void Bind(const SQInteger index, Object& object) {\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n        sq_pushobject(vm, object.GetObject());\n        sq_set(vm, -3);\n        sq_pop(vm,1); // pop array\n    }\n\n\n    template<class V>\n    ArrayBase& SetValue(const SQInteger index, const V& val) {\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n        PushVar(vm, val);\n        sq_set(vm, -3);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Sets an index in the Array to a specific instance (like a reference)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template<class V>\n    ArrayBase& SetInstance(const SQInteger index, V* val) {\n        BindInstance<V>(index, val, false);\n        return *this;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Sets an index in the Array to a specific function\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template<class F>\n    ArrayBase& Func(const SQInteger index, F method) {\n        BindFunc<F>(index, method, SqGlobalThunk<F>(), 1+SqGetArgCount<F>());\n        return *this;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Returns the element at a given index\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <typename T>\n    T GetValue(int index)\n    {\n        sq_pushobject(vm, obj);\n        sq_pushinteger(vm, index);\n        if (SQ_FAILED(sq_get(vm, -2))) {\n            sq_pop(vm, 1);\n            SQRAT_ASSERT(0); // Ensure that index is valid before calling this method\n            return T();\n        }\n\n        Var<T> element(vm, -1);\n        sq_pop(vm, 2);\n        return element.value;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Gets a Function from an index in the Array\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    Function GetFunction(const SQInteger index) {\n        HSQOBJECT funcObj;\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n        if(SQ_FAILED(sq_get(vm, -2))) {\n            sq_pop(vm, 1);\n            return Function();\n        }\n        SQObjectType value_type = sq_gettype(vm, -1);\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {\n            sq_pop(vm, 2);\n            return Function();\n        }\n\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &funcObj)));\n        Function ret(vm, GetObject(), funcObj); // must addref before the pop!\n        sq_pop(vm, 2);\n        return ret;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Fills a C array with the elements of the Array\n    ///\n    /// \\param array C array to be filled\n    /// \\param size  The amount of elements to fill the C array with\n    ///\n    /// \\tparam T Type of elements (fails if any elements in Array are not of this type)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <typename T>\n    void GetArray(T* array, int size)\n    {\n        HSQOBJECT value = GetObject();\n        sq_pushobject(vm, value);\n        // Before calling this method ensure that size provided size matches array's one\n        SQRAT_ASSERTF(size==sq_getsize(vm, -1), \"array size mismatch (%d vs %d)\", size, sq_getsize(vm, -1));\n\n        sq_pushnull(vm);\n        SQInteger i;\n        while (SQ_SUCCEEDED(sq_next(vm, -2))) {\n            sq_getinteger(vm, -2, &i);\n            if (i >= size) break;\n            Var<const T&> element(vm, -1); // TODO: handle error\n            sq_pop(vm, 2);\n            array[i] = element.value;\n        }\n        sq_pop(vm, 2); // pops the null iterator and the array object\n    }\n\n    template<class V>\n    ArrayBase& Append(const V& val) {\n        sq_pushobject(vm, GetObject());\n        PushVar(vm, val);\n        sq_arrayappend(vm, -2);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    template<class V>\n    ArrayBase& Append(V* val) {\n        sq_pushobject(vm, GetObject());\n        PushVar(vm, val);\n        sq_arrayappend(vm, -2);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    template<class V>\n    ArrayBase& Insert(const SQInteger destpos, const V& val) {\n        sq_pushobject(vm, GetObject());\n        PushVar(vm, val);\n        sq_arrayinsert(vm, -2, destpos);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    template<class V>\n    ArrayBase& Insert(const SQInteger destpos, V* val) {\n        sq_pushobject(vm, GetObject());\n        PushVar(vm, val);\n        sq_arrayinsert(vm, -2, destpos);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Removes the last element from the Array and returns it (returns null if failed)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    Object Pop() {\n        HSQOBJECT slotObj;\n        sq_pushobject(vm, GetObject());\n        if(SQ_FAILED(sq_arraypop(vm, -1, true))) {\n            sq_pop(vm, 1);\n            return Object(); // Return a NULL object\n        } else {\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &slotObj)));\n            Object ret(slotObj, vm);\n            sq_pop(vm, 2);\n            return ret;\n        }\n    }\n\n    ArrayBase& Remove(const SQInteger itemidx) {\n        sq_pushobject(vm, GetObject());\n        sq_arrayremove(vm, -1, itemidx);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    ArrayBase& Resize(const SQInteger newsize) {\n        sq_pushobject(vm, GetObject());\n        sq_arrayresize(vm, -1, newsize);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    ArrayBase& Reverse() {\n        sq_pushobject(vm, GetObject());\n        sq_arrayreverse(vm, -1);\n        sq_pop(vm,1); // pop array\n        return *this;\n    }\n\n    SQInteger Length() const {\n        sq_pushobject(vm, obj);\n        SQInteger r = sq_getsize(vm, -1);\n        sq_pop(vm, 1);\n        return r;\n    }\n\n    bool Clear() {\n        sq_pushobject(vm, GetObject());\n        bool ok = SQ_SUCCEEDED(sq_clear(vm, -1));\n        sq_pop(vm, 1); // pop array\n        return ok;\n    }\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Represents an array in Squirrel\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\nclass Array : public ArrayBase {\npublic:\n    Array() {\n    }\n\n    Array(HSQUIRRELVM v, const SQInteger size = 0) : ArrayBase(v) {\n        SQRAT_ASSERT(v);\n        sq_newarray(vm, size);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,-1,&obj)));\n        sq_addref(vm, &obj);\n        sq_pop(vm,1);\n    }\n\n    Array(const Object& obj) : ArrayBase(obj) {\n    }\n\n    Array(HSQOBJECT o, HSQUIRRELVM v) : ArrayBase(o, v) {\n    }\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Used to get and push Array instances to and from the stack as references (arrays are always references in Squirrel)\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<>\nstruct Var<Array> {\n\n    Array value; ///< The actual value of get operations\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Attempts to get the value off the stack at idx as an Array\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        HSQOBJECT obj;\n        sq_resetobject(&obj);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,idx,&obj)));\n        value = Array(obj, vm);\n        SQObjectType value_type = sq_gettype(vm, idx);\n        if (value_type != OT_ARRAY && value_type != OT_NULL) {\n            SQRAT_ASSERTF(0, FormatTypeError(vm, idx, \"array\").c_str());\n        }\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Called by Sqrat::PushVar to put an Array reference on the stack\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    static void push(HSQUIRRELVM vm, const Array& value) {\n        HSQOBJECT obj;\n        sq_resetobject(&obj);\n        obj = value.GetObject();\n        sq_pushobject(vm,obj);\n    }\n\n    static const char * getVarTypeName() { return \"array\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        return sq_gettype(vm, idx) == OT_ARRAY || sq_gettype(vm, idx) == OT_NULL;\n    }\n};\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Used to get and push Array instances to and from the stack as references (arrays are always references in Squirrel)\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<>\nstruct Var<Array&> : Var<Array> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Array>(vm, idx) {}};\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Used to get and push Array instances to and from the stack as references (arrays are always references in Squirrel)\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<>\nstruct Var<const Array&> : Var<Array> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Array>(vm, idx) {}};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratClass.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratClass: Class Binding\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//    1. The origin of this software must not be misrepresented; you must not\n//    claim that you wrote the original software. If you use this software\n//    in a product, an acknowledgment in the product documentation would be\n//    appreciated but is not required.\n//\n//    2. Altered source versions must be plainly marked as such, and must not be\n//    misrepresented as being the original software.\n//\n//    3. This notice may not be removed or altered from any source\n//    distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_CLASS_H_)\n#define _SQRAT_CLASS_H_\n\n#include <squirrel.h>\n#include <string.h>\n\n#include \"sqratObject.h\"\n#include \"sqratClassType.h\"\n#include \"sqratMemberMethods.h\"\n#include \"sqratAllocator.h\"\n#include \"sqratTypes.h\"\n\n\nnamespace Sqrat\n{\n\n// Maps C++ types to SQNFT_* constants for sq_registernativefield.\ntemplate<typename T> struct NativeFieldTypeFor;\ntemplate<> struct NativeFieldTypeFor<float>    { enum { value = SQNFT_FLOAT32 }; };\ntemplate<> struct NativeFieldTypeFor<double>   { enum { value = SQNFT_FLOAT64 }; };\ntemplate<> struct NativeFieldTypeFor<int32_t>  { enum { value = SQNFT_INT32 }; };\ntemplate<> struct NativeFieldTypeFor<int64_t>  { enum { value = SQNFT_INT64 }; };\ntemplate<> struct NativeFieldTypeFor<bool>     { enum { value = SQNFT_BOOL }; };\n\ntemplate<class C> struct InstanceToString;\n\n\n/// Facilitates exposing a C++ class with no base class to Squirrel\n///\n/// \\tparam C Class type to expose\n/// \\tparam A An allocator to use when instantiating and destroying class instances of this type in Squirrel\n///\n/// \\remarks\n/// DefaultAllocator is used if no allocator is specified. This should be sufficent for most classes,\n/// but if specific behavior is desired, it can be overridden. If the class should not be instantiated from\n/// Squirrel the NoConstructor allocator may be used. See NoCopy and CopyOnly too.\ntemplate<class C, class A = DefaultAllocator<C> >\nclass Class\n{\nprotected:\n  HSQUIRRELVM vm = nullptr;\n\npublic:\n\n    /// \\param v           Squirrel virtual machine to create the Class for\n    /// \\param className   A necessarily unique name for the class that can appear in error messages\n    /// \\param createClass Should class type data be created? (almost always should be true - don't worry about it)\n    Class(HSQUIRRELVM v, string && className, bool createClass = true) : vm(v) {\n        if (createClass && !ClassType<C>::hasClassData(v)) {\n            // Register static TypeTag (once per type, first VM wins)\n            TypeTag<C>* tag = TypeTag<C>::get();\n            TypeTagBase::allTypeTags().insert(tag);\n\n            // Create per-VM ClassData\n            ClassData<C>* cd = new ClassData<C>;\n            cd->copyFunc = &A::Copy;\n            cd->className = className;\n\n            if (ClassData<C>::staticClassName.empty()) {\n                ClassData<C>::staticClassName = className;\n                tag->className = ClassData<C>::staticClassName.c_str();\n            }\n\n            ClassType<C>::setClassData(v, cd);\n            SqratCleanup::getOrCreate(v)->add<C>(cd);\n\n            HSQOBJECT& classObj = cd->classObj; //-V522\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_newclass(v, false)));\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(v, -1, &classObj)));\n            sq_addref(v, &classObj); // must addref before the pop!\n            sq_pop(v, 1);\n            InitClass(cd);\n        }\n    }\n\n    /// Gets the Squirrel object for this Class (copy)\n    HSQOBJECT GetObject() const {\n        return ClassType<C>::getClassData(vm)->classObj; //-V522\n    }\n\n    /// Gets the Squirrel object for this Class (reference)\n    HSQOBJECT& GetObject() {\n        return ClassType<C>::getClassData(vm)->classObj; //-V522\n    }\n\npublic:\n\n    /// Binds a class variable of type V (getter + setter)\n    template<class V>\n    Class& Var(const char* name, V C::* var) {\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        BindAccessor(name, &var, sizeof(var), &sqDefaultGet<C, V>, cd->getTable); //-V522\n        BindAccessor(name, &var, sizeof(var), &sqDefaultSet<C, V>, cd->setTable); //-V522\n        return *this;\n    }\n\n    /// Binds a class variable without a setter (read-only)\n    template<class V>\n    Class& ConstVar(const char* name, V C::* var) {\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        BindAccessor(name, &var, sizeof(var), &sqDefaultGet<C, V>, cd->getTable); //-V522\n        return *this;\n    }\n\n    /// Binds a native field for direct VM access (no metamethod dispatch).\n    /// Only works for primitive types (float, double, int32_t, int64_t, bool)\n    /// on classes with inline userdata.\n    template<class V>\n    Class& NativeVar(const char* name, V C::* member) {\n        static_assert(sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT,\n                      \"NativeVar requires type to fit in inline userdata\");\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        sq_pushobject(vm, cd->classObj); //-V522\n        alignas(C) char buf[sizeof(C)] = {};\n        C* dummy = reinterpret_cast<C*>(buf);\n        SQInteger offset = (SQInteger)((const char*)&(dummy->*member) - (const char*)dummy);\n        SQRESULT res = sq_registernativefield(vm, -1, name, offset, NativeFieldTypeFor<V>::value);\n        SQRAT_UNUSED(res);\n        SQRAT_ASSERTF(SQ_SUCCEEDED(res),\n            \"NativeVar('%s') failed: call UseInlineUserdata() before registering native fields\", name);\n        sq_pop(vm, 1);\n        return *this;\n    }\n\n    template<class V>\n    Class& StaticVar(const char* name, V* var) {\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        BindAccessor(name, &var, sizeof(var), &sqStaticGet<C, V>, cd->getTable); //-V522\n        BindAccessor(name, &var, sizeof(var), &sqStaticSet<C, V>, cd->setTable); //-V522\n        return *this;\n    }\n\n    template<class F1, class F2>\n    Class& Prop(const char* name, F1 getMethod, F2 setMethod) {\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        if(getMethod != NULL)\n            BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberFunc<C, F1>(), cd->getTable); //-V522\n        if(setMethod != NULL)\n            BindAccessor(name, &setMethod, sizeof(setMethod), SqMemberFunc<C, F2>(), cd->setTable); //-V522\n        return *this;\n    }\n\n    template<class F1, class F2>\n    Class& GlobalProp(const char* name, F1 getMethod, F2 setMethod) {\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        if(getMethod != NULL)\n            BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberGlobalThunk<F1>(), cd->getTable); //-V522\n        if(setMethod != NULL)\n            BindAccessor(name, &setMethod, sizeof(setMethod), SqMemberGlobalThunk<F2>(), cd->setTable); //-V522\n        return *this;\n    }\n\n    template<class F>\n    Class& Prop(const char* name, F getMethod) {\n        BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberFunc<C, F>(), ClassType<C>::getClassData(vm)->getTable); //-V522\n        return *this;\n    }\n\n    Class& SquirrelProp(const char* name, SQFUNCTION getMethod, const char *docstring=nullptr) {\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->getTable); //-V522\n        sq_pushstring(vm, name, -1);\n        sq_newclosure(vm, getMethod, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, 1, \"x\")));\n        if (docstring)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm, 1);\n        return *this;\n    }\n\n    Class& SquirrelProp(const char* name, SQFUNCTION getMethod, SQFUNCTION setMethod, const char *docstring=nullptr) {\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->getTable); //-V522\n        sq_pushstring(vm, name, -1);\n        sq_newclosure(vm, getMethod, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, 1, \"x\")));\n        if (docstring)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm, 1);\n\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->setTable);\n        sq_pushstring(vm, name, -1);\n        sq_newclosure(vm, setMethod, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, 2, \"x.\")));\n        if (docstring)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm, 1);\n        return *this;\n    }\n\n    /// Binds a read-only class property (using a global function instead of a member function)\n    template<class F>\n    Class& GlobalProp(const char* name, F getMethod) {\n        BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberGlobalThunk<F>(), ClassType<C>::getClassData(vm)->getTable); //-V522\n        return *this;\n    }\n\n    /// Binds a class function\n    template<class F>\n    Class& Func(const char* name, F method, const char *docstring=nullptr) { //-V1071\n        BindFunc(name, method, SqMemberFunc<C, F>(), 1+SqGetArgCount<F>(), false, docstring);\n        return *this;\n    }\n\n    /// Binds a global function as a class function\n    template<class F>\n    Class& GlobalFunc(const char* name, F method, const char *docstring=nullptr) { //-V1071\n        BindFunc(name, method, SqMemberGlobalThunk<F>(), SqGetArgCount<F>(), false, docstring);\n        return *this;\n    }\n\n    /// Binds a static class function\n    template<class F>\n    Class& StaticFunc(const char* name, F method, const char *docstring=nullptr) { //-V1071\n        BindFunc(name, method, SqGlobalThunk<F>(), 1+SqGetArgCount<F>(), false, docstring);\n        return *this;\n    }\n\n    /// Binds a raw Squirrel function as a class function.\n    /// The class instance will be at index 1, arguments after that.\n    Class& SquirrelFunc(const char* name, SQFUNCTION func, SQInteger nparamscheck, const char *typemask=nullptr,\n                        const char *docstring=nullptr, SQInteger nfreevars=0, const Object *freevars=nullptr, //-V1071\n                        FunctionPurity purity=FunctionPurity::SideEffects) {\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->classObj); //-V522\n        sq_pushstring(vm, name, -1);\n        for (SQInteger i=0; i<nfreevars; ++i)\n            sq_pushobject(vm, freevars[i].GetObject());\n        sq_newclosure(vm, func, nfreevars);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, nparamscheck, typemask)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosurename(vm, -1, name)));\n        if (purity == FunctionPurity::Pure)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_mark_pure_inplace(vm, -1)));\n        if (docstring)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm, 1);\n        return *this;\n    }\n\n    Class& SquirrelFuncDeclString(SQFUNCTION func, const char *function_decl,\n                                  const char *docstring=nullptr, SQInteger nfreevars=0, const Object *freevars=nullptr) {\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->classObj); //-V522\n        for (SQInteger i=0; i<nfreevars; ++i)\n            sq_pushobject(vm, freevars[i].GetObject());\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_new_closure_slot_from_decl_string(vm, func, nfreevars, function_decl, docstring)));\n        sq_pop(vm,1);\n        return *this;\n    }\n\n    /// Gets a Function from a name in the Class (returns null if failed)\n    Function GetFunction(const char* name) {\n        ClassData<C>* cd = ClassType<C>::getClassData(vm);\n        HSQOBJECT funcObj;\n        sq_pushobject(vm, cd->classObj); //-V522\n        sq_pushstring(vm, name, -1);\n        if(SQ_FAILED(sq_get(vm, -2))) {\n            sq_pop(vm, 1);\n            return Function();\n        }\n        SQObjectType value_type = sq_gettype(vm, -1);\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE && value_type != OT_CLASS) {\n            sq_pop(vm, 2);\n            return Function();\n        }\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &funcObj)));\n        Function ret(vm, cd->classObj, funcObj);\n        sq_pop(vm, 2);\n        return ret;\n    }\n\nprotected:\n\n    template<class Func>\n    void BindFunc(const char* name, Func func, SQFUNCTION func_thunk, SQInteger nparamscheck, bool staticVar = false, const char *docstring=nullptr)\n    {\n      sq_pushobject(vm, GetObject());\n      sq_pushstring(vm, name, -1);\n\n      SQUserPointer funcPtr = sq_newuserdata(vm, sizeof(func));\n      new (funcPtr) Func(func);\n      sq_setreleasehook(vm, -1, ImplaceFreeReleaseHook<Func>);\n\n      sq_newclosure(vm, func_thunk, 1);\n      if (nparamscheck > 0)\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, nparamscheck, nullptr)));\n      SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosurename(vm, -1, name)));\n      if (docstring)\n          SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n\n      SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n      sq_pop(vm,1);\n    }\n\n    static SQInteger ClassWeakref(HSQUIRRELVM vm) {\n        sq_weakref(vm, -1);\n        return 1;\n    }\n\n    static SQInteger ClassTypeof(HSQUIRRELVM vm) {\n        sq_pushstring(vm, ClassType<C>::ClassName().c_str(), -1);\n        return 1;\n    }\n\n    static SQInteger ClassCloned(HSQUIRRELVM vm) {\n        Sqrat::Var<const C*> other(vm, 2);\n        return ClassType<C>::CopyFunc(vm)(vm, 1, other.value);\n    }\n\n    // Initialize the required data structure for the class\n    void InitClass(ClassData<C>* cd) {\n        // push the class\n        sq_pushobject(vm, cd->classObj);\n\n        // set the typetag to static TypeTag (VM-independent type identity)\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_settypetag(vm, -1, TypeTag<C>::get())));\n\n        // add the default constructor\n        this->BindConstructor(&A::New, 0);\n\n        // add the set table (static)\n        HSQOBJECT& setTable = cd->setTable;\n        sq_pushstring(vm, \"__setTable\", -1);\n        sq_newtable(vm);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &setTable)));\n        sq_addref(vm, &setTable);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, true)));\n\n        // add the get table (static)\n        HSQOBJECT& getTable = cd->getTable;\n        sq_pushstring(vm, \"__getTable\", -1);\n        sq_newtable(vm);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &getTable)));\n        sq_addref(vm, &getTable);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, true)));\n\n        // override _set\n        sq_pushstring(vm, \"_set\", -1);\n        sq_pushobject(vm, setTable); // Push the set table as a free variable\n        sq_newclosure(vm, &sqVarSet, 1);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // override _get\n        sq_pushstring(vm, \"_get\", -1);\n        sq_pushobject(vm, getTable); // Push the get table as a free variable\n        sq_newclosure(vm, &sqVarGet, 1);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add weakref\n        sq_pushstring(vm, \"weakref\", -1);\n        sq_newclosure(vm, &Class::ClassWeakref, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add _typeof\n        sq_pushstring(vm, \"_typeof\", -1);\n        sq_newclosure(vm, &Class::ClassTypeof, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add _cloned\n        sq_pushstring(vm, \"_cloned\", -1);\n        sq_newclosure(vm, &Class::ClassCloned, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add _tostring\n        sq_pushstring(vm, \"_tostring\", -1);\n        sq_newclosure(vm, InstanceToString<C>::Format, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // pop the class\n        sq_pop(vm, 1);\n    }\n\n    inline void BindAccessor(const char* name, void* var, size_t varSize, SQFUNCTION func, HSQOBJECT table) {\n        // Push the get or set table\n        sq_pushobject(vm, table);\n        sq_pushstring(vm, name, -1);\n\n        // Push the variable offset as a free variable\n        SQUserPointer varPtr = sq_newuserdata(vm, static_cast<SQUnsignedInteger>(varSize));\n        memcpy(varPtr, var, varSize);\n\n        // Create the accessor function\n        sq_newclosure(vm, func, 1);\n\n        // Add the accessor to the table\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // Pop get/set table\n        sq_pop(vm, 1);\n    }\n\n    Class& BindConstructor(SQFUNCTION method, SQInteger nParams) {\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->classObj); //-V522\n        sq_pushstring(vm, \"constructor\", 11);\n        sq_newclosure(vm, method, 0);\n        sq_setparamscheck(vm, nParams+1, NULL);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm, 1);\n        return *this;\n    }\n\npublic:\n\n    /// Enable inline userdata for this class. Instances will embed the C++ object\n    /// directly in SQInstance memory, avoiding a heap allocation. Only for small types.\n    /// Must be called before any instances are created (before the class is locked).\n    Class& UseInlineUserdata() {\n        static_assert(sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT,\n            \"Type is too large or has non-standard alignment for inline userdata\");\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->classObj); //-V522\n        sq_setclassudsize(vm, -1, sizeof(C));\n        sq_pop(vm, 1);\n        return *this;\n    }\n\n    Class& Ctor() {\n        return BindConstructor(A::iNew, 0);\n    }\n\n    template<class...Arg>\n    Class& Ctor() {\n        return BindConstructor(A::template iNew<Arg...>, sizeof...(Arg));\n    }\n\n    Class& SquirrelCtor(SQFUNCTION func, SQInteger nparamscheck=0, const char *typemask=nullptr,\n                        const char *docstring=nullptr) {\n        sq_pushobject(vm, ClassType<C>::getClassData(vm)->classObj); //-V522\n        sq_pushstring(vm, \"constructor\", 11);\n        sq_newclosure(vm, func, 0);\n        sq_setparamscheck(vm, nparamscheck, typemask);\n        if (docstring)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm, 1);\n        return *this;\n    }\n};\n\n\n/// Facilitates exposing a C++ class with a base class to Squirrel\n///\n/// \\tparam C Class type to expose\n/// \\tparam B Base class type (must already be bound)\n/// \\tparam A An allocator to use when instantiating and destroying class instances of this type in Squirrel\n///\n/// \\remarks\n/// Classes in Squirrel are single-inheritance only, and as such Sqrat only allows for single inheritance as well.\n/// You MUST bind the base class fully before constructing a derived class.\ntemplate<class C, class B, class A = DefaultAllocator<C> >\nclass DerivedClass : public Class<C, A>\n{\n  using Class<C, A>::vm;\n\npublic:\n\n    DerivedClass(HSQUIRRELVM v, string && className) : Class<C, A>(v, string(), false) {\n        if (!ClassType<C>::hasClassData(v)) {\n            // Initialize TypeTag inheritance chain (once per type)\n            TypeTag<C>* tag = TypeTag<C>::get();\n            tag->base = TypeTag<B>::get();\n            tag->castToBase = [](SQUserPointer p) -> SQUserPointer {\n                return static_cast<B*>(static_cast<C*>(p));\n            };\n            TypeTag<B>::get()->hasDerived = true;\n            TypeTagBase::allTypeTags().insert(tag);\n\n            // Create per-VM ClassData\n            ClassData<C>* cd = new ClassData<C>;\n            cd->copyFunc = &A::Copy;\n            cd->className = className;\n\n            if (ClassData<C>::staticClassName.empty()) {\n                ClassData<C>::staticClassName = className;\n                tag->className = ClassData<C>::staticClassName.c_str();\n            }\n\n            ClassData<B>* bd = ClassType<B>::getClassData(v);\n\n            ClassType<C>::setClassData(v, cd);\n            SqratCleanup::getOrCreate(v)->add<C>(cd);\n\n            HSQOBJECT& classObj = cd->classObj;\n            sq_pushobject(v, bd->classObj); //-V522\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_newclass(v, true)));\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(v, -1, &classObj)));\n            sq_addref(v, &classObj); // must addref before the pop!\n            sq_pop(v, 1);\n            InitDerivedClass(cd, bd);\n        }\n    }\n\nprotected:\n\n    void InitDerivedClass(ClassData<C>* cd, ClassData<B>* bd) {\n        // push the class\n        sq_pushobject(vm, cd->classObj);\n\n        // set the typetag to static TypeTag (VM-independent type identity)\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_settypetag(vm, -1, TypeTag<C>::get())));\n\n        // add the default constructor\n        this->BindConstructor(&A::New, 0);\n\n        // clone the base classes set table (static)\n        HSQOBJECT& setTable = cd->setTable;\n        sq_pushobject(vm, bd->setTable);\n        sq_pushstring(vm, \"__setTable\", -1);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_clone(vm, -2)));\n        sq_remove(vm, -3);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &setTable)));\n        sq_addref(vm, &setTable);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, true)));\n\n        // clone the base classes get table (static)\n        HSQOBJECT& getTable = cd->getTable;\n        sq_pushobject(vm, bd->getTable);\n        sq_pushstring(vm, \"__getTable\", -1);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_clone(vm, -2)));\n        sq_remove(vm, -3);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &getTable)));\n        sq_addref(vm, &getTable);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, true)));\n\n        // override _set\n        sq_pushstring(vm, \"_set\", -1);\n        sq_pushobject(vm, setTable); // Push the set table as a free variable\n        sq_newclosure(vm, sqVarSet, 1);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // override _get\n        sq_pushstring(vm, \"_get\", -1);\n        sq_pushobject(vm, getTable); // Push the get table as a free variable\n        sq_newclosure(vm, sqVarGet, 1);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add weakref\n        sq_pushstring(vm, \"weakref\", -1);\n        sq_newclosure(vm, &Class<C, A>::ClassWeakref, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add _typeof\n        sq_pushstring(vm, \"_typeof\", -1);\n        sq_newclosure(vm, &Class<C, A>::ClassTypeof, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add _cloned\n        sq_pushstring(vm, \"_cloned\", -1);\n        sq_newclosure(vm, &Class<C, A>::ClassCloned, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // add _tostring\n        sq_pushstring(vm, \"_tostring\", -1);\n        sq_newclosure(vm, InstanceToString<C>::Format, 0);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n\n        // pop the class\n        sq_pop(vm, 1);\n    }\n};\n\n\ntemplate<class C>\nstruct InstanceToString {\n  static SQInteger Format(HSQUIRRELVM vm) {\n    return ClassType<C>::ToString(vm);\n  }\n};\n\n\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratClassType.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratClassType: Type Translators\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//    1. The origin of this software must not be misrepresented; you must not\n//    claim that you wrote the original software. If you use this software\n//    in a product, an acknowledgment in the product documentation would be\n//    appreciated but is not required.\n//\n//    2. Altered source versions must be plainly marked as such, and must not be\n//    misrepresented as being the original software.\n//\n//    3. This notice may not be removed or altered from any source\n//    distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_CLASSTYPE_H_)\n#define _SQRAT_CLASSTYPE_H_\n\n#include <squirrel.h>\n#include \"sqratUtil.h\"\n\nnamespace Sqrat\n{\n\n// The copy function for a class\ntypedef SQInteger (*COPYFUNC)(HSQUIRRELVM, SQInteger, const void*);\n\n\n// VM-independent type identity. Static storage, one per C++ type, lives forever.\n// Used as SQClass::_typetag. Carries the inheritance chain and cast function.\nstruct TypeTagBase {\n    TypeTagBase* base = nullptr;\n    SQUserPointer (*castToBase)(SQUserPointer) = nullptr;\n    const char* className = nullptr; // set once during first registration\n    bool hasDerived = false;\n\n    // Validates that a type tag pointer is a Sqrat TypeTag.\n    // Entries are added at registration and never removed (safe to read after init).\n    static hash_set<TypeTagBase*>& allTypeTags() {\n        static hash_set<TypeTagBase*> s; //-V1096\n        return s;\n    }\n    static bool isSqratTypeTag(const void* tag) {\n        return tag && allTypeTags().count(\n            const_cast<TypeTagBase*>(static_cast<const TypeTagBase*>(tag)));\n    }\n};\n\ntemplate<class C>\nstruct TypeTag : TypeTagBase {\n    static TypeTag instance;\n    static TypeTag* get() { return &instance; }\n};\ntemplate<class C> TypeTag<C> TypeTag<C>::instance;\n\n\n// Per-VM, per-type class data. Stored as userpointer in the VM registry.\n// Only accessed on cold paths (Push, class registration, instance tracking).\ntemplate<class C> using InstancesMap = class_hash_map<C*, HSQOBJECT>;\n\ntemplate<class C>\nstruct ClassData {\n    HSQOBJECT classObj;\n    HSQOBJECT getTable;\n    HSQOBJECT setTable;\n    COPYFUNC copyFunc = nullptr;\n    string className;\n    InstancesMap<C>* instances = nullptr;\n\n    // Static class name, set once during first registration. Same for all VMs.\n    static string staticClassName;\n\n    ClassData() {\n        sq_resetobject(&classObj);\n        sq_resetobject(&getTable);\n        sq_resetobject(&setTable);\n    }\n\n    ~ClassData() {\n        delete instances;\n    }\n};\n\ntemplate<class C> string ClassData<C>::staticClassName;\n\n\n// Cleanup sentinel -- one per VM, deletes all ClassData entries on VM close.\n// Stored as a userdata in the registry so its release hook fires during sq_close.\nstruct SqratCleanup {\n    struct Entry {\n        void* ptr;\n        void (*deleter)(void*);\n    };\n    SQRAT_STD::vector<Entry> entries;\n\n    static SQUserPointer key() {\n        static int k = 0; //-V1096\n        return &k;\n    }\n\n    template<class C>\n    void add(ClassData<C>* cd) {\n        entries.push_back({cd, [](void* p) { delete static_cast<ClassData<C>*>(p); }});\n    }\n\n    static SQInteger release(HSQUIRRELVM, SQUserPointer ptr, SQInteger) {\n        SqratCleanup** pSelf = reinterpret_cast<SqratCleanup**>(ptr);\n        SqratCleanup* self = *pSelf;\n        for (auto& e : self->entries)\n            e.deleter(e.ptr);\n        delete self;\n        return 0;\n    }\n\n    static SqratCleanup* getOrCreate(HSQUIRRELVM vm) {\n        // Look up existing sentinel in registry\n        HSQOBJECT registry;\n        sq_getregistrytableobj(vm, &registry);\n\n        HSQOBJECT sentinelKey;\n        sq_resetobject(&sentinelKey);\n        sentinelKey._type = OT_USERPOINTER;\n        sentinelKey._unVal.pUserPointer = key();\n\n        HSQOBJECT result;\n        if (SQ_SUCCEEDED(sq_obj_get(vm, &registry, &sentinelKey, &result, true))) {\n            SqratCleanup** pp;\n            sq_obj_getuserdata(&result, (SQUserPointer*)&pp, nullptr);\n            SqratCleanup *ret = *pp;\n            sq_poptop(vm);\n            return ret;\n        }\n\n        // Create new sentinel\n        sq_pushregistrytable(vm);\n        sq_pushuserpointer(vm, key());\n        SqratCleanup** pp = reinterpret_cast<SqratCleanup**>(sq_newuserdata(vm, sizeof(SqratCleanup*)));\n        *pp = new SqratCleanup();\n        sq_setreleasehook(vm, -1, &SqratCleanup::release);\n        sq_rawset(vm, -3);\n        sq_pop(vm, 1);\n        return *pp;\n    }\n};\n\n\n// Iterative cast walk using TypeTagBase inheritance chain\ninline SQUserPointer CastToTarget(SQUserPointer ptr, TypeTagBase* actual, TypeTagBase* target) {\n    while (actual != target) {\n        if (!actual || !actual->castToBase)\n            return nullptr;\n        ptr = actual->castToBase(ptr);\n        actual = actual->base;\n    }\n    return ptr;\n}\n\n\n// Internal helper class for managing classes\ntemplate<class C>\nclass ClassType {\n\npublic:\n    // Registry lookup for per-VM ClassData. Uses TypeTag address as key.\n    // Only needed on cold paths (Push, class registration, tracking).\n    static inline ClassData<C>* getClassData(HSQUIRRELVM vm) {\n        HSQOBJECT registry;\n        sq_getregistrytableobj(vm, &registry);\n\n        HSQOBJECT key;\n        sq_resetobject(&key);\n        key._type = OT_USERPOINTER;\n        key._unVal.pUserPointer = TypeTag<C>::get();\n\n        HSQOBJECT result;\n        if (SQ_FAILED(sq_obj_get(vm, &registry, &key, &result, true)))\n            return nullptr;\n\n        ClassData<C> *ret = static_cast<ClassData<C>*>(result._unVal.pUserPointer);\n        sq_poptop(vm);\n        return ret;\n    }\n\n    static inline bool hasClassData(HSQUIRRELVM vm) {\n        return getClassData(vm) != nullptr;\n    }\n\n    static inline const string& ClassName() {\n        return ClassData<C>::staticClassName;\n    }\n\n    static inline const string& ClassName(HSQUIRRELVM vm) {\n        ClassData<C>* cd = getClassData(vm);\n        SQRAT_ASSERT(cd);\n        return cd->className; //-V522\n    }\n\n    static inline COPYFUNC CopyFunc(HSQUIRRELVM vm) {\n        ClassData<C>* cd = getClassData(vm);\n        SQRAT_ASSERT(cd);\n        return cd->copyFunc; //-V522\n    }\n\n    // Type checks using static TypeTag -- zero registry lookups\n    static bool IsObjectOfClass(const HSQOBJECT *obj) {\n        TypeTagBase* actualTag = nullptr;\n        if (SQ_FAILED(sq_getobjtypetag(obj, (SQUserPointer*)&actualTag)))\n            return false;\n        if (!TypeTagBase::isSqratTypeTag(actualTag))\n            return false;\n        for (TypeTagBase* t = actualTag; t; t = t->base)\n            if (t == TypeTag<C>::get())\n                return true;\n        return false;\n    }\n\n    // Release hooks.\n    // During sq_close's GC chain walk, vm can be nullptr (_root_vm is already\n    // nulled) and ClassData is already deleted, so map erase is skipped.\n\n    // Owned: Sqrat created this object, delete it on GC.\n    static SQInteger ReleaseOwned(HSQUIRRELVM vm, SQUserPointer ptr, SQInteger) {\n        if (vm) {\n            ClassData<C>* cd = getClassData(vm);\n            if (cd && cd->instances)\n                cd->instances->erase(static_cast<C*>(ptr));\n        }\n        delete static_cast<C*>(ptr);\n        return 0;\n    }\n\n    // Borrowed: C++ owns this object, just remove from map on GC.\n    static SQInteger ReleaseBorrowed(HSQUIRRELVM vm, SQUserPointer ptr, SQInteger) {\n        if (vm) {\n            ClassData<C>* cd = getClassData(vm);\n            if (cd && cd->instances)\n                cd->instances->erase(static_cast<C*>(ptr));\n        }\n        return 0;\n    }\n\n    // Inline: object lives inside SQInstance memory, just destruct.\n    static SQInteger DestructInline(HSQUIRRELVM, SQUserPointer ptr, SQInteger) {\n        static_cast<C*>(ptr)->~C();\n        return 0;\n    }\n\n\n    static bool PushNativeInstance(HSQUIRRELVM vm, C* ptr) {\n        if (!ptr) {\n            sq_pushnull(vm);\n            return true;\n        }\n\n        ClassData<C>* cd = getClassData(vm);\n        SQRAT_ASSERT(cd); // class must be registered for this VM\n        if (!cd)\n            return false;\n\n        // Dedup: if this pointer is already known (owned or borrowed),\n        // return the existing Quirrel instance. Prevents creating a\n        // borrowed duplicate of an owned instance (which would dangle\n        // after GC deletes the owned original).\n        if (!cd->instances)\n            cd->instances = new InstancesMap<C>();\n        auto it = cd->instances->find(ptr);\n        if (it != cd->instances->end()) {\n            sq_pushobject(vm, it->second);\n            return true;\n        }\n\n        sq_pushobject(vm, cd->classObj);\n        if (SQ_FAILED(sq_createinstance(vm, -1))) {\n            SQRAT_ASSERT(!\"Failed to create class instance\");\n            sq_pop(vm, 1);\n            return false;\n        }\n        sq_remove(vm, -2);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setinstanceup(vm, -1, ptr)));\n        sq_setreleasehook(vm, -1, &ReleaseBorrowed);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &(*cd->instances)[ptr])));\n        return true;\n    }\n\n    static bool PushInstanceCopy(HSQUIRRELVM vm, const C& value) {\n        ClassData<C>* cd = getClassData(vm);\n        SQRAT_ASSERT(cd); // class must be registered for this VM\n        if (!cd)\n            return false;\n\n        sq_pushobject(vm, cd->classObj);\n        if (SQ_FAILED(sq_createinstance(vm, -1))) {\n            SQRAT_ASSERT(!\"Failed to create class instance\");\n            sq_pop(vm, 1);\n            return false;\n        }\n        sq_remove(vm, -2);\n\n        SQRESULT result = cd->copyFunc(vm, -1, &value);\n        SQRAT_UNUSED(result);\n        SQRAT_ASSERT(SQ_SUCCEEDED(result));\n        return true;\n    }\n\n    // Hot path: zero registry lookups. Uses static TypeTag for type checking.\n    static C* GetInstance(HSQUIRRELVM vm, SQInteger idx, bool nullAllowed = false) {\n        if (nullAllowed && sq_gettype(vm, idx) == OT_NULL)\n            return nullptr;\n\n        C* ptr = nullptr;\n        // TypeTag<C>::get() is a static address -- no registry lookup needed\n        if (SQ_FAILED(sq_getinstanceup(vm, idx, (SQUserPointer*)&ptr, TypeTag<C>::get()))) {\n            SQRAT_ASSERTF(0, FormatTypeError(vm, idx, ClassName().c_str()).c_str());\n            return nullptr;\n        }\n\n        if (!ptr) {\n            SQRAT_ASSERTF(0, \"got unconstructed native class (call base.constructor in the constructor of Squirrel classes that extend native classes)\");\n            return nullptr;\n        }\n\n        // Cast if actual type differs from requested type (inheritance).\n        // Skip entirely for leaf types (no derived classes) -- the common case.\n        if (TypeTag<C>::get()->hasDerived) {\n            TypeTagBase* actualTag = nullptr;\n            sq_gettypetag(vm, idx, (SQUserPointer*)&actualTag);\n            if (actualTag != TypeTag<C>::get()) {\n                ptr = static_cast<C*>(CastToTarget(ptr, actualTag, TypeTag<C>::get()));\n                SQRAT_ASSERT(ptr); // TypeTag chain must be consistent with SQClass chain\n            }\n        }\n\n        return ptr;\n    }\n\n\n    // Stackless instance extraction from HSQOBJECT.\n    // Returns nullptr on null/failure (no asserts -- callers report errors).\n    static C* GetInstanceFromObj(const HSQOBJECT &o) {\n        if (o._type == OT_NULL)\n            return nullptr;\n\n        SQUserPointer ptr = nullptr;\n        if (SQ_FAILED(sq_obj_getinstanceup(&o, &ptr, TypeTag<C>::get())))\n            return nullptr;\n\n        if (!ptr)\n            return nullptr;  // unconstructed instance\n\n        if (TypeTag<C>::get()->hasDerived) {\n            TypeTagBase *actualTag = nullptr;\n            sq_getobjtypetag(&o, (SQUserPointer *)&actualTag);\n            if (actualTag != TypeTag<C>::get()) {\n                ptr = CastToTarget(ptr, actualTag, TypeTag<C>::get());\n                SQRAT_ASSERT(ptr);\n            }\n        }\n\n        return static_cast<C *>(ptr);\n    }\n\n\n    static void SetManagedInstance(HSQUIRRELVM vm, SQInteger idx, C* ptr) {\n        sq_setinstanceup(vm, idx, ptr);\n        ClassData<C>* cd = getClassData(vm);\n        SQRAT_ASSERT(cd);\n        if (!cd->instances) //-V522\n            cd->instances = new InstancesMap<C>();\n        sq_setreleasehook(vm, idx, &ReleaseOwned);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, idx, &(*cd->instances)[ptr]))); //-V522\n    }\n\n\n    // For SquirrelCtors: allocate instance data, preferring inline if available.\n    // Returns a default-constructed C*. Caller overwrites contents as needed.\n    // Inline path: DestructInline hook, no map. Heap path: ReleaseOwned hook, map.\n    static C* AllocInstanceData(HSQUIRRELVM vm, SQInteger idx) {\n        if constexpr (sizeof(C) <= 256 && alignof(C) <= SQ_ALIGNMENT) {\n            C* ptr = nullptr;\n            sq_getinstanceup(vm, idx, (SQUserPointer*)&ptr, nullptr);\n            if (ptr) {\n                new (ptr) C();\n                sq_setreleasehook(vm, idx, &DestructInline);\n                return ptr;\n            }\n        }\n        C* ptr = new C;\n        SetManagedInstance(vm, idx, ptr);\n        return ptr;\n    }\n\n\n    static bool IsClassInstance(const HSQOBJECT &ho) {\n        SQObjectType type = sq_type(ho);\n        if (type != OT_INSTANCE)\n            return false;\n        TypeTagBase* actualTag = nullptr;\n        if (SQ_FAILED(sq_getobjtypetag(&ho, (SQUserPointer*)&actualTag)))\n            return false;\n        if (!TypeTagBase::isSqratTypeTag(actualTag))\n            return false;\n        for (TypeTagBase* t = actualTag; t; t = t->base)\n            if (t == TypeTag<C>::get())\n                return true;\n        return false;\n    }\n\n    static bool IsClassInstance(HSQUIRRELVM vm, SQInteger idx) {\n        HSQOBJECT ho;\n        sq_getstackobj(vm, idx, &ho);\n        return IsClassInstance(ho);\n    }\n\n    static SQInteger ToString(HSQUIRRELVM vm) {\n        HSQOBJECT ho;\n        sq_getstackobj(vm, 1, &ho);\n        char buf[256];\n        int l = snprintf(buf, sizeof(buf), \"%s (%p)\", ClassName().c_str(), ho._unVal.pInstance);\n        if (l >= (int)sizeof(buf))\n            l = (int)sizeof(buf) - 1;\n        sq_pushstring(vm, buf, l);\n        return 1;\n    }\n\n\n    // Store ClassData in registry as userpointer, keyed by TypeTag address\n    static void setClassData(HSQUIRRELVM vm, ClassData<C>* cd) {\n        sq_pushregistrytable(vm);\n        sq_pushuserpointer(vm, TypeTag<C>::get());\n        sq_pushuserpointer(vm, cd);\n        sq_rawset(vm, -3);\n        sq_pop(vm, 1);\n    }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratConst.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratConst: Constant and Enumeration Binding\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_CONST_H_)\n#define _SQRAT_CONST_H_\n\n#include <squirrel.h>\n#include <string.h>\n\n#include \"sqratObject.h\"\n\nnamespace Sqrat {\n\nclass Enumeration : public Object {\npublic:\n    Enumeration(HSQUIRRELVM v, bool createTable = true) : Object(v) {\n        if(createTable) {\n            sq_newtable(vm);\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,-1,&obj)));\n            sq_addref(vm, &obj);\n            sq_pop(vm,1);\n        }\n    }\n\n    template <typename T, SQRAT_STD::enable_if_t<SQRAT_STD::is_arithmetic_v<T> || SQRAT_STD::is_enum_v<T>, int> = 0>\n    Enumeration& Const(const char* name, T val) {\n        BindValue<T>(name, strlen(name), val, false);\n        return *this;\n    }\n\n    Enumeration& Const(const char* name, const char* val) {\n        BindValue<const char*>(name, strlen(name), val, false);\n        return *this;\n    }\n};\n\n\nclass ConstTable : public Enumeration {\npublic:\n    ConstTable(HSQUIRRELVM v) : Enumeration(v, false) {\n        sq_pushconsttable(vm);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,-1, &obj)));\n        sq_addref(v, &obj);\n        sq_pop(v, 1);\n    }\n\n    template <typename T>\n    ConstTable& Const(const char* name, T val) {\n        Enumeration::Const(name, val);\n        return *this;\n    }\n\n    ConstTable& Enum(const char* name, Enumeration& en) {\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name, -1);\n        sq_pushobject(vm, en.GetObject());\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm,1); // pop table\n        return *this;\n    }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratFunction.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// sqratFunction: Quirrel Function Wrapper\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n// Copyirght 2011 Li-Cheng (Andy) Tai\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_SQFUNC_H_)\n#define _SQRAT_SQFUNC_H_\n\n#include <squirrel.h>\n#include \"sqratObject.h\"\n#include \"sqratUtil.h\"\n\nnamespace Sqrat {\n\n\nclass Function  {\n\n    friend class TableBase;\n    friend class Table;\n    friend class ArrayBase;\n    friend struct Var<Function>;\n\nprivate:\n\n    HSQUIRRELVM vm;\n    HSQOBJECT env, obj;\n\npublic:\n    Function() {\n        vm = NULL;\n        sq_resetobject(&env);\n        sq_resetobject(&obj);\n    }\n\n    Function(const Function& sf) : vm(sf.vm), env(sf.env), obj(sf.obj) {\n        sq_addref(vm, &env);\n        sq_addref(vm, &obj);\n    }\n\n    Function(Function&& sf) : vm(sf.vm), env(sf.env), obj(sf.obj)\n    {\n      sf.vm = nullptr; // don't try release in moved from state\n    }\n\n    Function(const Function&&)=delete;\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Constructs a Function from a slot in an Object\n    ///\n    /// \\param e    Object that potentially contains a Squirrel function in a slot\n    /// \\param slot Name of the slot to look for the Squirrel function in\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    Function(const Object& e, const char* slot) : vm(e.GetVM()), env(e.GetObject()) {\n        sq_addref(vm, &env);\n        Object so = e.GetSlot(slot);\n        obj = so.GetObject();\n        sq_addref(vm, &obj);\n\n        SQObjectType value_type = so.GetType();\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE\n          && value_type != OT_CLASS && value_type != OT_NULL) {\n            // Note that classes can also be considered functions in Squirrel\n            SQRAT_ASSERTF(0, \"function not found in slot\");\n        }\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Constructs a Function from two Squirrel objects (one is the environment object and the other is the function object)\n    ///\n    /// \\param v VM that the function will exist in\n    /// \\param e Squirrel object that should represent the environment of the function\n    /// \\param o Squirrel object that should already represent a Squirrel function\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    Function(HSQUIRRELVM v, HSQOBJECT e, HSQOBJECT o) : vm(v), env(e), obj(o) {\n        sq_addref(vm, &env);\n        sq_addref(vm, &obj);\n    }\n\n    ~Function() {\n        Release();\n    }\n\n    Function& operator=(const Function& sf) {\n      if (&sf != this)\n      {\n        Release();\n        vm = sf.vm;\n        env = sf.env;\n        obj = sf.obj;\n        sq_addref(vm, &env);\n        sq_addref(vm, &obj);\n      }\n      return *this;\n    }\n\n    Function& operator=(Function&& sf)\n    {\n      if (&sf != this)\n      {\n        Release();\n        vm = sf.vm;\n        env = sf.env;\n        obj = sf.obj;\n        sf.vm = nullptr; // don't try release in moved from state\n      }\n      return *this;\n    }\n\n    bool IsNull() const {\n        return sq_isnull(obj);\n    }\n\n    HSQOBJECT GetEnv() const {\n        return env;\n    }\n\n    HSQOBJECT& GetEnv() {\n        return env;\n    }\n\n    HSQOBJECT GetFunc() const {\n        return obj;\n    }\n\n    HSQOBJECT& GetFunc() {\n        return obj;\n    }\n\n    HSQUIRRELVM GetVM() const {\n        return vm;\n    }\n\n    HSQUIRRELVM& GetVM() {\n        return vm;\n    }\n\n    void Release() {\n        if (vm)\n        {\n          sq_release(vm, &env);\n          sq_release(vm, &obj);\n          sq_resetobject(&env);\n          sq_resetobject(&obj);\n          vm = nullptr;\n        }\n    }\n\n    bool ExecuteDynArgs(HSQOBJECT const* args, size_t args_count) const {\n        SQRAT_ASSERT(vm);\n        if (!vm)\n            return false;\n        SQInteger top = sq_gettop(vm);\n\n        sq_pushobject(vm, obj);\n        sq_pushobject(vm, env);\n\n        for (size_t i = 0; i < args_count; ++i)\n          sq_pushobject(vm, args[i]);\n\n        HSQUIRRELVM savedVm = vm; // vm can be nulled in sq_call()\n        SQRESULT result = sq_call(vm, args_count + 1, false, SQTrue);\n        if (SQ_FAILED(result))\n            ReportCallError();\n\n        sq_settop(savedVm, top);\n\n        return SQ_SUCCEEDED(result);\n    }\n\n    template<class R>\n    Sqrat::optional<R> EvalDynArgs(HSQOBJECT const* args, size_t args_count) const {\n        if (!vm)\n            return Sqrat::nullopt;\n        SQInteger top = sq_gettop(vm);\n\n        sq_pushobject(vm, obj);\n        sq_pushobject(vm, env);\n\n        for (size_t i = 0; i < args_count; ++i)\n          sq_pushobject(vm, args[i]);\n\n        HSQUIRRELVM savedVm = vm;\n        SQRESULT result = sq_call(vm, args_count + 1, true, SQTrue);\n        if (SQ_FAILED(result)) {\n            ReportCallError();\n            sq_settop(savedVm, top);\n            return Sqrat::nullopt;\n        }\n\n        auto var = Var<R>(savedVm, -1);\n        sq_settop(savedVm, top);\n        return Sqrat::optional<R>{SQRAT_STD::move(var.value)};\n    }\n\n    template<typename R, typename... Args>\n    Sqrat::optional<R> Eval(Args const&... args) const {\n        if (!vm)\n            return Sqrat::nullopt;\n\n        SQInteger top = sq_gettop(vm);\n        sq_pushobject(vm, obj);\n        sq_pushobject(vm, env);\n        PushArgs(args...);\n\n        HSQUIRRELVM savedVm = vm;\n        SQRESULT result = sq_call(vm, sizeof...(Args) + 1, true, SQTrue);\n        if (SQ_FAILED(result)) {\n            ReportCallError();\n            sq_settop(savedVm, top);\n            return Sqrat::nullopt;\n        }\n\n        auto var = Var<R>(savedVm, -1);\n        sq_settop(savedVm, top);\n        return Sqrat::optional<R>{SQRAT_STD::move(var.value)};\n    }\n\n    template <typename... Args>\n    bool Execute(Args const&... args) const {\n        SQRAT_ASSERT(vm);\n        if (!vm)\n            return false;\n        static constexpr size_t nArgs = sizeof...(Args);\n        SQInteger top = sq_gettop(vm);\n\n        sq_pushobject(vm, obj);\n        sq_pushobject(vm, env);\n\n        PushArgs(args...);\n\n        HSQUIRRELVM savedVm = vm; // vm can be nulled in sq_call()\n        SQRESULT result = sq_call(vm, nArgs + 1, false, SQTrue);\n        if (SQ_FAILED(result))\n            ReportCallError();\n\n        sq_settop(savedVm, top);\n\n        return SQ_SUCCEEDED(result);\n    }\n\n    template <typename... Args>\n    bool operator()(Args const&... args) const {\n        return Execute(args...);\n    }\n\n    bool IsEqual(const Sqrat::Function &so) const {\n        if (IsNull() && so.IsNull()) // Nulls may have uninitialized vm\n            return true;\n        if (GetVM() != so.GetVM())\n            return false;\n\n        return sq_obj_is_equal(vm, &obj, &so.obj);\n    }\n\nprivate:\n    template<class Arg, typename... Tail>\n    void PushArgs(Arg const& arg, Tail const&... tail) const\n    {\n      PushVar(vm, arg);\n      PushArgs(tail...);\n    }\n\n    void PushArgs() const\n    {\n    }\n\n    template<class Arg, typename... Tail>\n    void PushArgsWithoutRet(Arg const& arg, Tail const&... tail) const\n    {\n      PushVar(vm, arg);\n      PushArgsWithoutRet(tail...);\n    }\n\n    template<class R>\n    void PushArgsWithoutRet(R const&) const\n    {\n    }\n\n    void ReportCallError() const\n    {\n        if (!vm)\n            return;\n        SQPRINTFUNCTION errpf = sq_geterrorfunc(vm);\n        if (!errpf)\n            return;\n        sq_pushobject(vm, obj);\n        if (SQ_SUCCEEDED(sq_getclosurename(vm, -1)))\n        {\n            const char *name;\n            if (SQ_SUCCEEDED(sq_getstring(vm, -1, &name)))\n                errpf(vm, \"Failed to call squirrel function %s\\n\", name);\n            sq_pop(vm, 1);\n        }\n        sq_pop(vm, 1);\n    }\n};\n\n\n/// Used to get and push Function instances to and from the stack as references (functions are always references in Squirrel)\ntemplate<>\nstruct Var<Function> {\n\n    Function value; ///< The actual value of get operations\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Attempts to get the value off the stack at idx as a Function\n    ///\n    /// \\param vm  Target VM\n    /// \\param idx Index trying to be read\n    ///\n    /// \\remarks\n    /// Initializes environment to null\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        HSQOBJECT sqEnv;\n        HSQOBJECT sqValue;\n        sq_resetobject(&sqEnv);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, idx, &sqValue)));\n        value = Function(vm, sqEnv, sqValue);\n\n        SQObjectType value_type = sq_gettype(vm, idx);\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE\n          && value_type != OT_CLASS && value_type != OT_NULL)\n        {\n            SQRAT_ASSERTF(0, FormatTypeError(vm, idx, \"closure\").c_str());\n        }\n    }\n\n    /// \\remarks\n    /// Initializes environment to given object\n    Var(HSQUIRRELVM vm, SQInteger idx, HSQOBJECT env) {\n        HSQOBJECT sqValue;\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, idx, &sqValue)));\n        value = Function(vm, env, sqValue);\n\n        SQObjectType value_type = sq_gettype(vm, idx);\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE\n          && value_type != OT_CLASS && value_type != OT_NULL)\n        {\n            SQRAT_ASSERTF(0, FormatTypeError(vm, idx, \"closure\").c_str());\n        }\n    }\n\n    /// Called by Sqrat::PushVar to put a Function on the stack\n    static void push(HSQUIRRELVM vm, const Function& value) {\n        sq_pushobject(vm, value.GetFunc());\n    }\n\n\n    static const char * getVarTypeName() { return \"closure\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        SQObjectType type = sq_gettype(vm, idx);\n        return type == OT_CLOSURE || type == OT_NATIVECLOSURE || type == OT_NULL || type == OT_CLASS;\n    }\n};\n\ntemplate<>\nstruct Var<Function&> : Var<Function> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Function>(vm, idx) {}};\n\ntemplate<>\nstruct Var<const Function&> : Var<Function> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Function>(vm, idx) {}};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratGlobalMethods.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratGlobalMethods: Global Methods\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n// Copyirght 2011 Li-Cheng (Andy) Tai\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_GLOBAL_METHODS_H_)\n#define _SQRAT_GLOBAL_METHODS_H_\n\n#include <squirrel.h>\n#include \"sqratTypes.h\"\n\nnamespace Sqrat {\n\ntemplate<class Func, class Sig = get_callable_function_t<Func>>\nclass SqThunkGen;\n\ntemplate <class Callable, class... Args>\nclass SqThunkGen<Callable, void(Args...)>\n{\npublic:\n  template <SQInteger startIdx>\n  static SQInteger Func(HSQUIRRELVM vm)\n  {\n    if (!vargs::check_var_types<Args...>(vm, startIdx))\n      return SQ_ERROR;\n\n    Callable *method;\n    sq_getuserdata(vm, -1, (SQUserPointer *)&method, NULL);\n    auto vars = vargs::make_vars<Args...>(vm, startIdx);\n    vargs::apply(*method, vars);\n    return 0;\n  }\n};\n\ntemplate <class Callable, class R, class... Args>\nclass SqThunkGen<Callable, R(Args...)>\n{\npublic:\n  template <SQInteger startIdx>\n  static SQInteger Func(HSQUIRRELVM vm)\n  {\n    if (!vargs::check_var_types<Args...>(vm, startIdx))\n      return SQ_ERROR;\n\n    Callable *method;\n    sq_getuserdata(vm, -1, (SQUserPointer *)&method, NULL);\n    auto vars = vargs::make_vars<Args...>(vm, startIdx);\n    PushVar(vm, vargs::apply(*method, vars));\n    return 1;\n  }\n};\n\ntemplate<class Callable>\nSQFUNCTION SqGlobalThunk()\n{\n  return &SqThunkGen<Callable>::template Func<2>;\n}\n\ntemplate<class Callable>\nSQFUNCTION SqMemberGlobalThunk()\n{\n  return &SqThunkGen<Callable>::template Func<1>;\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratMemberMethods.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratMemberMethods: Member Methods\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n// Copyright 2011 Li-Cheng (Andy) Tai\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_MEMBER_METHODS_H_)\n#define _SQRAT_MEMBER_METHODS_H_\n\n#include <squirrel.h>\n#include \"sqratTypes.h\"\n\nnamespace Sqrat {\n\n\ntemplate<class C, class MemberFunc, class MemberFuncSig = member_function_signature_t<MemberFunc>>\nstruct SqMemberThunkGen;\n\ntemplate<class C, class MemberFunc, class R, class... A>\nstruct SqMemberThunkGen<C, MemberFunc, R(A...)>\n{\n  static SQInteger Func(HSQUIRRELVM vm)\n  {\n    SQRAT_ASSERT(sq_gettop(vm) == 2 + sizeof...(A)); // CallNative validates; extra guard\n\n    if (!vargs::check_var_types<A...>(vm, 2))\n      return SQ_ERROR;\n\n    MemberFunc *methodPtr;\n    sq_getuserdata(vm, -1, (SQUserPointer *)&methodPtr, NULL);\n\n    HSQOBJECT selfObj;\n    sq_getstackobj(vm, 1, &selfObj);\n    C *ptr = ClassType<C>::GetInstanceFromObj(selfObj);\n    if (!ptr)\n      return sq_throwerror(vm, FormatTypeError(vm, 1, ClassType<C>::ClassName().c_str()).c_str());\n    auto vars = vargs::make_vars<A...>(vm, 2);\n    R ret = vargs::apply_member(ptr, *methodPtr, vars);\n    PushVar(vm, ret);\n    return 1;\n  }\n};\n\ntemplate<class C, class MemberFunc, class... A>\nstruct SqMemberThunkGen<C, MemberFunc, void(A...)>\n{\n  static SQInteger Func(HSQUIRRELVM vm)\n  {\n    SQRAT_ASSERT(sq_gettop(vm) == 2 + sizeof...(A)); // CallNative validates; extra guard\n\n    if (!vargs::check_var_types<A...>(vm, 2))\n      return SQ_ERROR;\n\n    MemberFunc *methodPtr;\n    sq_getuserdata(vm, -1, (SQUserPointer *)&methodPtr, NULL);\n\n    HSQOBJECT selfObj;\n    sq_getstackobj(vm, 1, &selfObj);\n    C *ptr = ClassType<C>::GetInstanceFromObj(selfObj);\n    if (!ptr)\n      return sq_throwerror(vm, FormatTypeError(vm, 1, ClassType<C>::ClassName().c_str()).c_str());\n    auto vars = vargs::make_vars<A...>(vm, 2);\n    vargs::apply_member(ptr, *methodPtr, vars);\n    return 0;\n  }\n};\n\n//\n// Member Function Resolvers\n//\n\ntemplate<class C, class MemberFunc>\nSQFUNCTION SqMemberFunc()\n{\n  return &SqMemberThunkGen<C, MemberFunc>::Func;\n}\n\n\n//\n// Variable Get\n//\n\ntemplate <class C, class V>\ninline SQInteger sqDefaultGet(HSQUIRRELVM vm) {\n    HSQOBJECT selfObj;\n    sq_getstackobj(vm, 1, &selfObj);\n    C* ptr = ClassType<C>::GetInstanceFromObj(selfObj);\n    if (!ptr)\n      return sq_throwerror(vm, FormatTypeError(vm, 1, ClassType<C>::ClassName().c_str()).c_str());\n\n    typedef V C::*M;\n    M* memberPtr = NULL;\n    sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, NULL); // Get Member...\n    M member = *memberPtr;\n\n    PushVarR(vm, ptr->*member);\n\n    return 1;\n}\n\ntemplate <class C, class V>\ninline SQInteger sqStaticGet(HSQUIRRELVM vm) {\n    typedef V *M;\n    M* memberPtr = NULL;\n    sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, NULL); // Get Member...\n    M member = *memberPtr;\n\n    PushVarR(vm, *member);\n\n    return 1;\n}\n\ninline SQInteger sqVarGet(HSQUIRRELVM vm) {\n    // Find the get method in the get table\n    sq_push(vm, 2);\n    if (SQ_FAILED(sq_rawget(vm, -2))) {\n        sq_pushnull(vm);\n        return sq_throwobject(vm);\n    }\n\n    // push 'this'\n    sq_push(vm, 1);\n\n    // Call the getter\n    SQRESULT result = sq_call(vm, 1, true, SQTrue);\n    return SQ_SUCCEEDED(result) ? 1 : SQ_ERROR;\n}\n\n\n//\n// Variable Set\n//\n\ntemplate <class C, class V>\ninline SQInteger sqDefaultSet(HSQUIRRELVM vm) {\n    HSQOBJECT selfObj;\n    sq_getstackobj(vm, 1, &selfObj);\n    C* ptr = ClassType<C>::GetInstanceFromObj(selfObj);\n    if (!ptr)\n      return sq_throwerror(vm, FormatTypeError(vm, 1, ClassType<C>::ClassName().c_str()).c_str());\n\n    typedef V C::*M;\n    M* memberPtr = NULL;\n    sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, NULL); // Get Member...\n    M member = *memberPtr;\n\n    if constexpr (SQRAT_STD::is_pointer_v<V> || SQRAT_STD::is_reference_v<V>) {\n        ptr->*member = Var<V>(vm, 2).value;\n    } else {\n        ptr->*member = Var<const V&>(vm, 2).value;\n    }\n\n    return 0;\n}\n\ntemplate <class C, class V>\ninline SQInteger sqStaticSet(HSQUIRRELVM vm) {\n    typedef V *M;\n    M* memberPtr = NULL;\n    sq_getuserdata(vm, -1, (SQUserPointer*)&memberPtr, NULL); // Get Member...\n    M member = *memberPtr;\n\n    if constexpr (SQRAT_STD::is_pointer_v<V> || SQRAT_STD::is_reference_v<V>) {\n        *member = Var<V>(vm, 2).value;\n    } else {\n        *member = Var<const V&>(vm, 2).value;\n    }\n\n    return 0;\n}\n\ninline SQInteger sqVarSet(HSQUIRRELVM vm) {\n    // Find the set method in the set table\n    sq_push(vm, 2);\n    if (SQ_FAILED(sq_rawget(vm, -2))) {\n        sq_pushnull(vm);\n        return sq_throwobject(vm);\n    }\n\n    // push 'this'\n    sq_push(vm, 1);\n    sq_push(vm, 3);\n\n    // Call the setter\n    SQRESULT result = sq_call(vm, 2, false, SQTrue);\n    return SQ_SUCCEEDED(result) ? 0 : SQ_ERROR;\n}\n\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratObject.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratObject: Referenced Quirrel Object Wrapper\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_OBJECT_H_)\n#define _SQRAT_OBJECT_H_\n\n#include <squirrel.h>\n#include <string.h>\n\n#include \"sqratAllocator.h\"\n#include \"sqratTypes.h\"\n#include \"sqratUtil.h\"\n\nnamespace Sqrat {\n\nclass Table;\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// The base class for classes that represent Squirrel objects\n///\n/// \\remarks\n/// All Object and derived classes MUST be destroyed before calling sq_close or your application will crash when exiting.\n///\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\nclass Object {\nprotected:\n\n    HSQUIRRELVM vm;\n    HSQOBJECT obj;\n\npublic:\n\n    Object(HSQUIRRELVM v) : vm(v){\n        sq_resetobject(&obj);\n    }\n\n    Object() : vm(0) {\n        sq_resetobject(&obj);\n    }\n\n    Object(const Object& so) : vm(so.vm), obj(so.obj) {\n      sq_addref(vm, &obj);\n    }\n\n    Object(Object && so) : vm(so.vm), obj(so.obj) {\n        sq_resetobject(&so.obj);\n    }\n\n    Object(const Object &&)=delete;\n\n    Object(HSQOBJECT o, HSQUIRRELVM v) : vm(v), obj(o) {\n      sq_addref(vm, &obj);\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Constructs an Object from a known/bound type\n    ///\n    /// \\param t        If t is pointer to a C++ class instance then it has to be bound already, otherwise it's ref to value of known type\n    /// \\param v        VM that the object will exist in\n    ///\n    /// \\tparam T       Type\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <class T, SQRAT_STD::enable_if_t<!SQRAT_STD::is_arithmetic_v<T>, bool> = false>\n    Object(const T &t, HSQUIRRELVM v) : vm(v) {\n        Var<T>::push(vm, t);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &obj)));\n        sq_addref(vm, &obj);\n        sq_poptop(vm);\n    }\n\n    Object(const char *str, HSQUIRRELVM v, SQInteger str_len = -1) : vm(v) {\n        if (str) {\n            sq_pushstring(vm, str, str_len);\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &obj)));\n            sq_addref(vm, &obj);\n            sq_poptop(vm);\n        }\n        else\n            sq_resetobject(&obj);\n    }\n\n    Object(char *str, HSQUIRRELVM v, SQInteger str_len = -1) : vm(v) {\n        if (str) {\n            sq_pushstring(vm, str, str_len);\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &obj)));\n            sq_addref(vm, &obj);\n            sq_poptop(vm);\n        }\n        else\n            sq_resetobject(&obj);\n    }\n\n    template <class T, SQRAT_STD::enable_if_t<SQRAT_STD::is_arithmetic_v<T>, bool> = false>\n    Object(T t, HSQUIRRELVM v) : vm(v) {\n        sq_resetobject(&obj);\n        if constexpr (SQRAT_STD::is_same_v<T, bool>) {\n            obj._type = OT_BOOL;\n            obj._unVal.nInteger = t ? 1 : 0;\n        } else if constexpr (SQRAT_STD::is_floating_point_v<T>) {\n            obj._type = OT_FLOAT;\n            obj._unVal.fFloat = (SQFloat)t;\n        } else {\n            obj._type = OT_INTEGER;\n            obj._unVal.nInteger = (SQInteger)t;\n        }\n    }\n\n    ~Object() {\n        Release();\n    }\n\n    Object& operator=(const Object& so) {\n        if (&so != this)\n        {\n          Release();\n          vm = so.vm;\n          obj = so.obj;\n          sq_addref(vm, &obj);\n        }\n        return *this;\n    }\n\n    Object& operator=(Object && so) {\n        if (&so != this)\n        {\n          Release();\n          vm = so.vm;\n          obj = so.obj;\n          sq_resetobject(&so.obj);\n        }\n        return *this;\n    }\n\n    HSQUIRRELVM& GetVM() {\n        return vm;\n    }\n\n    HSQUIRRELVM GetVM() const {\n        return vm;\n    }\n\n    SQObjectType GetType() const {\n        return GetObject()._type;\n    }\n\n    bool IsNull() const {\n        return sq_isnull(GetObject());\n    }\n\n    const HSQOBJECT &GetObject() const {\n        return obj;\n    }\n\n    HSQOBJECT& GetObject() {\n        return obj;\n    }\n\n    operator HSQOBJECT&() {\n        return GetObject();\n    }\n\n    void Release() {\n        sq_release(vm, &obj);\n        sq_resetobject(&obj);\n    }\n\n    bool IsEqual(const Sqrat::Object &so) const {\n        if (IsNull() && so.IsNull()) // Nulls may have uninitialized vm\n            return true;\n        if (GetVM() != so.GetVM())\n            return false;\n\n        return sq_obj_is_equal(vm, &obj, &so.obj);\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Attempts to get the value of a slot from the object\n    /// \\return An Object representing the value of the slot (can be a null object if nothing was found)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <bool raw>\n    Object GetSlotImpl(const char* slot, int slen) const {\n        HSQOBJECT slotObj;\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, slot, slen);\n\n        SQRESULT res = raw ? sq_rawget(vm, -2) : sq_get(vm, -2);\n        if(SQ_FAILED(res)) {\n            sq_pop(vm, 1);\n            return Object(vm); // Return a NULL object\n        } else {\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &slotObj)));\n            Object ret(slotObj, vm); // must addref before the pop!\n            sq_pop(vm, 2);\n            return ret;\n        }\n    }\n\n    Object GetSlot(const char* slot) const {\n        return GetSlotImpl<false>(slot, strlen(slot));\n    }\n\n    Object RawGetSlot(const char* slot) const {\n        return GetSlotImpl<true>(slot, strlen(slot));\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Attempts to get the value of an index from the object\n    /// \\return An Object representing the value of the slot (can be a null object if nothing was found)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <bool raw>\n    Object GetSlotImpl(SQInteger index) const {\n        HSQOBJECT slotObj;\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n\n        SQRESULT res = raw ? sq_rawget(vm, -2) : sq_get(vm, -2);\n        if(SQ_FAILED(res)) {\n            sq_pop(vm, 1);\n            return Object(vm); // Return a NULL object\n        } else {\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &slotObj)));\n            Object ret(slotObj, vm); // must addref before the pop!\n            sq_pop(vm, 2);\n            return ret;\n        }\n    }\n\n    Object GetSlot(SQInteger index) const {\n        return GetSlotImpl<false>(index);\n    }\n\n    Object RawGetSlot(SQInteger index) const {\n        return GetSlotImpl<true>(index);\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Attempts to get the value of an key from the object\n    /// \\param slot Key (of any type) of the slot\n    /// \\return An Object representing the value of the slot (can be a null object if nothing was found)\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <bool raw>\n    Object GetSlotImpl(const Object& slot) const {\n        SQRAT_ASSERT(slot.IsNull() || slot.GetVM() == vm);\n        HSQOBJECT res;\n        if (SQ_FAILED(sq_obj_get(vm, &obj, &slot.obj, &res, raw)))\n            return Object(vm);\n        Object ret(res, vm);\n        sq_poptop(vm);\n        return ret;\n    }\n\n    Object GetSlot(const Object& slot) const {\n        return GetSlotImpl<false>(slot);\n    }\n\n    Object RawGetSlot(const Object& slot) const {\n        return GetSlotImpl<true>(slot);\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Casts the object to a certain C++ type\n    /// \\tparam T Type to cast to\n    /// \\return A copy of the value of the Object with the given type\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    template <class T>\n    T Cast() const {\n        static_assert(VarControlsValueLifeTime<T>::value == 0,\n                      \"direct cast to T failed due to value is bound to Var<T>. use GetVar() instead\");\n        return GetVar<T>().value;\n    }\n\n    template<class T>\n    Var<T>  GetVar() const\n    {\n        sq_pushobject(vm, GetObject());\n        Var<T> ret(vm, -1);\n        sq_pop(vm, 1);\n        return ret;\n    }\n\n    /// Gets object slot value as a certain C++ type\n    template<class T, bool raw>\n    T GetSlotValueImpl(const char* slot, int slen, T def_val) const {\n        static_assert(VarControlsValueLifeTime<T>::value == 0,\n                      \"direct cast to T failed due to value is bound to Var<T>\");\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, slot, slen);\n\n        SQRESULT res = raw ? sq_rawget(vm, -2) : sq_get(vm, -2);\n        if (SQ_FAILED(res)) {\n            sq_pop(vm, 1);\n            return def_val;\n        } else if (!Var<T>::check_type(vm, -1)) {\n            sq_pop(vm, 2);\n            return def_val;\n        } else {\n            T ret = Var<T>(vm, -1).value;\n            sq_pop(vm, 2);\n            return ret;\n        }\n    }\n\n    template<class T>\n    T GetSlotValue(const char* slot, T def_val) const {\n        return GetSlotValueImpl<T, false>(slot, strlen(slot), def_val);\n    }\n\n    template<class T>\n    T RawGetSlotValue(const char* slot, T def_val) const {\n        return GetSlotValueImpl<T, true>(slot, strlen(slot), def_val);\n    }\n\n    template<class T, bool raw>\n    T GetSlotValueImpl(SQInteger slot, T def_val) const {\n        static_assert(VarControlsValueLifeTime<T>::value == 0,\n                      \"direct cast to T failed due to value is bound to Var<T>\");\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, slot);\n\n        SQRESULT res = raw ? sq_rawget(vm, -2) : sq_get(vm, -2);\n        if (SQ_FAILED(res)) {\n            sq_pop(vm, 1);\n            return def_val;\n        } else if (!Var<T>::check_type(vm, -1)) {\n            sq_pop(vm, 2);\n            return def_val;\n        } else {\n            T ret = Var<T>(vm, -1).value;\n            sq_pop(vm, 2);\n            return ret;\n        }\n    }\n\n    template<class T>\n    T GetSlotValue(SQInteger slot, T def_val) const {\n        return GetSlotValueImpl<T, false>(slot, def_val);\n    }\n\n    template<class T>\n    T RawGetSlotValue(SQInteger slot, T def_val) const {\n        return GetSlotValueImpl<T, true>(slot, def_val);\n    }\n\n    /// Gets object slot value as a certain C++ type\n    template<class T, bool raw>\n    T GetSlotValueImpl(const Object &key, T def_val) const {\n        SQRAT_ASSERT(key.IsNull() || key.GetVM() == vm);\n        static_assert(VarControlsValueLifeTime<T>::value == 0,\n                      \"direct cast to T failed due to value is bound to Var<T>\");\n        HSQOBJECT res;\n        if (SQ_FAILED(sq_obj_get(vm, &obj, &key.obj, &res, raw)))\n          return def_val;\n\n        // sq_obj_get already pushed result to VM stack\n        if constexpr (has_direct_var_v<T>) {\n            T ret = Var<T>::check_type(res) ? Var<T>(res).value : def_val;\n            sq_pop(vm, 1);\n            return ret;\n        } else {\n            if (!Var<T>::check_type(vm, -1)) {\n                sq_pop(vm, 1);\n                return def_val;\n            }\n            T ret = Var<T>(vm, -1).value;\n            sq_pop(vm, 1);\n            return ret;\n        }\n    }\n\n    template<class T>\n    T GetSlotValue(const Object &key, T def_val) const {\n        return GetSlotValueImpl<T, false>(key, def_val);\n    }\n\n    template<class T>\n    T RawGetSlotValue(const Object &key, T def_val) const {\n        return GetSlotValueImpl<T, true>(key, def_val);\n    }\n\n    template <class T>\n    inline Object operator[](T slot) {\n        return GetSlot(slot);\n    }\n\n    template <class T>\n    const Object operator[](T slot) const {\n        return GetSlot(slot);\n    }\n\n    SQInteger GetSize() const {\n        return sq_obj_getsize(&obj);\n    }\n\n    struct iterator;\n    bool Next(iterator& iter) const;\n\n    void FreezeSelf() {\n        obj._flags |= SQOBJ_FLAG_IMMUTABLE;\n    }\n\n    void UnfreezeSelf() {\n        obj._flags &= ~SQOBJ_FLAG_IMMUTABLE;\n    }\n\n    const SQRAT_STD::string_view GetString(const SQRAT_STD::string_view def_val = {}) const {\n        const char *str = sq_objtostring(&obj);\n        if (!str)\n            return def_val;\n        return SQRAT_STD::string_view(str, sq_obj_getsize(&obj));\n    }\n\n\nprotected:\n    template<class Func>\n    void BindFunc(const char* name, Func func, SQFUNCTION func_thunk, SQInteger nparamscheck, bool staticVar = false, const char *docstring=nullptr)\n    {\n      sq_pushobject(vm, GetObject());\n      sq_pushstring(vm, name, -1);\n\n      SQUserPointer funcPtr = sq_newuserdata(vm, sizeof(func));\n      new (funcPtr) Func(func);\n      sq_setreleasehook(vm, -1, ImplaceFreeReleaseHook<Func>);\n\n      sq_newclosure(vm, func_thunk, 1);\n      if (nparamscheck > 0)\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, nparamscheck, nullptr)));\n      SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosurename(vm, -1, name)));\n      if (docstring)\n          SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n\n      SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n      sq_pop(vm,1); // pop table\n    }\n\n    template<class Func>\n    void BindFunc(SQInteger index, Func func, SQFUNCTION func_thunk, SQInteger nparamscheck, bool staticVar = false, const char *docstring=nullptr)\n    {\n      sq_pushobject(vm, GetObject());\n      sq_pushinteger(vm, index);\n\n      SQUserPointer funcPtr = sq_newuserdata(vm, sizeof(func));\n      new (funcPtr) Func(func);\n      sq_setreleasehook(vm, -1, ImplaceFreeReleaseHook<Func>);\n\n      sq_newclosure(vm, func_thunk, 1);\n      if (nparamscheck > 0)\n         SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, nparamscheck, nullptr)));\n      if (docstring)\n          SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n\n      SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n      sq_pop(vm,1); // pop table\n    }\n\n    /// Set the value of a variable on the object. Changes to values set this way are not reciprocated\n    template<class V>\n#ifdef _MSC_VER\n    __declspec(noinline) // To force `SetValue` to be inlined for `strlen(name)`\n#elif defined(__GNUC__)\n    __attribute__((noinline))\n#endif\n    inline void BindValue(const char* name, int nlen, const V& val, bool staticVar = false) {\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name, nlen);\n        PushVar(vm, val);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n        sq_pop(vm,1); // pop table\n    }\n\n    template<class V>\n    inline void BindValue(const  SQRAT_STD::string_view name, const V& val, bool staticVar = false) {\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name.data(), name.size());\n        PushVar(vm, val);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n        sq_pop(vm,1); // pop table\n    }\n\n    template<class V>\n    inline void BindValue(const SQInteger index, const V& val, bool staticVar = false) {\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n        PushVar(vm, val);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n        sq_pop(vm,1); // pop table\n    }\n\n    template<class V>\n    inline void BindValue(const Object &key, const V& val, bool staticVar = false) {\n        PushVar(vm, val);\n        HSQOBJECT valObj;\n        sq_getstackobj(vm, -1, &valObj);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_obj_newslot(vm, &obj, &key.obj, &valObj, staticVar)));\n        sq_poptop(vm);\n    }\n\n    // Set the value of an instance on the object. Changes to values set this way are reciprocated back to the source instance\n    template<class V>\n    inline void BindInstance(const char* name, V* val, bool staticVar = false) {\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name, -1);\n        PushVar(vm, val);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n        sq_pop(vm,1); // pop table\n    }\n\n    template<class V>\n    inline void BindInstance(const SQInteger index, V* val, bool staticVar = false) {\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n        PushVar(vm, val);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n        sq_pop(vm,1); // pop table\n    }\n\n    template<class V>\n    inline void BindInstance(const Object &key, V* val, bool staticVar = false) {\n        PushVar(vm, val);\n        HSQOBJECT valObj;\n        sq_getstackobj(vm, -1, &valObj);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_obj_newslot(vm, &obj, &key.obj, &valObj, staticVar)));\n        sq_poptop(vm);\n    }\n};\n\n// Optimized no-stack-push-and-pop versions\ntemplate<> inline int32_t Object::Cast() const {\n    return sq_objtointeger(&obj);\n}\n\ntemplate<> inline int64_t Object::Cast() const {\n    return sq_objtointeger(&obj);\n}\n\ntemplate<> inline float Object::Cast() const {\n    return sq_objtofloat(&obj);\n}\n\ntemplate<> inline double Object::Cast() const {\n    return sq_objtofloat(&obj);\n}\n\ntemplate<> inline bool Object::Cast() const {\n    return sq_obj_is_true(&obj) != SQFalse;\n}\n\n\ntemplate<>\n#ifdef _MSC_VER\n  __declspec(noinline) // To force `SetValue` to be inlined for `strlen(name)`\n#elif defined(__GNUC__)\n  __attribute__((noinline))\n#endif\ninline void Object::BindValue<int>(const char* name, int nlen, const int & val, bool staticVar /* = false */) {\n    sq_pushobject(vm, GetObject());\n    sq_pushstring(vm, name, nlen);\n    PushVar<int>(vm, val);\n    SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, staticVar)));\n    sq_pop(vm,1); // pop table\n}\n\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Used to get and push Object instances to and from the stack as references (Object is always a reference)\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<>\nstruct Var<Object> {\n\n    Object value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as an Object\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        HSQOBJECT sqValue;\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, idx, &sqValue)));\n        value = Object(sqValue, vm);\n    }\n\n    /// Called by Sqrat::PushVar to put an Object on the stack\n    static void push(HSQUIRRELVM vm, const Object& value) {\n        sq_pushobject(vm, value.GetObject());\n    }\n\n    static const char * getVarTypeName() { return \"object\"; }\n    static bool check_type(HSQUIRRELVM /*vm*/, SQInteger /*idx*/) {\n        return true;\n    }\n};\n\ntemplate<>\nstruct Var<Object&> : Var<Object> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Object>(vm, idx) {}};\n\ntemplate<>\nstruct Var<const Object&> : Var<Object> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Object>(vm, idx) {}};\n\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Iterator for going over the slots in the object using Object::Next\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\nstruct Object::iterator {\n    friend class Object;\n\n    const char* getName() {\n        HSQOBJECT hKey = key.GetObject();\n        return sq_objtostring(&hKey);\n    }\n\n    HSQOBJECT getKey() { return key.GetObject(); }\n    HSQOBJECT getValue() { return value.GetObject(); }\n\nprivate:\n    Object    index, key, value;\n};\n\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Used to go through all the slots in an Object (same limitations as sq_next)\n/// \\param iter An iterator being used for going through the slots\n/// \\return Whether there is a next slot\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ninline bool Object::Next(iterator& iter) const {\n    sq_pushobject(vm, obj);\n    sq_pushobject(vm, iter.index.GetObject());\n\n    if (SQ_SUCCEEDED(sq_next(vm,-2))) {\n        iter.index = Var<Object>(vm, -3).value;\n        iter.key   = Var<Object>(vm, -2).value;\n        iter.value = Var<Object>(vm, -1).value;\n\n        sq_pop(vm, 4);\n        return true;\n    }\n    else {\n        sq_pop(vm, 2);\n        return false;\n    }\n}\n\n} // namespace Sqrat\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratScript.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratScript: Script Compilation and Execution\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_SCRIPT_H_)\n#define _SQRAT_SCRIPT_H_\n\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <string.h>\n\n#include \"sqratObject.h\"\n\n\nnamespace Sqrat {\n\n/// Helper class for managing Squirrel scripts\nclass Script : public Object {\npublic:\n\n    Script(HSQUIRRELVM v) : Object(v) {\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Sets up the Script using a string containing a Squirrel script\n    ///\n    /// \\param script String containing a file path to a Squirrel script\n    /// \\param errMsg String that is filled with any errors that may occur\n    /// \\param name   Optional string containing the script's name (for errors)\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    bool CompileString(const string_view &script, string &errMsg,\n                       const string_view &name = string_view(),\n                       const HSQOBJECT *bindings=nullptr)\n    {\n        if(!sq_isnull(obj)) {\n            sq_release(vm, &obj);\n            sq_resetobject(&obj);\n        }\n\n        if(SQ_FAILED(sq_compile(vm, script.data(), static_cast<SQInteger>(script.size() /** sizeof(char)*/), name.data(), true, bindings))) {\n            errMsg = LastErrorString(vm);\n            return false;\n        }\n\n        sq_getstackobj(vm,-1,&obj);\n        sq_addref(vm, &obj);\n        sq_pop(vm, 1);\n        return true;\n    }\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Sets up the Script using a file containing a Squirrel script\n    ///\n    /// \\param path   File path containing a Squirrel script\n    /// \\param errMsg String that is filled with any errors that may occur\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    bool CompileFile(const string& path, string& errMsg) {\n        if(!sq_isnull(obj)) {\n            sq_release(vm, &obj);\n            sq_resetobject(&obj);\n        }\n\n        if(SQ_FAILED(sqstd_loadfile(vm, path.c_str(), true))) {\n            errMsg = LastErrorString(vm);\n            return false;\n        }\n\n        sq_getstackobj(vm,-1,&obj);\n        sq_addref(vm, &obj);\n        sq_pop(vm, 1);\n        return true;\n    }\n\n\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    /// Runs the script\n    ///\n    /// \\param errMsg String that is filled with any errors that may occur\n    ///\n    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    bool Run(string& errMsg, Object * context = NULL) {\n        if(!sq_isnull(obj)) {\n            SQRESULT result;\n            SQInteger top = sq_gettop(vm);\n            sq_pushobject(vm, obj);\n\n            if (!context)\n              sq_pushroottable(vm);\n            else\n              sq_pushobject(vm, context->GetObject());\n\n            result = sq_call(vm, 1, false, true);\n            sq_settop(vm, top);\n            if(SQ_FAILED(result)) {\n                errMsg = LastErrorString(vm);\n                return false;\n            }\n            return true;\n        }\n        return false;\n    }\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratTable.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratTable: Table Binding\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_TABLE_H_)\n#define _SQRAT_TABLE_H_\n\n#include <squirrel.h>\n#include <string.h>\n\n#include \"sqratObject.h\"\n#include \"sqratFunction.h\"\n#include \"sqratGlobalMethods.h\"\n\nnamespace Sqrat {\n\ntemplate<class C, class A >\nclass Class;\n\nenum class FunctionPurity {\n    Pure,\n    SideEffects,\n};\n\nclass TableBase : public Object {\npublic:\n    TableBase() {\n    }\n\n    TableBase(HSQUIRRELVM v) : Object(v) {\n    }\n\n    TableBase(const Object& obj) : Object(obj) {\n    }\n\n    TableBase(Object && obj) : Object(SQRAT_STD::move(obj)) {\n    }\n\n    TableBase(HSQOBJECT o, HSQUIRRELVM v) : Object(o, v) {\n    }\n\n    /// Binds a Table or Class to the Table (can be used to facilitate namespaces)\n    void Bind(const char* name, Object& object) { BindImpl(name, object); }\n    template <typename C, typename A>\n    void Bind(const char* name, Class<C, A>& klass)  { BindImpl(name, klass); }\n\n    /// Binds a raw Squirrel closure to the Table\n    TableBase& SquirrelFunc(const char* name, SQFUNCTION func, SQInteger nparamscheck, const char *typemask=nullptr,\n                            const char *docstring=nullptr, SQInteger nfreevars=0, const Object *freevars=nullptr,\n                            FunctionPurity purity=FunctionPurity::SideEffects) {\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name, -1);\n        for (SQInteger i=0; i<nfreevars; ++i)\n            sq_pushobject(vm, freevars[i].GetObject());\n        sq_newclosure(vm, func, nfreevars);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setparamscheck(vm, nparamscheck, typemask)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosurename(vm, -1, name)));\n        if (purity == FunctionPurity::Pure)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_mark_pure_inplace(vm, -1)));\n        if (docstring)\n            SQRAT_VERIFY(SQ_SUCCEEDED(sq_setnativeclosuredocstring(vm, -1, docstring)));\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm,1); // pop table\n        return *this;\n    }\n\n    TableBase& SquirrelFuncDeclString(SQFUNCTION func, const char *function_decl,\n                                      const char *docstring=nullptr, SQInteger nfreevars=0, const Object *freevars=nullptr) {\n        sq_pushobject(vm, GetObject());\n        for (SQInteger i=0; i<nfreevars; ++i)\n            sq_pushobject(vm, freevars[i].GetObject());\n\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_new_closure_slot_from_decl_string(vm, func, nfreevars, function_decl, docstring)));\n        sq_pop(vm,1); // pop table\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetValue(const char* name, const V& val) { //-V1071\n        BindValue<V>(name, strlen(name), val, false);\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetValue(const SQRAT_STD::string_view& name, const V& val) { //-V1071\n        BindValue<V>(name, val, false);\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetValue(const SQInteger index, const V& val) {\n        BindValue<V>(index, val, false);\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetValue(const Object &key, const V& val) {\n        BindValue<V>(key, val, false);\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetInstance(const char* name, V* val) {\n        BindInstance<V>(name, val, false);\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetInstance(const SQInteger index, V* val) {\n        BindInstance<V>(index, val, false);\n        return *this;\n    }\n\n    template<class V>\n    TableBase& SetInstance(const Object &key, V* val) {\n        BindInstance<V>(key, val, false);\n        return *this;\n    }\n\n    /// Sets a key in the Table to a specific function\n    template<class F>\n    TableBase& Func(const char* name, F method, const char *docstring=nullptr) { //-V1071\n        BindFunc<F>(name, method, SqGlobalThunk<F>(), 1+SqGetArgCount<F>(), false, docstring);\n        return *this;\n    }\n\n    template <bool raw>\n    bool HasKeyImpl(const char* name) const {\n        sq_pushobject(vm, obj);\n        sq_pushstring(vm, name, -1);\n        if (SQ_FAILED(raw ? sq_rawget(vm, -2) : sq_get(vm, -2))) {\n            sq_pop(vm, 1);\n            return false;\n        }\n        sq_pop(vm, 2);\n        return true;\n    }\n\n    bool HasKey(const char* name) const {\n        return HasKeyImpl<false>(name);\n    }\n\n    bool RawHasKey(const char* name) const {\n        return HasKeyImpl<true>(name);\n    }\n\n    bool HasKey(const Object &key) const {\n        SQRAT_ASSERT(key.IsNull() || key.GetVM() == vm);\n        const HSQOBJECT &hSelf = GetObject(), &hKey = key.GetObject();\n        HSQOBJECT out;\n        bool res = SQ_SUCCEEDED(sq_obj_get(vm, &hSelf, &hKey, &out, /*raw*/ false));\n        if (res)\n            sq_poptop(vm);\n        return res;\n    }\n\n\n    bool RawHasKey(const Object &key) const {\n        SQRAT_ASSERT(key.IsNull() || key.GetVM() == vm);\n        const HSQOBJECT &hSelf = GetObject(), &hKey = key.GetObject();\n        HSQOBJECT out;\n        bool res = SQ_SUCCEEDED(sq_obj_get(vm, &hSelf, &hKey, &out, /*raw*/ true));\n        if (res)\n            sq_poptop(vm);\n        return res;\n    }\n\n\n    template <bool raw>\n    Function GetFunctionImpl(const char* name) const {\n        HSQOBJECT funcObj;\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name, -1);\n        if(SQ_FAILED(raw ? sq_rawget(vm, -2) : sq_get(vm, -2))) {\n            sq_pop(vm, 1);\n            return Function();\n        }\n        SQObjectType value_type = sq_gettype(vm, -1);\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {\n            sq_pop(vm, 2);\n            return Function();\n        }\n\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &funcObj)));\n        Function ret(vm, GetObject(), funcObj); // must addref before the pop!\n        sq_pop(vm, 2);\n        return ret;\n    }\n\n    Function GetFunction(const char* name) const {\n        return GetFunctionImpl<false>(name);\n    }\n\n    Function RawGetFunction(const char* name) const {\n        return GetFunctionImpl<true>(name);\n    }\n\n    template <bool raw>\n    Function GetFunctionImpl(const SQInteger index) const {\n        HSQOBJECT funcObj;\n        sq_pushobject(vm, GetObject());\n        sq_pushinteger(vm, index);\n        if(SQ_FAILED(raw ? sq_rawget(vm, -2) : sq_get(vm, -2))) {\n            sq_pop(vm, 1);\n            return Function();\n        }\n        SQObjectType value_type = sq_gettype(vm, -1);\n        if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {\n            sq_pop(vm, 2);\n            return Function();\n        }\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm, -1, &funcObj)));\n        Function ret(vm, GetObject(), funcObj); // must addref before the pop!\n        sq_pop(vm, 2);\n        return ret;\n    }\n\n    template <bool raw>\n    Function GetFunctionImpl(const Object& key) const {\n        SQRAT_ASSERT(key.IsNull() || key.GetVM() == vm);\n        const HSQOBJECT &hSelf = GetObject(), &hKey = key.GetObject();\n        HSQOBJECT funcObj;\n        if (SQ_FAILED(sq_obj_get(vm, &hSelf, &hKey, &funcObj, raw)))\n            return Function();\n        if (funcObj._type != OT_CLOSURE && funcObj._type != OT_NATIVECLOSURE) {\n            sq_poptop(vm);\n            return Function();\n        }\n        Function ret(vm, GetObject(), funcObj);\n        sq_poptop(vm);\n        return ret;\n    }\n\n    Function GetFunction(const Object& key) const {\n        return GetFunctionImpl<false>(key);\n    }\n\n    Function RawGetFunction(const Object& key) const {\n        return GetFunctionImpl<true>(key);\n    }\n\n    template <bool raw>\n    bool DeleteSlotImpl(const char* name) const {\n        sq_pushobject(vm, obj);\n        sq_pushstring(vm, name, -1);\n        if (SQ_FAILED(raw ? sq_rawdeleteslot(vm, -2, false) : sq_deleteslot(vm, -2, false))) {\n            sq_pop(vm, 1);\n            return false;\n        }\n        sq_pop(vm, 1);\n        return true;\n    }\n\n    bool DeleteSlot(const char* name) const {\n        return DeleteSlotImpl<false>(name);\n    }\n\n    bool RawDeleteSlot(const char* name) const {\n        return DeleteSlotImpl<true>(name);\n    }\n\n    template <bool raw>\n    bool DeleteSlotImpl(const Object &key) const {\n        sq_pushobject(vm, obj);\n        sq_pushobject(vm, key.GetObject());\n        if (SQ_FAILED(raw ? sq_rawdeleteslot(vm, -2, false) : sq_deleteslot(vm, -2, false))) {\n            sq_pop(vm, 1);\n            return false;\n        }\n        sq_pop(vm, 1);\n        return true;\n    }\n\n    bool DeleteSlot(const Object &key) const {\n        return DeleteSlotImpl<false>(key);\n    }\n\n    bool RawDeleteSlot(const Object &key) const {\n        return DeleteSlotImpl<true>(key);\n    }\n\n    SQInteger Length() const {\n        return sq_obj_getsize(&obj);\n    }\n\n    bool Clear() {\n        sq_pushobject(vm, GetObject());\n        bool ok = SQ_SUCCEEDED(sq_clear(vm, -1));\n        sq_pop(vm, 1);\n        return ok;\n    }\n\nprotected:\n    template <class V>\n    void BindImpl(const char* name, V& v) {\n        sq_pushobject(vm, GetObject());\n        sq_pushstring(vm, name, -1);\n        sq_pushobject(vm, v.GetObject());\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_newslot(vm, -3, false)));\n        sq_pop(vm,1); // pop table\n    }\n};\n\nclass Table : public TableBase {\npublic:\n    Table(HSQUIRRELVM v) : TableBase(v) {\n        SQRAT_ASSERT(v);\n        sq_newtable(vm);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,-1,&obj)));\n        sq_addref(vm, &obj);\n        sq_pop(vm,1);\n    }\n\n    Table() {\n    }\n\n    Table(const Object& obj) : TableBase(obj) {\n    }\n\n    Table(Object && obj) : TableBase(SQRAT_STD::move(obj)) {\n    }\n\n    Table(HSQOBJECT o, HSQUIRRELVM v) : TableBase(o, v) {\n    }\n};\n\n\nclass RootTable : public TableBase {\npublic:\n    RootTable(HSQUIRRELVM v) : TableBase(v) {\n        sq_pushroottable(vm);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,-1,&obj)));\n        sq_addref(vm, &obj);\n        sq_pop(v,1); // pop root table\n    }\n};\n\n\nclass RegistryTable : public TableBase {\npublic:\n    RegistryTable(HSQUIRRELVM v) : TableBase(v) {\n        sq_pushregistrytable(v);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,-1,&obj)));\n        sq_addref(vm, &obj);\n        sq_pop(v,1); // pop the registry table\n    }\n};\n\n/// Used to get and push Table instances to and from the stack as references (tables are always references in Squirrel)\ntemplate<>\nstruct Var<Table> {\n\n    Table value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as a Table\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        HSQOBJECT obj;\n        sq_resetobject(&obj);\n        SQRAT_VERIFY(SQ_SUCCEEDED(sq_getstackobj(vm,idx,&obj)));\n        value = Table(obj, vm);\n\n        SQObjectType value_type = sq_gettype(vm, idx);\n        if (value_type != OT_TABLE && value_type != OT_NULL) {\n            SQRAT_ASSERTF(0, FormatTypeError(vm, idx, \"table\").c_str());\n        }\n    }\n\n    /// Called by Sqrat::PushVar to put an Table reference on the stack\n    static void push(HSQUIRRELVM vm, const Table& value) {\n        HSQOBJECT obj;\n        sq_resetobject(&obj);\n        obj = value.GetObject();\n        sq_pushobject(vm,obj);\n    }\n\n    static const char * getVarTypeName() { return \"table\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        return sq_gettype(vm, idx) == OT_TABLE || sq_gettype(vm, idx) == OT_NULL;\n    }\n};\n\n\ntemplate<>\nstruct Var<Table&> : Var<Table> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Table>(vm, idx) {}};\n\ntemplate<>\nstruct Var<const Table&> : Var<Table> {Var(HSQUIRRELVM vm, SQInteger idx) : Var<Table>(vm, idx) {}};\n\n}\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratTypes.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratTypes: Type Translators\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_TYPES_H_)\n#define _SQRAT_TYPES_H_\n\n#include <squirrel.h>\n\n#include \"sqratClassType.h\"\n#include \"sqratUtil.h\"\n\nnamespace Sqrat {\n\n\ntemplate <typename T>\nstruct getAsInt\n{\n    static bool getFromStack(HSQUIRRELVM vm, SQInteger idx, T &value)\n    {\n        static_assert(SQRAT_STD::is_convertible<T, SQInteger>::value, \"type is not convertible to int\");\n\n        SQObjectType value_type = sq_gettype(vm, idx);\n        switch(value_type) {\n          case OT_BOOL: {\n              SQBool sqValueb = SQFalse;\n              SQRESULT res = sq_getbool(vm, idx, &sqValueb);\n              value = static_cast<T>(sqValueb);\n              return SQ_SUCCEEDED(res);\n          }\n          case OT_INTEGER: {\n              SQInteger sqValue = 0;\n              SQRESULT res = sq_getinteger(vm, idx, &sqValue);\n              value = static_cast<T>(sqValue);\n              return SQ_SUCCEEDED(res);\n          }\n          case OT_FLOAT: {\n              SQFloat sqValuef = 0;\n              SQRESULT res = sq_getfloat(vm, idx, &sqValuef);\n              value = static_cast<T>(static_cast<int>(sqValuef));\n              return SQ_SUCCEEDED(res);\n          }\n          default:\n              SQRAT_ASSERTF(0, FormatTypeError(vm, idx, \"integer\").c_str());\n              value = static_cast<T>(0);\n              break;\n        }\n        return false;\n    }\n};\n\n\ntemplate <typename T>\nstruct getAsFloat\n{\n    static bool getFromStack(HSQUIRRELVM vm, SQInteger idx, T& value)\n    {\n        static_assert(SQRAT_STD::is_convertible<T, float>::value, \"type is not convertible to float\");\n\n        SQObjectType value_type = sq_gettype(vm, idx);\n        switch(value_type) {\n          case OT_BOOL: {\n              SQBool sqValueb = SQFalse;\n              SQRESULT res = sq_getbool(vm, idx, &sqValueb);\n              value = static_cast<T>(sqValueb);\n              return SQ_SUCCEEDED(res);\n          }\n          case OT_INTEGER: {\n              SQInteger sqValue = 0;\n              SQRESULT res = sq_getinteger(vm, idx, &sqValue);\n              value = static_cast<T>(sqValue);\n              return SQ_SUCCEEDED(res);\n          }\n          case OT_FLOAT: {\n              SQFloat sqValuef = 0;\n              SQRESULT res = sq_getfloat(vm, idx, &sqValuef);\n              value = static_cast<T>(sqValuef);\n              return SQ_SUCCEEDED(res);\n          }\n          default:\n              SQRAT_ASSERTF(0, FormatTypeError(vm, idx, \"float\").c_str());\n              value = 0;\n              break;\n        }\n        return false;\n    }\n};\n\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Used to get and push class instances to and from the stack as copies\n///\n/// \\remarks\n/// This specialization requires T to have a default constructor.\n///\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<class T, class>\nstruct Var {\n\n    using ClassT = ClassType<SQRAT_STD::remove_const_t<T>>;\n    T value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as the given type\n    Var(HSQUIRRELVM vm, SQInteger idx) { //-V1077\n        T* ptr = ClassT::GetInstance(vm, idx);\n        if (ptr != NULL) {\n            value = *ptr;\n        }\n    }\n\n    /// Called by Sqrat::PushVar to put a class object on the stack\n    static void push(HSQUIRRELVM vm, const T& value) {\n        if (ClassT::hasClassData(vm))\n            ClassT::PushInstanceCopy(vm, value);\n        else\n            SQRAT_ASSERTF(0, \"Class/typename was not bound\");\n    }\n\n    static const char * getVarTypeName() { return ClassT::ClassName().c_str(); }\n\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        return ClassT::IsClassInstance(vm, idx);\n    }\n};\n\n// Forward-declare Var<> specializations for host project types (if any).\n// These turn missing-include bugs into compile errors instead of runtime asserts.\n#ifdef SQRAT_FORWARD_VAR_SPECIALIZATIONS\n  SQRAT_FORWARD_VAR_SPECIALIZATIONS\n#endif\n\n// Var<T> trait to find-out whether value can be used after Var has been\n// destroyed. If Var has user-provided destructor it likely controls value\n// lifetime\ntemplate<typename T>\nstruct VarControlsValueLifeTime\n{\n  enum {value = 0};\n};\n\ntemplate<class Callable> SQFUNCTION SqGlobalThunk();\n\ntemplate<typename Func>\nstruct Var<Func, SQRAT_STD::enable_if_t<is_callable_v<Func>>>\n{\n  static void push(HSQUIRRELVM vm, const Func& value)\n  {\n    SQFUNCTION funcThunk = SqGlobalThunk<Func>();\n    SQUserPointer funcPtr = sq_newuserdata(vm, sizeof(Func));\n    new (funcPtr) Func(value);\n    sq_setreleasehook(vm, -1, ImplaceFreeReleaseHook<Func>);\n    sq_newclosure(vm, funcThunk, 1);\n  }\n};\n\n\n/// Used to get and push class instances to and from the stack as references\ntemplate<class T>\nstruct Var<T&, SQRAT_STD::enable_if_t<!SQRAT_STD::is_arithmetic_v<SQRAT_STD::remove_const_t<T>>\n                                      && !SQRAT_STD::is_enum_v<SQRAT_STD::remove_const_t<T>>>> {\n\n    using ClassT = ClassType<SQRAT_STD::remove_const_t<T>>;\n    T& value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as the given type\n    Var(HSQUIRRELVM vm, SQInteger idx) : value(*getCheckedInstance(vm, idx)) {\n    }\n\nprivate:\n    static T* getCheckedInstance(HSQUIRRELVM vm, SQInteger idx) {\n        T* ptr = ClassT::GetInstance(vm, idx);\n        if (!ptr) {\n            // Return pointer to aligned dummy storage to avoid null dereference.\n            // GetInstance already raised an assert; the caller should check for errors.\n            // Uses raw storage instead of T{} to compile for non-default-constructible types.\n            alignas(SQRAT_STD::remove_const_t<T>) static char dummy[sizeof(SQRAT_STD::remove_const_t<T>)] = {};\n            return reinterpret_cast<T*>(dummy);\n        }\n        return ptr;\n    }\n\npublic:\n\n    /// Called by Sqrat::PushVarR to put a class object on the stack\n    static void push(HSQUIRRELVM vm, T& value) {\n        if (ClassT::hasClassData(vm))\n        {\n          if constexpr (SQRAT_STD::is_const_v<T>)\n            ClassT::PushInstanceCopy(vm, value);\n          else\n            ClassT::PushNativeInstance(vm, const_cast<SQRAT_STD::remove_const_t<T>*>(&value));\n        }\n        else\n            SQRAT_ASSERTF(0, \"Class/typename was not bound\");\n    }\n\n    static const char * getVarTypeName() { return ClassT::ClassName().c_str(); }\n\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        return ClassT::IsClassInstance(vm, idx);\n    }\n};\n\n/// Used to get and push class instances to and from the stack as pointers\ntemplate<class T>\nstruct Var<T*, SQRAT_STD::enable_if_t<!is_callable_v<T*>>> {\n\n    using ClassT = ClassType<SQRAT_STD::remove_const_t<T>>;\n    T* value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as the given type\n    Var(HSQUIRRELVM vm, SQInteger idx) : value(ClassT::GetInstance(vm, idx, true)) {\n    }\n\n    /// Direct extraction from HSQOBJECT -- stackless\n    explicit Var(const HSQOBJECT &o) : value(ClassT::GetInstanceFromObj(o)) {}\n\n    /// Called by Sqrat::PushVar to put a class object on the stack\n    static void push(HSQUIRRELVM vm, T* value) {\n        if (ClassT::hasClassData(vm))\n          ClassT::PushNativeInstance(vm, const_cast<SQRAT_STD::remove_const_t<T>*>(value));\n        else\n          SQRAT_ASSERTF(0, \"Class/typename was not bound\");\n    }\n\n    static const char * getVarTypeName() { return ClassT::ClassName().c_str(); }\n\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        return ClassT::IsClassInstance(vm, idx);\n    }\n};\n\n\n/// Used to get (as copies) and push (as references) class instances to and from the stack as a shared_ptr\ntemplate<class T> void PushVarR(HSQUIRRELVM vm, T& value);\ntemplate<class T>\nstruct Var<SQRAT_STD::shared_ptr<T> > {\n\n    SQRAT_STD::shared_ptr<T> value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as the given type\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        if (sq_gettype(vm, idx) != OT_NULL) {\n            Var<T> instance(vm, idx);\n            value.reset(new T(instance.value));\n        }\n    }\n\n    /// Called by Sqrat::PushVar to put a class object on the stack\n    static void push(HSQUIRRELVM vm, const SQRAT_STD::shared_ptr<T>& value) {\n        PushVarR(vm, *value);\n    }\n};\n\n\n// Arithmetic types (integers and floats, excluding bool which has special handling)\ntemplate<typename T>\nstruct Var<T, SQRAT_STD::enable_if_t<SQRAT_STD::is_arithmetic_v<T> && !SQRAT_STD::is_same_v<T, bool>>> {\n    T value;\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        if constexpr (SQRAT_STD::is_integral_v<T>)\n            getAsInt<T>::getFromStack(vm, idx, value);\n        else\n            getAsFloat<T>::getFromStack(vm, idx, value);\n    }\n    explicit Var(const HSQOBJECT &o) {\n        SQRAT_ASSERT(check_type(o));\n        if constexpr (SQRAT_STD::is_integral_v<T>)\n            value = static_cast<T>(sq_objtointeger(&o));\n        else\n            value = static_cast<T>(sq_objtofloat(&o));\n    }\n    static void push(HSQUIRRELVM vm, T value) {\n        if constexpr (SQRAT_STD::is_integral_v<T>)\n            sq_pushinteger(vm, static_cast<SQInteger>(value));\n        else\n            sq_pushfloat(vm, static_cast<SQFloat>(value));\n    }\n    static const char * getVarTypeName() { return SQRAT_STD::is_integral_v<T> ? \"integer\" : \"float\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) { return sq_gettype(vm, idx) & SQOBJECT_NUMERIC; }\n    static bool check_type(const HSQOBJECT &o) { return o._type & SQOBJECT_NUMERIC; }\n};\n\n// Reference/const-reference forwarder for arithmetic types (including bool)\ntemplate<class T>\nstruct Var<T&, SQRAT_STD::enable_if_t<SQRAT_STD::is_arithmetic_v<SQRAT_STD::remove_const_t<T>>>>\n    : Var<SQRAT_STD::remove_const_t<T>> {\n    using Var<SQRAT_STD::remove_const_t<T>>::Var;\n};\n\n\n///////////////////////////////////////\n/// Enums\n///////////////////////////////////////\n\ntemplate<typename T>\nstruct Var<T, SQRAT_STD::enable_if_t<SQRAT_STD::is_enum_v<T>>> {\n    T value;\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        SQInteger intVal = 0;\n        if (SQ_SUCCEEDED(sq_getinteger(vm, idx, &intVal)))\n            value = static_cast<T>(intVal);\n     }\n    explicit Var(const HSQOBJECT &o) {\n        SQRAT_ASSERT(check_type(o));\n        value = static_cast<T>(sq_objtointeger(&o));\n    }\n\n     static void push(HSQUIRRELVM vm, T value) {\n         sq_pushinteger(vm, static_cast<SQInteger>(value));\n     }\n    static const char * getVarTypeName() { return \"enum\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) {\n        return sq_gettype(vm, idx) == OT_INTEGER;\n    }\n    static bool check_type(const HSQOBJECT &o) { return o._type == OT_INTEGER; }\n};\n\n// Reference/const-reference forwarder for enum types\ntemplate<class T>\nstruct Var<T&, SQRAT_STD::enable_if_t<SQRAT_STD::is_enum_v<SQRAT_STD::remove_const_t<T>>>>\n    : Var<SQRAT_STD::remove_const_t<T>> {\n    using Var<SQRAT_STD::remove_const_t<T>>::Var;\n};\n\n\n/// Used to get and push bools to and from the stack\ntemplate<>\nstruct Var<bool> {\n    bool value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as a bool\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        SQBool sqValue;\n        sq_tobool(vm, idx, &sqValue);\n        value = (sqValue != 0);\n    }\n    explicit Var(const HSQOBJECT &o) {\n        SQRAT_ASSERT(check_type(o));\n        value = sq_obj_is_true(&o) != 0;\n    }\n\n    /// Called by Sqrat::PushVar to put a bool on the stack\n    static void push(HSQUIRRELVM vm, const bool& value) {\n        sq_pushbool(vm, static_cast<SQBool>(value));\n    }\n\n    static const char * getVarTypeName() { return \"bool\"; }\n    static bool check_type(HSQUIRRELVM /*vm*/, SQInteger /*idx*/) { return true; }\n    static bool check_type(const HSQOBJECT &) { return true; }\n};\n\n// Trait: true for types with HSQOBJECT-based Var constructors (arithmetic + enum).\n// Used by GetSlotValueImpl to dispatch the stackless extraction path at compile time.\ntemplate<class T>\ninline constexpr bool has_direct_var_v = SQRAT_STD::is_arithmetic_v<T> || SQRAT_STD::is_enum_v<T>;\n\n/// Var<char*> construction is deleted: it exposed non-const write access to VM-internal strings.\n/// Use Var<const char*> or Var<string_view> instead. push() is kept for PushVar<char>(vm, ptr).\ntemplate<>\nstruct Var<char*> {\n    Var() = delete;\n    Var(HSQUIRRELVM, SQInteger) = delete;\n\n    static void push(HSQUIRRELVM vm, const char* value, SQInteger len = -1) {\n        sq_pushstring(vm, value, len);\n    }\n\n    static const char * getVarTypeName() { return \"string\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) { return sq_gettype(vm, idx) == OT_STRING; }\n};\n\n/// Used to get and push strings as char arrays to and from the stack\ntemplate<>\nstruct Var<const char*> {\nprivate:\n    HSQOBJECT obj = {}; /* hold a reference to the object holding value during the Var struct lifetime*/\n    HSQUIRRELVM v = nullptr;\n\npublic:\n    const char* value = \"\"; ///< The actual value of get operations\n    SQInteger valueLen = 0;\n\n    /// Attempts to get the value off the stack at idx as a character array\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        v = vm;\n        if (SQ_SUCCEEDED(sq_tostring(vm, idx))) {\n            sq_getstackobj(vm, -1, &obj);\n            sq_getstringandsize(vm, -1, &value, &valueLen);\n            sq_addref(vm, &obj);\n            sq_pop(vm,1);\n        } else {\n            sq_resetobject(&obj);\n        }\n    }\n\n    Var(Var<const char *> const &rhs)\n      : obj(rhs.obj)\n      , v(rhs.v)\n      , value(rhs.value)\n      , valueLen(rhs.valueLen)\n    {\n      sq_addref(v, &obj);\n    }\n\n    Var<const char *> &operator=(Var<const char *> const &rhs)\n    {\n      if (&rhs == this)\n        return *this;\n      if (v && !sq_isnull(obj))\n        sq_release(v, &obj);\n      obj = rhs.obj;\n      v = rhs.v;\n      value = rhs.value;\n      valueLen = rhs.valueLen;\n      sq_addref(v, &obj);\n      return *this;\n    }\n\n    ~Var()\n    {\n        if(v && !sq_isnull(obj)) {\n            sq_release(v, &obj);\n        }\n    }\n\n    /// Called by Sqrat::PushVar to put a character array on the stack\n    static void push(HSQUIRRELVM vm, const char* value, SQInteger len = -1) {\n        sq_pushstring(vm, value, len);\n    }\n\n    static const char * getVarTypeName() { return \"string\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) { return sq_gettype(vm, idx) == OT_STRING; }\n};\n\ntemplate<>\nstruct VarControlsValueLifeTime<const char*>\n{\n  enum {value = 1};\n};\n\n/// Used to get and push strings to and from the stack\ntemplate<>\nstruct Var<string> {\n    string value; ///< The actual value of get operations\n\n    /// Attempts to get the value off the stack at idx as a string\n    Var(HSQUIRRELVM vm, SQInteger idx) {\n        if (SQ_FAILED(sq_tostring(vm, idx)))\n            return;\n        const char* ret = nullptr;\n        sq_getstring(vm, -1, &ret);\n        value = string(ret, sq_getsize(vm, -1));\n        sq_pop(vm,1);\n    }\n\n    /// Called by Sqrat::PushVar to put a string on the stack\n    static void push(HSQUIRRELVM vm, const string& value) {\n        sq_pushstring(vm, value.c_str(), value.size());\n    }\n\n    static const char * getVarTypeName() { return \"string\"; }\n    static bool check_type(HSQUIRRELVM vm, SQInteger idx) { return sq_gettype(vm, idx) == OT_STRING; }\n};\n\n/// Const string references are handled as copies (strings are always copied)\ntemplate<>\nstruct Var<const string&> : Var<string> {\n    using Var<string>::Var;\n};\n\n\n/// Used to get and push strings as string_view objects\ntemplate <>\nstruct Var<string_view>\n{\nprivate:\n  HSQOBJECT obj = {}; /* hold a reference to the object holding value during the Var struct lifetime*/\n  HSQUIRRELVM v = nullptr;\n\npublic:\n  string_view value;\n\n  Var(HSQUIRRELVM vm, SQInteger idx)\n  {\n    v = vm;\n    if (SQ_SUCCEEDED(sq_tostring(vm, idx))) {\n      sq_getstackobj(vm, -1, &obj);\n      const char *strPtr = nullptr;\n      SQInteger strLen = 0;\n      sq_getstringandsize(vm, -1, &strPtr, &strLen);\n      sq_addref(vm, &obj);\n      sq_pop(vm, 1);\n      value = string_view(strPtr, strLen);\n    } else {\n      sq_resetobject(&obj);\n    }\n  }\n\n  ~Var()\n  {\n    if (v && !sq_isnull(obj))\n      sq_release(v, &obj);\n  }\n\n  Var(Var<string_view> const &rhs)\n    : obj(rhs.obj)\n    , v(rhs.v)\n    , value(rhs.value)\n  {\n    sq_addref(v, &obj);\n  }\n\n  Var<string_view> &operator=(Var<string_view> const &rhs)\n  {\n    if (&rhs == this)\n      return *this;\n    if (v && !sq_isnull(obj))\n      sq_release(v, &obj);\n    obj = rhs.obj;\n    v = rhs.v;\n    value = rhs.value;\n    sq_addref(v, &obj);\n    return *this;\n  }\n\n  static void push(HSQUIRRELVM vm, string_view sv)\n  {\n    sq_pushstring(vm, sv.data(), sv.size());\n  }\n\n  static const char *getVarTypeName()\n  {\n    return \"string\";\n  }\n  static bool check_type(HSQUIRRELVM vm, SQInteger idx)\n  {\n    return sq_gettype(vm, idx) == OT_STRING;\n  }\n};\n\ntemplate <>\nstruct VarControlsValueLifeTime<string_view> // Var holds reference to VM's string which is pointed by string_view\n{\n  enum\n  {\n    value = 1\n  };\n};\n\n\n// Non-referencable type definitions\ntemplate <class T, class = void> struct is_referencable : public SQRAT_STD::true_type {};\ntemplate <class T>\nstruct is_referencable<T, SQRAT_STD::enable_if_t<SQRAT_STD::is_scalar<T>::value>> : public SQRAT_STD::false_type {};\n\n#define SQRAT_MAKE_NONREFERENCABLE( type ) \\\n template<> struct is_referencable<type> : public SQRAT_STD::false_type {};\n\nSQRAT_MAKE_NONREFERENCABLE(string)\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Pushes a value on to a given VM's stack\n///\n/// \\remarks\n/// What this function does is defined by Sqrat::Var template specializations,\n/// and thus you can create custom functionality for it by making new template specializations.\n/// When making a custom type that is not referencable, you must use SQRAT_MAKE_NONREFERENCABLE( type )\n///\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<class T>\ninline void PushVar(HSQUIRRELVM vm, T* value) {\n    Var<T*>::push(vm, value);\n}\n\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Pushes a value on to a given VM's stack\n///\n/// \\remarks\n/// What this function does is defined by Sqrat::Var template specializations,\n/// and thus you can create custom functionality for it by making new template specializations.\n/// When making a custom type that is not referencable, you must use SQRAT_MAKE_NONREFERENCABLE( type )\n///\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ntemplate<class T>\ninline void PushVar(HSQUIRRELVM vm, const T& value) {\n    Var<T>::push(vm, value);\n}\n\n\n/// Pushes a reference on to a given VM's stack (some types cannot be referenced and will be copied instead)\ntemplate<class T>\ninline void PushVarR(HSQUIRRELVM vm, T& value) {\n    if constexpr (!SQRAT_STD::is_pointer_v<T> && is_referencable<SQRAT_STD::remove_cv_t<T>>::value) {\n        Var<T&>::push(vm, value);\n    } else if constexpr (SQRAT_STD::is_scalar_v<T>) {\n        PushVar<T>(vm, value);\n    } else {\n        PushVar<const T&>(vm, value);\n    }\n}\n\nnamespace vargs\n{\n  template <typename... Args, size_t... Indeces>\n  SQRAT_STD::tuple<Var<Args>...> make_vars_i(HSQUIRRELVM vm, int idx, SQRAT_STD::index_sequence<Indeces...>)\n  {\n    ((void)idx);\n    ((void)vm);\n    return SQRAT_STD::make_tuple(Var<Args>(vm, idx + Indeces)...);\n  }\n\n  template <typename... Args>\n  SQRAT_STD::tuple<Var<Args>...> make_vars(HSQUIRRELVM vm, int idx)\n  {\n    return make_vars_i<Args...>(vm, idx, SQRAT_STD::index_sequence_for<Args...>());\n  }\n\n  template <typename T>\n  bool check_var_types(HSQUIRRELVM vm, int idx)\n  {\n    if (!Var<T>::check_type(vm, idx)) {\n      const char *argTypeName = \"unknown\";\n      SQInteger prevTop = sq_gettop(vm);\n      if (SQ_SUCCEEDED(sq_typeof(vm, idx)) && SQ_SUCCEEDED(sq_tostring(vm, -1))) {\n        sq_getstring(vm, -1, &argTypeName);\n      }\n\n      char errMsg[128];\n      snprintf(errMsg, sizeof(errMsg), \"Wrong argument type, expected '%s', got '%s'\",\n                    Var<T>::getVarTypeName(), argTypeName);\n      sq_settop(vm, prevTop);\n      (void)sq_throwerror(vm, errMsg);\n      return false;\n    }\n    return true;\n  }\n\n  template <typename Head, typename... Tail>\n  bool check_var_types(HSQUIRRELVM vm, int idx, SQRAT_STD::enable_if_t<(sizeof...(Tail) > 0), bool> = false)\n  {\n    if (!check_var_types<Head>(vm, idx))\n      return false;\n    return check_var_types<Tail...>(vm, idx+1);\n  }\n\n  template <typename... T>\n  bool check_var_types(HSQUIRRELVM /*vm*/,\n                       int /*idx*/,\n                       SQRAT_STD::enable_if_t<(sizeof...(T) == 0), bool> = false)\n  {\n    return true;\n  }\n}\n\n\n// utility for checking types of SquirrelFunc arguments\ntemplate <typename... Args>\nbool check_signature(HSQUIRRELVM vm, SQInteger start_stack_pos=1) {\n    return vargs::check_var_types<Args...>(vm, start_stack_pos);\n}\n\n\n}  // namespace Sqrat\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat/sqratUtil.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// SqratUtil: Quirrel Utilities\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_UTIL_H_)\n#define _SQRAT_UTIL_H_\n\n#ifdef USE_SQRAT_CONFIG\n\n  #include \"sqratConfig.h\"\n\n#else\n\n  #include <assert.h>\n\n  #define SQRAT_ASSERT assert\n  #define SQRAT_ASSERTF(cond, msg, ...) assert((cond) && (msg))\n  #define SQRAT_VERIFY(cond) do { if (!(cond)) assert(#cond); } while(0)\n#endif\n\n#include <squirrel.h>\n#include <sqstdaux.h>\n\n#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)\n#else\n  #error C++17 support required\n#endif\n\n#if defined(SQRAT_HAS_SKA_HASH_MAP)\n# include <ska_hash_map/flat_hash_map2.hpp>\n#endif\n\n#ifndef SQRAT_STD\n#define SQRAT_STD std\n#endif\n\n#if defined(SQRAT_HAS_EASTL)\n# include <EASTL/string.h>\n# include <EASTL/string_view.h>\n# include <EASTL/unordered_map.h>\n# include <EASTL/unordered_set.h>\n# include <EASTL/vector_map.h>\n# include <EASTL/shared_ptr.h>\n# include <EASTL/optional.h>\nEA_DISABLE_ALL_VC_WARNINGS()\n#else\n# include <string>\n# include <string_view>\n# include <vector>\n# include <unordered_map>\n# include <unordered_set>\n# include <memory>\n# include <tuple>\n# include <type_traits>\n# include <optional>\n#endif\n\n\nnamespace Sqrat {\n\n#if defined(SQRAT_HAS_EASTL)\n  using string = eastl::basic_string<char>;\n  using string_view = eastl::basic_string_view<char>;\n  template <class T> using hash = eastl::hash<T>;\n  template <class T> using shared_ptr = eastl::shared_ptr<T>;\n  template <class T> using weak_ptr = eastl::weak_ptr<T>;\n#else\n  using string = std::basic_string<char>;\n  using string_view = std::basic_string_view<char>;\n  template <class T> using hash = std::hash<T>;\n  template <class T> using shared_ptr = std::shared_ptr<T>;\n  template <class T> using weak_ptr = std::weak_ptr<T>;\n#endif //defined(SQRAT_HAS_EASTL)\n\n#if defined(SQRAT_HAS_EASTL)\n  template <class T> using optional = eastl::optional<T>;\n  using nullopt_t = eastl::nullopt_t;\n  inline constexpr eastl::nullopt_t nullopt{eastl::nullopt};\n#else\n  template <class T> using optional = std::optional<T>;\n  using nullopt_t = std::nullopt_t;\n  inline constexpr std::nullopt_t nullopt{std::nullopt};\n#endif\n\n#if defined(SQRAT_HAS_SKA_HASH_MAP)\n\n  template <class K, class V, typename H = hash<K>>\n  using class_hash_map = ska::flat_hash_map<K, V, H>;\n\n  template <typename T, typename H = hash<T>>\n  using hash_set = ska::flat_hash_set<T, H>;\n\n#elif defined(SQRAT_HAS_EASTL)\n\n  template <class K, class V, typename H = hash<K>>\n  using class_hash_map = eastl::unordered_map<K, V, H>;\n\n  template <typename T, typename H = hash<T>>\n  using hash_set = eastl::unordered_set<T, H>;\n\n#else\n\n  template <class K, class V, typename H = hash<K>>\n  using class_hash_map = std::unordered_map<K, V, H>;\n\n  template <typename T, typename H = hash<T>>\n  using hash_set = std::unordered_set<T, H>;\n\n#endif\n\n\ntemplate <typename T>\nvoid SQRAT_UNUSED(const T&) {}\n\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/// Returns a string that has been formatted to give a nice type error message (for usage with Class::SquirrelFunc)\n///\n/// \\param vm           VM the error occurred with\n/// \\param idx          Index on the stack of the argument that had a type error\n/// \\param expectedType The name of the type that the argument should have been\n///\n/// \\return String containing a nice type error message\n///\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\ninline string FormatTypeError(HSQUIRRELVM vm, SQInteger idx, const char *expectedType) {\n    SQInteger prevTop = sq_gettop(vm);\n    const char* actualType = \"unknown\";\n    if (SQ_SUCCEEDED(sq_typeof(vm, idx))) {\n        sq_tostring(vm, -1);\n        sq_getstring(vm, -1, &actualType);\n    }\n\n    char buf[128];\n    snprintf(buf, sizeof(buf), \"wrong type (%s expected, got %s)\", expectedType, actualType);\n\n    sq_settop(vm, prevTop);\n    return string(buf);\n}\n\n\n/// Returns the last error that occurred with a Squirrel VM (not associated with Sqrat errors)\ninline string LastErrorString(HSQUIRRELVM vm) {\n    const char* sqErr = \"n/a\";\n    sq_getlasterror(vm);\n    if (sq_gettype(vm, -1) == OT_NULL) {\n        sq_pop(vm, 1);\n        return string();\n    }\n    sq_tostring(vm, -1);\n    sq_getstring(vm, -1, &sqErr);\n    string res(sqErr);\n    sq_pop(vm, 2);\n    return res;\n}\n\ntemplate<class Obj>\nSQInteger ImplaceFreeReleaseHook(HSQUIRRELVM, SQUserPointer p, SQInteger)\n{\n  SQRAT_UNUSED(p); // for Obj without destructor\n  static_cast<Obj*>(p)->~Obj();\n  return 1;\n}\n\ntemplate<class T, class = void> struct Var;\n\n// utilities for manipulations with variadic templates arguments\nnamespace vargs {\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable: 4100)\n#endif\n  template <class Func, class Tuple, size_t... Indexes>\n  auto apply_helper(Func pf, SQRAT_STD::index_sequence<Indexes...>, Tuple &args)\n  {\n    return pf(SQRAT_STD::get<Indexes>(args).value...);\n  }\n\n  template <class Func, class Tuple>\n  auto apply(Func pf, Tuple &&args)\n  {\n    constexpr auto argsN = SQRAT_STD::tuple_size<SQRAT_STD::decay_t<Tuple>>::value;\n    return apply_helper(pf, SQRAT_STD::make_index_sequence<argsN>(), args);\n  }\n\n  template <class C, class Member, class Tuple, size_t... Indexes>\n  auto apply_member_helper(C *ptr, Member pf, SQRAT_STD::index_sequence<Indexes...>,\n                           Tuple &args)\n  {\n    return (ptr->*pf)(SQRAT_STD::get<Indexes>(args).value...);\n  }\n\n  template <class C, class Member, class Tuple>\n  auto apply_member(C *ptr, Member pf, Tuple &&args)\n  {\n    constexpr auto argsN = SQRAT_STD::tuple_size<SQRAT_STD::decay_t<Tuple>>::value;\n    return apply_member_helper(ptr, pf, SQRAT_STD::make_index_sequence<argsN>(), args);\n  }\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n}\n\ntemplate<typename ...Tn>\nusing disjunction = SQRAT_STD::disjunction<Tn...>;\ntemplate <typename ...Tn>\nusing void_t = SQRAT_STD::void_t<Tn...>;\n\ntemplate <typename T>\nstruct is_function\n  : disjunction<SQRAT_STD::is_function<T>,\n                SQRAT_STD::is_function<SQRAT_STD::remove_pointer_t<SQRAT_STD::remove_reference_t<T>>>>\n{\n};\n\ntemplate <bool B, typename T>\nusing disable_if = SQRAT_STD::enable_if<!B, T>;\n\ntemplate <typename T>\nstruct member_function_signature\n{\n  using type = void;\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...)>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) const>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) volatile>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) volatile const>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) noexcept>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) const noexcept>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) volatile noexcept>\n{\n  using type = R(A...);\n};\n\ntemplate <typename C, typename R, typename... A>\nstruct member_function_signature<R (C::*)(A...) volatile const noexcept>\n{\n  using type = R(A...);\n};\n\ntemplate<typename T>\nusing member_function_signature_t = typename member_function_signature<T>::type;\n\ntemplate<class T>\nstruct get_class_callop_signature\n{\n  using type = member_function_signature_t<decltype(&SQRAT_STD::remove_reference_t<T>::operator())>;\n};\n\ntemplate<class T>\nusing get_class_callop_signature_t = typename get_class_callop_signature<T>::type;\n\ntemplate<class F>\nstruct get_function_signature\n{\n  using type = void;\n};\n\ntemplate <typename R, typename... A>\nstruct get_function_signature<R(A...)>\n{\n  using type = R(A...);\n};\n\ntemplate <typename R, typename... A>\nstruct get_function_signature<R (&)(A...)>\n{\n  using type = R(A...);\n};\n\ntemplate <typename R, typename... A>\nstruct get_function_signature<R (*)(A...)>\n{\n  using type = R(A...);\n};\n\ntemplate <typename R, typename... A>\nstruct get_function_signature<R (*&)(A...)>\n{\n  using type = R(A...);\n};\n\ntemplate<typename Func>\nusing get_function_signature_t = typename get_function_signature<Func>::type;\n\n\ntemplate<typename T>\nstruct get_callable_function : SQRAT_STD::conditional_t<\n  SQRAT_STD::is_member_function_pointer<T>::value,\n  member_function_signature<T>,\n  SQRAT_STD::conditional_t<\n    is_function<T>::value,\n    get_function_signature<SQRAT_STD::remove_pointer_t<T>>,\n    SQRAT_STD::conditional_t<\n      SQRAT_STD::is_class<T>::value,\n      get_class_callop_signature<T>,\n      void_t<T>\n    >\n  >\n>\n{\n};\n\n\ntemplate<typename T>\nusing get_callable_function_t = typename get_callable_function<T>::type;\n\ntemplate<typename Function>\nstruct result_of;\n\ntemplate<typename R, typename... A>\nstruct result_of<R(A...)>\n{\n  using type = R;\n};\n\ntemplate<typename F>\nusing result_of_t = typename result_of<F>::type;\n\ntemplate<typename Function>\nstruct function_args_num;\n\ntemplate<typename R, typename... A>\nstruct function_args_num<R(A...)>\n{\n  static size_t const value = sizeof...(A);\n};\n\ntemplate<typename F>\nconstexpr size_t function_args_num_v = function_args_num<F>::value;\n\ntemplate<typename T>\nstruct has_call_operator\n{\n  using yes = char[2];\n  using no  = char[1];\n\n  struct Fallback { void operator()();};\n  struct Derived : T, Fallback { Derived() {} };\n\n  template<typename U>\n  static no& test(decltype(&U::operator())*);\n\n  template<typename U>\n  static yes& test(...);\n\n  static bool const value = sizeof(test<Derived>(0)) == sizeof(yes);\n};\n\ntemplate<typename T>\nstruct is_callable :\n  SQRAT_STD::conditional<SQRAT_STD::is_class<T>::value,\n                      has_call_operator<T>,\n                      is_function<T>>::type\n{\n};\n\ntemplate<typename T>\nconstexpr int is_callable_v = is_callable<T>::value;\n\ntemplate<class F>\nint SqGetArgCount()\n{\n  return function_args_num_v<get_callable_function_t<F>>;\n}\n\n}\n\n#if defined(SQRAT_HAS_EASTL)\nEA_RESTORE_ALL_VC_WARNINGS()\n#endif\n\n#endif\n"
  },
  {
    "path": "sqrat/include/sqrat.h",
    "content": "// Sqrat: altered version by Gaijin Games KFT\n// Sqrat: Quirrel C++ Binding Utility\n//\n\n//\n// Copyright (c) 2009 Brandon Jones\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//  claim that you wrote the original software. If you use this software\n//  in a product, an acknowledgment in the product documentation would be\n//  appreciated but is not required.\n//\n//  2. Altered source versions must be plainly marked as such, and must not be\n//  misrepresented as being the original software.\n//\n//  3. This notice may not be removed or altered from any source\n//  distribution.\n//\n\n#pragma once\n#if !defined(_SQRAT_MAIN_H_)\n#define _SQRAT_MAIN_H_\n\n#include \"sqrat/sqratTable.h\"\n#include \"sqrat/sqratClass.h\"\n#include \"sqrat/sqratFunction.h\"\n#include \"sqrat/sqratConst.h\"\n#include \"sqrat/sqratUtil.h\"\n#include \"sqrat/sqratScript.h\"\n#include \"sqrat/sqratArray.h\"\n\n#endif\n"
  },
  {
    "path": "sqstdlib/CMakeLists.txt",
    "content": "set(SQSTDLIB_SRC sqstdaux.cpp\n                 sqstdblob.cpp\n                 sqstddebug.cpp\n                 sqstdio.cpp\n                 sqstdhash.cpp\n                 sqstdmath.cpp\n                 sqstdrex.cpp\n                 sqstdstream.cpp\n                 sqstdstring.cpp\n                 sqstddatetime.cpp\n                 sqstdserialization.cpp\n                 sqstdsystem.cpp)\n\n\nadd_library(sqstdlib STATIC ${SQSTDLIB_SRC})\nadd_library(squirrel::sqstdlib ALIAS sqstdlib)\n\ntarget_include_directories(sqstdlib PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\"\n  \"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\"\n  PRIVATE\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/internal>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/squirrel>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>\"\n  )\n"
  },
  {
    "path": "sqstdlib/sqstdaux.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <sqstdaux.h>\n#include <stdio.h>\n#include <assert.h>\n#include <inttypes.h>\n#include <string.h>\n#include <stdarg.h>\n#include <squirrel/sqvm.h>\n#include <squirrel/sqstate.h>\n#include <squirrel/sqobject.h>\n#include <squirrel/sqfuncproto.h>\n#include <squirrel/sqclosure.h>\n#include <squirrel/sqtable.h>\n#include <squirrel/sqarray.h>\n#include <squirrel/sqvm.h>\n\n#define ARRAY_ELEMENTS_IN_BRIEF_DUMP 4\n#define TABLE_ELEMENTS_IN_BRIEF_DUMP 3\n\n#ifdef SQ_STACK_DUMP_SECRET_PREFIX\n    #define STRINGIZE(x) #x\n    #define SQ_STRING_EXPAND(x) STRINGIZE(x)\n    #define SECRET_PREFIX SQ_STRING_EXPAND(SQ_STACK_DUMP_SECRET_PREFIX)\n#endif\n\ntemplate<typename PrintFunc>\nstatic void print_simple_value(HSQUIRRELVM v, PrintFunc pf, SQObjectPtr &val, bool string_quotes = true)\n{\n    SQObjectPtr valStr;\n    switch (sq_type(val))\n    {\n        case OT_STRING:\n            if (v->ToString(val, valStr))\n            {\n                if (string_quotes)\n                    pf(v, \"\\\"%s\\\"\", _stringval(valStr));\n                else\n                    pf(v, \"%s\", _stringval(valStr));\n            }\n            break;\n        case OT_CLOSURE:\n            if (v->ToString(_closure(val)->_function->_name, valStr))\n                pf(v, \"FN:%s\", _stringval(valStr));\n            break;\n        case OT_NATIVECLOSURE:\n            if (v->ToString(_nativeclosure(val)->_name, valStr))\n                pf(v, \"FN:%s\", _stringval(valStr));\n            break;\n        case OT_TABLE:\n            pf(v, \"TABLE\");\n            break;\n        case OT_ARRAY:\n            pf(v, \"ARRAY\");\n            break;\n        case OT_CLASS:\n            pf(v, \"CLASS\");\n            break;\n        default:\n            if (v->ToString(val, valStr))\n                pf(v, \"%s\", _stringval(valStr));\n        break;\n    }\n}\n\n\ntemplate<typename PrintFunc>\nstatic void collect_stack_string(HSQUIRRELVM v, PrintFunc pf)\n{\n    SQStackInfos si;\n    SQInteger i;\n    SQFloat f;\n    const char *s;\n    SQInteger level=0;\n    const char *name=0;\n    SQInteger seq=0;\n    pf(v,\"\\nCALLSTACK\\n\");\n    while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si)))\n    {\n        if (si.line < 0 && level == 0) { // skip top native function\n            ++level;\n            continue;\n        }\n\n        const char *fn=\"unknown\";\n        const char *src=\"unknown\";\n        if(si.funcname)fn=si.funcname;\n        if(si.source)src=si.source;\n        pf(v,\"*FUNCTION [%s()] %s:%d\\n\",fn,src,si.line);\n        level++;\n    }\n    level=0;\n    pf(v,\"\\nLOCALS\\n\");\n\n    for(level=0;level<10;level++){\n        seq=0;\n        while((name = sq_getlocal(v,level,seq)))\n        {\n            seq++;\n#ifdef SQ_STACK_DUMP_SECRET_PREFIX\n            bool should_keep_secret = (strncmp(name, SECRET_PREFIX, sizeof(SECRET_PREFIX)/sizeof(char) - 1) == 0);\n            if (should_keep_secret) {\n                sq_pop(v, 1);\n                continue;\n            }\n#endif\n            switch(sq_gettype(v,-1))\n            {\n            case OT_NULL:\n                pf(v,\"[%s] NULL\\n\",name);\n                break;\n            case OT_INTEGER:\n                sq_getinteger(v,-1,&i);\n                pf(v,\"[%s] %\" PRId64 \"\\n\",name, int64_t(i));\n                break;\n            case OT_FLOAT:\n                sq_getfloat(v,-1,&f);\n                pf(v,\"[%s] %.14g\\n\",name,f);\n                break;\n            case OT_USERPOINTER:\n                pf(v,\"[%s] USERPOINTER\\n\",name);\n                break;\n            case OT_STRING:\n                sq_getstring(v,-1,&s);\n                pf(v,\"[%s] \\\"%s\\\"\\n\",name,s);\n                break;\n            case OT_TABLE:\n                {\n                    pf(v,\"[%s] TABLE={\",name);\n                    SQTable * t = _table(stack_get(v, -1));\n                    SQObjectPtr refidx, key, val;\n                    SQInteger idx;\n                    SQInteger count = 0;\n                    while((idx = t->Next(false, refidx, key, val)) != -1) {\n                        refidx = idx;\n                        print_simple_value(v, pf, key, false);\n                        pf(v,\"=\");\n                        print_simple_value(v, pf, val);\n                        count++;\n                        if (count != t->CountUsed())\n                            pf(v,\", \");\n                        if (count + 1 > TABLE_ELEMENTS_IN_BRIEF_DUMP && count != t->CountUsed()) {\n                            pf(v,\"...\", int(t->CountUsed()));\n                            break;\n                        }\n                    }\n                    if (t->CountUsed() > TABLE_ELEMENTS_IN_BRIEF_DUMP)\n                        pf(v,\"} (%d)\\n\", int(t->CountUsed()));\n                    else\n                        pf(v,\"}\\n\");\n                }\n                break;\n            case OT_ARRAY:\n                {\n                    pf(v,\"[%s] ARRAY=[\",name);\n                    SQArray * a = _array(stack_get(v, -1));\n                    SQObjectPtr val;\n                    for (SQInteger i = 0; i < a->Size(); i++) {\n                        a->Get(i, val);\n                        print_simple_value(v, pf, val);\n                        if (i + 1 < a->Size())\n                        {\n                            pf(v,\", \");\n                            if (i > ARRAY_ELEMENTS_IN_BRIEF_DUMP - 2) {\n                                pf(v,\"...\");\n                                break;\n                            }\n                        }\n                    }\n                    if (a->Size() > ARRAY_ELEMENTS_IN_BRIEF_DUMP)\n                        pf(v,\"] (%d)\\n\", int(a->Size()));\n                    else\n                        pf(v,\"]\\n\",name);\n                }\n                break;\n            case OT_CLOSURE:\n                pf(v,\"[%s] CLOSURE=\",name);\n                print_simple_value(v, pf, stack_get(v, -1));\n                pf(v,\"\\n\");\n                break;\n            case OT_NATIVECLOSURE:\n                pf(v,\"[%s] NATIVECLOSURE=\",name);\n                print_simple_value(v, pf, stack_get(v, -1));\n                pf(v,\"\\n\");\n                break;\n            case OT_GENERATOR:\n                pf(v,\"[%s] GENERATOR\\n\",name);\n                break;\n            case OT_USERDATA:\n                pf(v,\"[%s] USERDATA\\n\",name);\n                break;\n            case OT_THREAD:\n                pf(v,\"[%s] THREAD\\n\",name);\n                break;\n            case OT_CLASS:\n                pf(v,\"[%s] CLASS\\n\",name);\n                break;\n            case OT_INSTANCE:\n                pf(v,\"[%s] INSTANCE=\",name);\n                print_simple_value(v, pf, stack_get(v, -1));\n                pf(v,\"\\n\");\n                break;\n            case OT_WEAKREF:\n                pf(v,\"[%s] WEAKREF\\n\",name);\n                break;\n            case OT_BOOL:{\n                SQBool bval;\n                sq_getbool(v,-1,&bval);\n                pf(v,\"[%s] %s\\n\",name,bval == SQTrue ? \"true\":\"false\");\n                break;\n            }\n            default:\n                assert(0);\n                break;\n            }\n            sq_pop(v,1);\n        }\n    }\n}\n\n\nvoid sqstd_printcallstack(HSQUIRRELVM v)\n{\n    SQPRINTFUNCTION pf = sq_geterrorfunc(v);\n    if (pf)\n        collect_stack_string(v, pf);\n}\n\n\nSQRESULT sqstd_formatcallstackstring(HSQUIRRELVM v)\n{\n    int memlen = 128;\n    SQAllocContext alloc_ctx = sq_getallocctx(v);\n    char* mem = (char*)sq_malloc(alloc_ctx, memlen*sizeof(char));\n    if (!mem)\n      return sq_throwerror(v, \"Cannot allocate memory\");\n\n    char* dst = mem;\n\n    collect_stack_string(v, [alloc_ctx, &mem, &dst, &memlen](HSQUIRRELVM, const char *fmt, ...) {\n        const int appendBlock = 128;\n        va_list args;\n        va_list argsCopy;\n\n        va_start(args, fmt);\n        va_copy(argsCopy, args);\n\n        int nappend = vsnprintf(0, 0, fmt, argsCopy) + 1;\n        va_end(argsCopy);\n\n        int poffset = int(dst - mem);\n        int memleft = memlen - poffset;\n        if (memleft < nappend) {\n            int nrequire = nappend - memleft;\n            int newlen = memlen + ((nrequire / appendBlock) + 1) * appendBlock;\n            char *newmem = (char *)sq_realloc(alloc_ctx, mem, memlen*sizeof(char), newlen*sizeof(char));\n            if (!newmem)\n                return;\n            mem = newmem;\n            memlen = newlen;\n            dst = mem + poffset;\n        }\n\n        dst += vsnprintf(dst, memlen - poffset, fmt, args);\n        va_end(args);\n    });\n\n    sq_pushstring(v, mem, dst-mem);\n    sq_free(alloc_ctx, mem, memlen);\n    return SQ_OK;\n}\n\nstatic SQInteger _sqstd_aux_printerror(HSQUIRRELVM v)\n{\n    SQPRINTFUNCTION pf = sq_geterrorfunc(v);\n    if(pf) {\n        const char *sErr = 0;\n        if(sq_gettop(v)>=1) {\n            if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr)))   {\n                pf(v,\"\\nAN ERROR HAS OCCURRED [%s]\\n\",sErr);\n            }\n            else{\n                pf(v,\"\\nAN ERROR HAS OCCURRED [unknown]\\n\");\n            }\n            sqstd_printcallstack(v);\n        }\n    }\n    return 0;\n}\n\nvoid _sqstd_compiler_message(HSQUIRRELVM v,SQMessageSeverity severity,const char *sErr,const char *sSource,SQInteger line,SQInteger column, const char *extra)\n{\n    SQPRINTFUNCTION pf = sq_geterrorfunc(v);\n    if(pf) {\n        pf(v, \"%s\\n\", sErr);\n        pf(v, \"%s:%d:%d\\n\",sSource,(int)line,(int)column);\n        if (extra)\n          pf(v, \"%s\\n\", extra);\n    }\n}\n\nvoid sqstd_seterrorhandlers(HSQUIRRELVM v)\n{\n    sq_setcompilererrorhandler(v,_sqstd_compiler_message);\n    sq_newclosure(v,_sqstd_aux_printerror,0);\n    sq_seterrorhandler(v);\n}\n\n\nSQRESULT sqstd_throwerrorf(HSQUIRRELVM v,const char *err,...)\n{\n    SQInteger n=256;\n    va_list args;\nbegin:\n    va_start(args,err);\n    char *b=sq_getscratchpad(v,n);\n    SQInteger r=vsnprintf(b,n,err,args);\n    va_end(args);\n    if (r>=n) {\n        n=r+1;//required+null\n        goto begin;\n    } else if (r<0) {\n        return sq_throwerror(v,\"@failed to generate formatted error message\");\n    } else {\n        return sq_throwerror(v,b);\n    }\n}\n"
  },
  {
    "path": "sqstdlib/sqstdblob.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <new>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <string.h>\n#include <sqstdblob.h>\n#include <sqstdaux.h>\n#include \"sqstdstream.h\"\n#include \"sqstdblobimpl.h\"\n\n#define SQSTD_BLOB_TYPE_TAG ((SQUnsignedInteger)(SQSTD_STREAM_TYPE_TAG | 0x00000002))\n\n//Blob\n\n\n#define SETUP_BLOB(v) \\\n    SQBlob *self = NULL; \\\n    { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \\\n        return sq_throwerror(v,\"invalid type tag\");  } \\\n    if(!self || !self->IsValid())  \\\n        return sq_throwerror(v,\"the blob is invalid\");\n\n\nstatic SQInteger _blob_resize(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger size;\n    sq_getinteger(v,2,&size);\n    if(!self->Resize(size))\n        return sqstd_throwerrorf(v,\"resize failed, cur size=%d, requested=%d\", int(self->Len()), int(size));\n    return 0;\n}\n\nstatic void __swap_dword(unsigned int *n)\n{\n    *n=(unsigned int)(((*n&0xFF000000)>>24)  |\n            ((*n&0x00FF0000)>>8)  |\n            ((*n&0x0000FF00)<<8)  |\n            ((*n&0x000000FF)<<24));\n}\n\nstatic void __swap_word(unsigned short *n)\n{\n    *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00);\n}\n\nstatic SQInteger _blob_swap4(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger num=(self->Len()-(self->Len()%4))>>2;\n    unsigned int *t=(unsigned int *)self->GetBuf();\n    for(SQInteger i = 0; i < num; i++) {\n        __swap_dword(&t[i]);\n    }\n    return 0;\n}\n\nstatic SQInteger _blob_swap2(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger num=(self->Len()-(self->Len()%2))>>1;\n    unsigned short *t = (unsigned short *)self->GetBuf();\n    for(SQInteger i = 0; i < num; i++) {\n        __swap_word(&t[i]);\n    }\n    return 0;\n}\n\nstatic SQInteger _blob__set(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger idx,val;\n    sq_getinteger(v,2,&idx);\n    sq_getinteger(v,3,&val);\n    if(idx < 0 || idx >= self->Len())\n        return sq_throwerror(v,\"index out of range\");\n    ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val;\n    sq_push(v,3);\n    return 1;\n}\n\nstatic SQInteger _blob__get(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    SQInteger idx;\n\n    if ((sq_gettype(v, 2) & SQOBJECT_NUMERIC) == 0)\n    {\n        sq_pushnull(v);\n        return sq_throwobject(v);\n    }\n    sq_getinteger(v,2,&idx);\n    if(idx < 0 || idx >= self->Len())\n        return sq_throwerror(v,\"index out of range\");\n    sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]);\n    return 1;\n}\n\nstatic SQInteger _blob__nexti(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    if(sq_gettype(v,2) == OT_NULL) {\n        sq_pushinteger(v, 0);\n        return 1;\n    }\n    SQInteger idx;\n    if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) {\n        if(idx+1 < self->Len()) {\n            sq_pushinteger(v, idx+1);\n            return 1;\n        }\n        sq_pushnull(v);\n        return 1;\n    }\n    return sq_throwerror(v,\"internal error (_nexti) wrong argument type\");\n}\n\nstatic SQInteger _blob__typeof(HSQUIRRELVM v)\n{\n    sq_pushstring(v,\"blob\",-1);\n    return 1;\n}\n\nstatic SQInteger _blob_releasehook(HSQUIRRELVM SQ_UNUSED_ARG(vm), SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))\n{\n    SQBlob *self = (SQBlob*)p;\n    SQAllocContext alloc_ctx = self->_alloc_ctx;\n    self->~SQBlob();\n    sq_free(alloc_ctx, self, sizeof(SQBlob));\n    return 1;\n}\n\nstatic SQInteger _blob_constructor(HSQUIRRELVM v)\n{\n    SQInteger nparam = sq_gettop(v);\n    SQInteger size = 0;\n    if(nparam == 2) {\n        sq_getinteger(v, 2, &size);\n    }\n    if(size < 0) return sq_throwerror(v, \"cannot create blob with negative size\");\n    //SQBlob *b = new SQBlob(size);\n\n    SQAllocContext alloc_ctx = sq_getallocctx(v);\n    SQBlob *b = new (sq_malloc(alloc_ctx, sizeof(SQBlob)))SQBlob(alloc_ctx, size);\n    if(SQ_FAILED(sq_setinstanceup(v,1,b))) {\n        b->~SQBlob();\n        sq_free(alloc_ctx,b,sizeof(SQBlob));\n        return sq_throwerror(v, \"cannot create blob\");\n    }\n    sq_setreleasehook(v,1,_blob_releasehook);\n    return 0;\n}\n\nstatic SQInteger _blob__cloned(HSQUIRRELVM v)\n{\n    SQBlob *other = NULL;\n    {\n        if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\n            return SQ_ERROR;\n    }\n    //SQBlob *thisone = new SQBlob(other->Len());\n    SQAllocContext alloc_ctx = sq_getallocctx(v);\n    SQBlob *thisone = new (sq_malloc(alloc_ctx,sizeof(SQBlob))) SQBlob(alloc_ctx, other->Len());\n    memcpy(thisone->GetBuf(),other->GetBuf(),thisone->Len());\n    if(SQ_FAILED(sq_setinstanceup(v,1,thisone))) {\n        thisone->~SQBlob();\n        sq_free(alloc_ctx,thisone,sizeof(SQBlob));\n        return sq_throwerror(v, \"cannot clone blob\");\n    }\n    sq_setreleasehook(v,1,_blob_releasehook);\n    return 0;\n}\n\nstatic SQInteger _blob_as_string(HSQUIRRELVM v)\n{\n    SETUP_BLOB(v);\n    sq_pushstring(v, (const char *)self->GetBuf(), self->Len() / sizeof(char));\n    return 1;\n}\n\nstatic const SQRegFunctionFromStr _blob_methods[] = {\n    { _blob_constructor, \"constructor([size: int]): instance\",      \"Creates a blob of the given size (default 0)\" },\n    { _blob_resize,      \"instance.resize(size: int)\",              \"Resizes the blob to the given size\" },\n    { _blob_swap2,       \"instance.swap2()\",                        \"Byte-swaps the blob contents as an array of 16-bit values\" },\n    { _blob_swap4,       \"instance.swap4()\",                        \"Byte-swaps the blob contents as an array of 32-bit values\" },\n    { _blob_as_string,   \"instance.as_string(): string\",            \"Returns the blob contents as a string\" },\n    { _blob__set,        \"instance._set(idx: int, val: int): int\",  \"Sets the byte at the given index\" },\n    { _blob__get,        \"instance._get(idx: int): int\",            \"Returns the byte at the given index\" },\n    { _blob__typeof,     \"instance._typeof(): string\",              \"Returns 'blob'\" },\n    { _blob__nexti,      \"instance._nexti(prev): int|null\",         \"Iterator support: returns the next index or null\" },\n    { _blob__cloned,     \"instance._cloned(other: instance)\",       \"Clones the given blob into this instance\" },\n    { NULL, NULL, NULL }\n};\n\n\n\n//GLOBAL FUNCTIONS\n\nstatic SQInteger _g_blob_casti2f(HSQUIRRELVM v)\n{\n    SQInteger i;\n    sq_getinteger(v,2,&i);\n    sq_pushfloat(v,*((const SQFloat *)&i));\n    return 1;\n}\n\nstatic SQInteger _g_blob_castf2i(HSQUIRRELVM v)\n{\n    SQFloat f;\n    sq_getfloat(v,2,&f);\n    SQInteger result = 0;\n    memcpy(&result, &f, sizeof(f));\n    sq_pushinteger(v, result);\n    return 1;\n}\n\nstatic SQInteger _g_blob_swap2(HSQUIRRELVM v)\n{\n    SQInteger i;\n    sq_getinteger(v,2,&i);\n    unsigned short s = (unsigned short)i;\n    sq_pushinteger(v, ((s << 8) | ((s >> 8) & 0x00FFu)) & 0xFFFFu);\n    return 1;\n}\n\nstatic SQInteger _g_blob_swap4(HSQUIRRELVM v)\n{\n    SQInteger i;\n    sq_getinteger(v,2,&i);\n    unsigned int t4 = (unsigned int)i;\n    __swap_dword(&t4);\n    sq_pushinteger(v,(SQInteger)t4);\n    return 1;\n}\n\nstatic SQInteger _g_blob_swapfloat(HSQUIRRELVM v)\n{\n    SQFloat f;\n    sq_getfloat(v,2,&f);\n    __swap_dword((unsigned int *)&f);\n    sq_pushfloat(v,f);\n    return 1;\n}\n\nstatic const SQRegFunctionFromStr bloblib_funcs[] = {\n    { _g_blob_casti2f,   \"pure casti2f(i: int): float\",        \"Reinterprets the bits of an integer as a float\" },\n    { _g_blob_castf2i,   \"pure castf2i(f: number): int\",       \"Reinterprets the bits of a float as an integer\" },\n    { _g_blob_swap2,     \"pure swap2(val: number): int\",       \"Byte-swaps a 16-bit value\" },\n    { _g_blob_swap4,     \"pure swap4(val: number): int\",       \"Byte-swaps a 32-bit value\" },\n    { _g_blob_swapfloat, \"pure swapfloat(val: number): float\", \"Byte-swaps the bits of a float\" },\n    { NULL, NULL, NULL }\n};\n\nSQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr)\n{\n    SQBlob *blob;\n    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\n        return -1;\n    *ptr = blob->GetBuf();\n    return SQ_OK;\n}\n\nSQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx)\n{\n    SQBlob *blob;\n    if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\n        return -1;\n    return blob->Len();\n}\n\nSQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)\n{\n    SQInteger top = sq_gettop(v);\n    sq_pushregistrytable(v);\n    sq_pushstring(v,\"std_blob\",-1);\n    if(SQ_SUCCEEDED(sq_get(v,-2))) {\n        sq_remove(v,-2); //removes the registry\n        sq_push(v,1); // push the this\n        sq_pushinteger(v,size); //size\n        SQBlob *blob = NULL;\n        if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse))\n            && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) {\n            sq_remove(v,-2);\n            return blob->GetBuf();\n        }\n    }\n    sq_settop(v,top);\n    return NULL;\n}\n\nSQRESULT sqstd_register_bloblib(HSQUIRRELVM v)\n{\n    return declare_stream(v,\"blob\",(SQUserPointer)SQSTD_BLOB_TYPE_TAG,\"std_blob\",_blob_methods,bloblib_funcs);\n}\n\n"
  },
  {
    "path": "sqstdlib/sqstdblobimpl.h",
    "content": "/*  see copyright notice in squirrel.h */\n#pragma once\n\nstruct SQBlob : public SQStream\n{\n    SQBlob(SQAllocContext alloc_ctx, SQInteger size)\n        : _alloc_ctx(alloc_ctx)\n    {\n        _size = size;\n        _allocated = size;\n        _buf = (unsigned char *)sq_malloc(_alloc_ctx, size);\n        memset(_buf, 0, _size);\n        _ptr = 0;\n    }\n\n    virtual ~SQBlob() {\n        sq_free(_alloc_ctx, _buf, _allocated);\n    }\n\n    SQInteger Write(const void *buffer, SQInteger size) override {\n        if(!CanAdvance(size)) {\n            GrowBufOf(_ptr + size - _size);\n        }\n        memcpy(&_buf[_ptr], buffer, size);\n        _ptr += size;\n        return size;\n    }\n\n    SQInteger Read(void *buffer,SQInteger size) override {\n        SQInteger n = size;\n        if(!CanAdvance(size)) {\n            if((_size - _ptr) > 0)\n                n = _size - _ptr;\n            else return 0;\n        }\n        memcpy(buffer, &_buf[_ptr], n);\n        _ptr += n;\n        return n;\n    }\n\n    bool Resize(SQInteger n) {\n        if (n < 0)\n            return false;\n\n        if(n != _allocated) {\n            unsigned char *newbuf = (unsigned char *)sq_malloc(_alloc_ctx, n);\n            memset(newbuf,0,n);\n            if(_size > n)\n                memcpy(newbuf,_buf,n);\n            else\n                memcpy(newbuf,_buf,_size);\n            sq_free(_alloc_ctx, _buf,_allocated);\n            _buf=newbuf;\n            _allocated = n;\n            if(_size > _allocated)\n                _size = _allocated;\n            if(_ptr > _allocated)\n                _ptr = _allocated;\n        }\n        return true;\n    }\n\n    void GrowBufOf(SQInteger n)\n    {\n        if(_size + n > _allocated) {\n            if(_size + n > _size * 2)\n                Resize(_size + n);\n            else\n                Resize(_size * 2);\n        }\n        _size = _size + n;\n    }\n\n    bool CanAdvance(SQInteger n) {\n        if(_ptr+n>_size)return false;\n        return true;\n    }\n\n    SQInteger Seek(SQInteger offset, SQInteger origin) override {\n        switch(origin) {\n            case SQ_SEEK_SET:\n                if(offset > _size || offset < 0) return -1;\n                _ptr = offset;\n                break;\n            case SQ_SEEK_CUR:\n                if(_ptr + offset > _size || _ptr + offset < 0) return -1;\n                _ptr += offset;\n                break;\n            case SQ_SEEK_END:\n                if(_size + offset > _size || _size + offset < 0) return -1;\n                _ptr = _size + offset;\n                break;\n            default: return -1;\n        }\n        return 0;\n    }\n\n    bool IsValid() override {\n        return _size == 0 || _buf?true:false;\n    }\n\n    bool EOS() override {\n        return _ptr == _size;\n    }\n\n    SQInteger Flush() override { return 0; }\n    SQInteger Tell() override { return _ptr; }\n    SQInteger Len() override { return _size; }\n    SQUserPointer GetBuf(){ return _buf; }\n\npublic:\n    SQAllocContext _alloc_ctx;\n\nprivate:\n    SQInteger _size;\n    SQInteger _allocated;\n    SQInteger _ptr;\n    unsigned char *_buf;\n};\n"
  },
  {
    "path": "sqstdlib/sqstddatetime.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <time.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <sqstddatetime.h>\n\n\nstatic SQInteger _datetime_clock(HSQUIRRELVM v)\n{\n    sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC);\n    return 1;\n}\n\nstatic SQInteger _datetime_time(HSQUIRRELVM v)\n{\n    SQInteger t = (SQInteger)time(NULL);\n    sq_pushinteger(v,t);\n    return 1;\n}\n\nstatic void _set_integer_slot(HSQUIRRELVM v,const char *name,SQInteger val)\n{\n    sq_pushstring(v,name,-1);\n    sq_pushinteger(v,val);\n    sq_rawset(v,-3);\n}\n\nstatic SQInteger _datetime_date(HSQUIRRELVM v)\n{\n    time_t t;\n    SQInteger it;\n    SQInteger format = 'l';\n    if(sq_gettop(v) > 1) {\n        sq_getinteger(v,2,&it);\n        t = it;\n        if(sq_gettop(v) > 2) {\n            sq_getinteger(v,3,(SQInteger*)&format);\n        }\n    }\n    else {\n        time(&t);\n    }\n    tm *date;\n    if(format == 'u')\n        date = gmtime(&t);\n    else\n        date = localtime(&t);\n    if(!date)\n        return sq_throwerror(v,\"crt api failure\");\n    sq_newtable(v);\n    _set_integer_slot(v, \"sec\", date->tm_sec);\n    _set_integer_slot(v, \"min\", date->tm_min);\n    _set_integer_slot(v, \"hour\", date->tm_hour);\n    _set_integer_slot(v, \"day\", date->tm_mday);\n    _set_integer_slot(v, \"month\", date->tm_mon);\n    _set_integer_slot(v, \"year\", date->tm_year+1900);\n    _set_integer_slot(v, \"wday\", date->tm_wday);\n    _set_integer_slot(v, \"yday\", date->tm_yday);\n    return 1;\n}\n\n\n\nstatic const SQRegFunctionFromStr datetimelib_funcs[] = {\n    { _datetime_clock, \"pure clock(): float\", \"Returns CPU time used by the process in seconds\" },\n    { _datetime_time,  \"time(): int\", \"Returns the current time as seconds since the Unix epoch\" },\n    { _datetime_date,  \"date([time: int, format: int]): table\", \"Returns a table with date fields (sec,min,hour,day,month,year,wday,yday); format 'l' for local, 'u' for UTC\" },\n    { NULL, NULL, NULL }\n};\n\n\nSQRESULT sqstd_register_datetimelib(HSQUIRRELVM v)\n{\n    SQInteger i = 0;\n    while (datetimelib_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, datetimelib_funcs[i].f, 0, datetimelib_funcs[i].declstring, datetimelib_funcs[i].docstring);\n        i++;\n    }\n    return SQ_OK;\n}\n"
  },
  {
    "path": "sqstdlib/sqstddebug.cpp",
    "content": "#include <squirrel.h>\n#include <sqstddebug.h>\n#include <sqstdaux.h>\n#include <string.h>\n#include <assert.h>\n#include <squirrel/sqvm.h>\n#include <squirrel/sqstate.h>\n#include <squirrel/sqobject.h>\n#include <squirrel/sqfuncproto.h>\n#include <squirrel/sqclosure.h>\n#include <squirrel/sqtable.h>\n#include <squirrel/sqarray.h>\n#include <squirrel/sqclass.h>\n#include <squirrel/compiler/sqtypeparser.h>\n#include <chrono>\n\n\nstatic SQInteger debug_seterrorhandler(HSQUIRRELVM v)\n{\n  sq_seterrorhandler(v);\n  return 0;\n}\n\nstatic SQInteger debug_setdebughook(HSQUIRRELVM v)\n{\n  sq_setdebughook(v);\n  return 0;\n}\n\nextern SQInteger __sq_getcallstackinfos(HSQUIRRELVM v, SQInteger level);\n\nstatic SQInteger debug_getstackinfos(HSQUIRRELVM v)\n{\n  SQInteger level;\n  sq_getinteger(v, -1, &level);\n  return __sq_getcallstackinfos(v, level);\n}\n\nstatic SQInteger debug_getlocals(HSQUIRRELVM v)\n{\n    SQInteger level = 1;\n    SQBool includeInternal = false;\n\n    if (sq_gettop(v) >= 2)\n        sq_getinteger(v, 2, &level);\n    if (sq_gettop(v) >= 3)\n        sq_getbool(v, 3, &includeInternal);\n\n    sq_newtable(v);\n    const char *name = NULL;\n\n    SQInteger seq=0;\n    SQInteger prevTop = sq_gettop(v);\n    while ((name = sq_getlocal(v, level, seq))) {\n        ++seq;\n        if (!includeInternal && (name[0] == '@' || strcmp(name, \"this\")==0 || strcmp(name, \"vargv\")==0)) {\n            sq_pop(v, 1);\n            continue;\n        }\n\n        sq_pushstring(v, name, -1);\n        sq_push(v, -2);\n        sq_newslot(v, -4, SQFalse);\n        sq_pop(v, 1);\n    }\n    return 1;\n}\n\n\nstatic SQInteger debug_get_stack_top(HSQUIRRELVM v)\n{\n    sq_pushinteger(v, sq_gettop(v));\n    return 1;\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\nstatic SQInteger debug_collectgarbage(HSQUIRRELVM v)\n{\n    sq_pushinteger(v, sq_collectgarbage(v));\n    return 1;\n}\nstatic SQInteger debug_resurrectunreachable(HSQUIRRELVM v)\n{\n    sq_resurrectunreachable(v);\n    return 1;\n}\n#endif\n\nstatic SQInteger debug_getbuildinfo(HSQUIRRELVM v)\n{\n  sq_newtable(v);\n  sq_pushstring(v, \"version\", -1);\n  sq_pushstring(v, SQUIRREL_VERSION, -1);\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, \"charsize\", -1);\n  sq_pushinteger(v, sizeof(char));\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, \"intsize\", -1);\n  sq_pushinteger(v, sizeof(SQInteger));\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, \"floatsize\", -1);\n  sq_pushinteger(v, sizeof(SQFloat));\n  sq_newslot(v, -3, SQFalse);\n  sq_pushstring(v, \"gc\", -1);\n#ifndef NO_GARBAGE_COLLECTOR\n  sq_pushstring(v, \"enabled\", -1);\n#else\n  sq_pushstring(v, \"disabled\", -1);\n#endif // NO_GARBAGE_COLLECTOR\n  sq_newslot(v, -3, SQFalse);\n  return 1;\n}\n\nstatic SQInteger debug_doc(HSQUIRRELVM v)\n{\n    HSQOBJECT subject;\n    sq_getstackobj(v, 2, &subject);\n\n    SQObjectPtr value;\n    SQObjectPtr key;\n    key._type = OT_USERPOINTER;\n    switch(sq_type(subject))\n    {\n        case OT_CLOSURE:\n            key._unVal.pUserPointer = (void *)_closure(subject)->_function;\n            break;\n        case OT_NATIVECLOSURE:\n            key._unVal.pUserPointer = (void *)_nativeclosure(subject)->_function;\n            break;\n        case OT_INSTANCE:\n            key._unVal.pUserPointer = (void *)_instance(subject)->_class;\n            break;\n        default:\n            key._unVal.pUserPointer = subject._unVal.pUserPointer;\n            break;\n    }\n\n    if (!_table(_ss(v)->doc_objects)->Get(key, value))\n    {\n        sq_pushnull(v);\n        return 1;\n    }\n\n    sq_pushobject(v, value);\n    return 1;\n}\n\n\nstatic int nparamscheck_to_required_args(int nparamscheck)\n{\n    if (nparamscheck==0) // No param check\n        return 0;\n    return abs(nparamscheck)-1; // Don't include `this`\n}\n\nstatic SQInteger debug_get_function_info_table(HSQUIRRELVM v)\n{\n    HSQOBJECT subject;\n    sq_getstackobj(v, 2, &subject);\n\n    SQObjectPtr nullVal;\n    SQObjectPtr docObject;\n    SQObjectPtr value;\n    SQObjectPtr key;\n    key._type = OT_USERPOINTER;\n    SQFunctionType ft(_ss(v));\n    bool initialized = false;\n    bool native = false;\n\n    switch (sq_type(subject))\n    {\n        case OT_CLOSURE:\n        {\n            SQFunctionProto *f = _closure(subject)->_function;\n            key._unVal.pUserPointer = (void *)_closure(subject)->_function;\n            _table(_ss(v)->doc_objects)->Get(key, docObject);\n\n            ft.functionName = f->_name;\n            ft.returnTypeMask = f->_result_type_mask;\n            ft.objectTypeMask = f->_param_type_masks[0];\n            ft.requiredArgs = f->_nparameters - f->_ndefaultparams - 1;\n            ft.pure = f->_purefunction;\n            ft.nodiscard = f->_nodiscard;\n\n            int cnt = f->_nparameters - (f->_varparams ? 1 : 0);\n            for (SQInteger n = 1; n < cnt; n++) {\n                ft.argNames.push_back(f->_parameters[n]);\n                ft.argTypeMask.push_back(f->_param_type_masks[n]);\n                ft.defaultValues.push_back(nullVal);\n                // TODO: defaultValues\n            }\n\n            if (f->_varparams) {\n                ft.ellipsisArgTypeMask = f->_param_type_masks[f->_nparameters - 1];\n            }\n\n            initialized = true;\n            break;\n        }\n\n        case OT_NATIVECLOSURE: {\n            native = true;\n\n            key._unVal.pUserPointer = (void *)_nativeclosure(subject)->_function;\n            _table(_ss(v)->doc_objects)->Get(key, docObject);\n\n            key._unVal.pUserPointer = (void *)((size_t)(void *)_nativeclosure(subject)->_function ^ ~size_t(0));\n            if (_table(_ss(v)->doc_objects)->Get(key, value)) {\n                SQInteger errorPos = -1;\n                SQObjectPtr errorString;\n                if (sq_isstring(value)) {\n                   if (sq_parse_function_type_string(v, _stringval(value), ft, errorPos, errorString)) {\n                       initialized = true;\n                   }\n                   else {\n                       // TODO: raise errorString\n                   }\n                }\n                break;\n            }\n            else {\n                SQNativeClosure *f = _nativeclosure(subject);\n\n                ft.functionName = f->_name;\n                ft.returnTypeMask = ~0u;\n                ft.objectTypeMask = f->_typecheck.size() > 0 ? f->_typecheck[0] : (_RT_INSTANCE | _RT_TABLE | _RT_CLASS | _RT_USERDATA | _RT_NULL);\n                ft.requiredArgs = nparamscheck_to_required_args(f->_nparamscheck);\n                ft.pure = f->_purefunction;\n                ft.nodiscard = f->_nodiscard;\n\n                int cnt = (ft.requiredArgs > f->_typecheck.size()) ? ft.requiredArgs : f->_typecheck.size();\n\n                for (SQInteger n = 1; n < cnt; n++) {\n                    char buf[16] = { 0 };\n                    snprintf(buf, sizeof(buf), \"arg%d\", int(n));\n                    ft.argNames.push_back(SQObjectPtr(SQString::Create(_ss(v), buf, -1)));\n                    ft.argTypeMask.push_back(n < f->_typecheck.size() ? f->_typecheck[n] : ~0u);\n                    ft.defaultValues.push_back(nullVal);\n                    // TODO: defaultValues\n                }\n\n                if (f->_nparamscheck < 0) {\n                    ft.ellipsisArgTypeMask = ~0u;\n                }\n\n                initialized = true;\n                break;\n            }\n        }\n\n        default:\n            break;\n    }\n\n    if (!initialized) {\n        sq_pushnull(v);\n        return 1;\n    }\n\n    SQTable *res = SQTable::Create(_ss(v), 12);\n\n    #define SET_SLOT(name, value) \\\n        res->NewSlot(SQObjectPtr(SQString::Create(_ss(v), name, -1)), SQObjectPtr(value))\n\n    SET_SLOT(\"functionName\", ft.functionName);\n    SET_SLOT(\"returnTypeMask\", (int)ft.returnTypeMask);\n    SET_SLOT(\"objectTypeMask\", (int)ft.objectTypeMask);\n    SET_SLOT(\"ellipsisArgTypeMask\", (int)ft.ellipsisArgTypeMask);\n    SET_SLOT(\"requiredArgs\", ft.requiredArgs);\n    SET_SLOT(\"native\", native);\n    SET_SLOT(\"pure\", ft.pure);\n    SET_SLOT(\"nodiscard\", ft.nodiscard);\n    SET_SLOT(\"doc\", docObject);\n\n    SQObjectPtr argNames(SQArray::Create(_ss(v), ft.argNames.size()));\n    for (SQInteger n = 0; n < ft.argNames.size(); n++)\n        _array(argNames)->Set((SQInteger)n, ft.argNames[n]);\n    SET_SLOT(\"argNames\", argNames);\n\n    SQObjectPtr argTypeMask(SQArray::Create(_ss(v), ft.argTypeMask.size()));\n    for (SQInteger n = 0; n < ft.argTypeMask.size(); n++)\n        _array(argTypeMask)->Set((SQInteger)n, SQObjectPtr((int)ft.argTypeMask[n]));\n    SET_SLOT(\"argTypeMask\", argTypeMask);\n\n    /*SQObjectPtr defaultValues(SQArray::Create(_ss(v), ft.defaultValues.size()));\n    for (SQInteger n = 0; n < ft.defaultValues.size(); n++)\n        _array(defaultValues)->Set((SQInteger)n, ft.defaultValues[n]);\n    SET_SLOT(\"defaultValues\", defaultValues);*/\n\n    #undef SET_SLOT\n\n    v->Push(SQObjectPtr(res));\n    return 1;\n}\n\nstatic SQInteger debug_get_function_decl_string(HSQUIRRELVM v)\n{\n    HSQOBJECT subject;\n    sq_getstackobj(v, 2, &subject);\n\n    SQObjectPtr nullVal;\n    SQObjectPtr value;\n    SQObjectPtr key;\n    key._type = OT_USERPOINTER;\n    switch (sq_type(subject))\n    {\n        case OT_CLOSURE:\n        {\n            SQFunctionProto *f = _closure(subject)->_function;\n            SQFunctionType ft(_ss(v));\n\n            ft.functionName = f->_name;\n            ft.returnTypeMask = f->_result_type_mask;\n            ft.objectTypeMask = f->_param_type_masks[0];\n            ft.requiredArgs = f->_nparameters - f->_ndefaultparams - 1;\n            ft.pure = f->_purefunction;\n            ft.nodiscard = f->_nodiscard;\n\n            int cnt = f->_nparameters - (f->_varparams ? 1 : 0);\n            for (SQInteger n = 1; n < cnt; n++) {\n                ft.argNames.push_back(f->_parameters[n]);\n                ft.argTypeMask.push_back(f->_param_type_masks[n]);\n                ft.defaultValues.push_back(nullVal);\n                // TODO: defaultValues\n            }\n\n            if (f->_varparams) {\n                ft.ellipsisArgTypeMask = f->_param_type_masks[f->_nparameters - 1];\n            }\n\n            sq_pushobject(v, sq_stringify_function_type(v, ft));\n            return 1;\n        }\n\n        case OT_NATIVECLOSURE:\n            key._unVal.pUserPointer = (void *)((size_t)(void *)_nativeclosure(subject)->_function ^ ~size_t(0));\n            if (_table(_ss(v)->doc_objects)->Get(key, value)) {\n                sq_pushobject(v, value);\n                return 1;\n            }\n            else {\n                SQNativeClosure *f = _nativeclosure(subject);\n                SQFunctionType ft(_ss(v));\n\n                ft.functionName = f->_name;\n                ft.returnTypeMask = ~0u;\n                ft.objectTypeMask = f->_typecheck.size() > 0 ? f->_typecheck[0] : (_RT_INSTANCE | _RT_TABLE | _RT_CLASS | _RT_USERDATA | _RT_NULL);\n                ft.requiredArgs = nparamscheck_to_required_args(f->_nparamscheck);\n                ft.pure = f->_purefunction;\n                ft.nodiscard = f->_nodiscard;\n\n                int nArgsFromMask = f->_typecheck.size() ? f->_typecheck.size()-1 : 0; // Exclude `this`\n                int nArgsDisplayed = f->_nparamscheck >= 0 ? ft.requiredArgs : // for fixed args count ignore mask length\n                                    (ft.requiredArgs > nArgsFromMask) ? ft.requiredArgs : nArgsFromMask;\n\n                for (SQInteger n = 1; n <= nArgsDisplayed; n++) {\n                    char buf[16] = { 0 };\n                    snprintf(buf, sizeof(buf), \"arg%d\", int(n));\n                    ft.argNames.push_back(SQObjectPtr(SQString::Create(_ss(v), buf, -1)));\n                    ft.argTypeMask.push_back(n < f->_typecheck.size() ? f->_typecheck[n] : ~0u);\n                    ft.defaultValues.push_back(nullVal);\n                    // TODO: defaultValues\n                }\n\n                if (f->_nparamscheck < 0) {\n                    ft.ellipsisArgTypeMask = ~0u;\n                }\n\n                sq_pushobject(v, sq_stringify_function_type(v, ft));\n                return 1;\n            }\n            break;\n\n        default:\n            break;\n    }\n\n    sq_pushnull(v);\n    return 1;\n}\n\nstatic SQInteger format_call_stack_string(HSQUIRRELVM v)\n{\n  SQRESULT r = sqstd_formatcallstackstring(v);\n  return SQ_SUCCEEDED(r) ? 1 : SQ_ERROR;\n}\n\n\nstatic SQInteger debug_type_mask_to_string(HSQUIRRELVM v)\n{\n  SQInteger typeMask = 0;\n  sq_getinteger(v, 2, &typeMask);\n\n  char buf[2048];\n  sq_stringify_type_mask(buf, sizeof(buf), typeMask);\n\n  sq_pushstring(v, buf, -1);\n\n  return 1;\n}\n\n\nstatic SQUnsignedInteger32 sq_debug_time_msec()\n{\n  return SQUnsignedInteger32(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count());\n}\n\n\nstatic bool default_quirrel_watchdog_hook(HSQUIRRELVM v, bool kick)\n{\n  if (_ss(v)->watchdog_threshold_msec && !kick)\n  {\n    SQUnsignedInteger32 curTime = sq_debug_time_msec();\n    if (curTime - _ss(v)->watchdog_last_alive_time_msec > _ss(v)->watchdog_threshold_msec)\n    {\n      _ss(v)->watchdog_last_alive_time_msec = curTime;\n      return false;\n    }\n    return true;\n  }\n\n  if (kick)\n  {\n    _ss(v)->watchdog_last_alive_time_msec = sq_debug_time_msec();\n    return true;\n  }\n\n  return true;\n}\n\nSQInteger debug_script_watchdog_kick(HSQUIRRELVM v)\n{\n  sq_kick_watchdog(v);\n  return SQ_OK;\n}\n\nSQInteger debug_set_script_watchdog_timeout_msec(HSQUIRRELVM v)\n{\n  SQInteger timeoutMsec = 0;\n  sq_getinteger(v, 2, &timeoutMsec);\n  SQInteger prevTimeout = sq_set_watchdog_timeout_msec(v, timeoutMsec);\n  sq_pushinteger(v, prevTimeout);\n  return 1;\n}\n\n\nstatic const SQRegFunctionFromStr debuglib_funcs[] = {\n    { debug_seterrorhandler, \"seterrorhandler(handler: function|null)\", \"Installs the given function as the VM error handler; null clears it\" },\n    { debug_setdebughook, \"setdebughook(hook: function|null)\", \"Installs the given function as the VM debug hook; null clears it\" },\n    { debug_getstackinfos, \"getstackinfos(level: int): table|null\", \"Returns call stack information for the given stack level\" },\n    { format_call_stack_string, \"format_call_stack_string(): string\", \"Returns a formatted string describing the current call stack\" },\n    { debug_getlocals, \"getlocals([level: int, include_internal: bool]): table\", \"Returns a table of local variables at the given stack level\" },\n    { debug_get_stack_top, \"get_stack_top(): int\", \"Returns the current VM stack top index\" },\n    { debug_script_watchdog_kick, \"script_watchdog_kick()\", \"Resets the script watchdog timer\" },\n    { debug_set_script_watchdog_timeout_msec, \"set_script_watchdog_timeout_msec(timeout_msec: int): int\", \"Sets the script watchdog timeout in milliseconds and returns the previous value\" },\n    { debug_get_function_decl_string, \"get_function_decl_string(func: function): string|null\", \"Returns a function declaration string\" },\n    { debug_type_mask_to_string, \"type_mask_to_string(mask: int): string\", \"Convert type mask to human-readable string\" },\n    { debug_get_function_info_table, \"get_function_info_table(func: function): table|null\", \"Returns meta information about a function as table\" },\n    { debug_doc, \"doc(subject: table|function|instance|class): string|null\", \"Returns a documentation string for a function, class, or table\" },\n#ifndef NO_GARBAGE_COLLECTOR\n    { debug_collectgarbage, \"collectgarbage(): int\", \"Runs the garbage collector and returns the number of reclaimed objects\" },\n    { debug_resurrectunreachable, \"resurrectunreachable(): array|null\", \"Resurrects unreachable objects for inspection\" },\n#endif\n    { debug_getbuildinfo, \"getbuildinfo(): table\", \"Returns a table describing the Quirrel build (version, sizes, GC status)\" },\n    { NULL, NULL, NULL }\n};\n\n\nSQRESULT sqstd_register_debuglib(HSQUIRRELVM v)\n{\n  SQInteger i = 0;\n  while (debuglib_funcs[i].f) {\n    sq_new_closure_slot_from_decl_string(v, debuglib_funcs[i].f, 0, debuglib_funcs[i].declstring, debuglib_funcs[i].docstring);\n    i++;\n  }\n\n  SQWATCHDOGHOOK prevHook = sq_set_watchdog_hook(v, default_quirrel_watchdog_hook);\n  if (prevHook != nullptr)\n    sq_set_watchdog_hook(v, prevHook);\n\n  return SQ_OK;\n}\n"
  },
  {
    "path": "sqstdlib/sqstdhash.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <float.h>\n#include <assert.h>\n#include <squirrel/sqvm.h>\n#include <squirrel/sqstate.h>\n#include <squirrel/sqtable.h>\n#include <squirrel/sqclass.h>\n#include <squirrel/sqarray.h>\n\n// FNV-1a hash parameters\n#define SQ_M_HASH_MULTIPLIER 1099511628211LU\n#define SQ_M_HASH_INIT 14695981039346656037LU\n\nstatic SQInteger math_recursive_hash_impl(HSQUIRRELVM vm, HSQOBJECT &obj, SQUnsignedInteger prev_hash,\n  SQUnsignedInteger &out_hash, SQInteger depth)\n{\n  if (depth <= 0) {\n    out_hash = prev_hash;\n    return SQ_OK;\n  }\n\n  SQObjectType objType = sq_type(obj);\n  prev_hash = (objType ^ prev_hash) * SQ_M_HASH_MULTIPLIER;\n\n  switch (objType) {\n    case OT_NULL:\n    case OT_BOOL:\n    case OT_INTEGER:\n      out_hash = (SQUnsignedInteger(_integer(obj)) ^ prev_hash) * SQ_M_HASH_MULTIPLIER;\n      break;\n    case OT_FLOAT: {\n      #ifdef SQUSEDOUBLE\n        uint64_t fbits = 0;\n        memcpy(&fbits, &_float(obj), sizeof(SQFloat));\n        out_hash = (SQUnsignedInteger(fbits ^ (fbits >> 42u)) ^ prev_hash) * SQ_M_HASH_MULTIPLIER;\n      #else\n        uint32_t fbits = 0;\n        memcpy(&fbits, &_float(obj), sizeof(SQFloat));\n        out_hash = (SQUnsignedInteger(fbits ^ (fbits >> 21u)) ^ prev_hash) * SQ_M_HASH_MULTIPLIER;\n      #endif\n      break;\n    }\n    case OT_STRING: {\n      SQString *str = _string(obj);\n      out_hash = (prev_hash ^ str->_len) * SQ_M_HASH_MULTIPLIER;\n      out_hash = (out_hash ^ str->_hash) * SQ_M_HASH_MULTIPLIER;\n      break;\n    }\n    case OT_ARRAY: {\n      SQArray *arr = _array(obj);\n      SQUnsignedInteger h = prev_hash;\n      SQInteger arrSize = arr->Size();\n      for (SQInteger i = 0; i < arrSize; ++i) {\n        SQUnsignedInteger resultHash = 0;\n        if (SQ_FAILED(math_recursive_hash_impl(vm, arr->_values[i], h, resultHash, depth - 1)))\n          return SQ_ERROR;\n        h = resultHash;\n      }\n      out_hash = h;\n      break;\n    }\n    case OT_TABLE:\n    case OT_CLASS:\n    case OT_INSTANCE: {\n      out_hash = prev_hash;\n      sq_pushobject(vm, obj);\n      sq_pushnull(vm);\n      while (SQ_SUCCEEDED(sq_next(vm, -2))) {\n        SQUnsignedInteger resultHash = 0;\n        HSQOBJECT key = stack_get(vm, -2);\n        if (SQ_FAILED(math_recursive_hash_impl(vm, key, out_hash, resultHash, depth - 1)))\n          return SQ_ERROR;\n        out_hash = resultHash;\n        HSQOBJECT val = stack_get(vm, -1);\n        if (SQ_FAILED(math_recursive_hash_impl(vm, val, out_hash, resultHash, depth - 1)))\n          return SQ_ERROR;\n        out_hash = resultHash;\n        sq_pop(vm, 2);\n      }\n      sq_pop(vm, 2);\n      break;\n    }\n\n    default:\n      out_hash = prev_hash;\n      return sq_throwerror(vm, \"unsupported type for hashing\");\n  }\n\n  out_hash ^= out_hash >> 15;\n  return SQ_OK;\n}\n\nSQInteger sq_math_hash(HSQUIRRELVM v)\n{\n  HSQOBJECT obj;\n  sq_getstackobj(v, 2, &obj);\n  SQUnsignedInteger resultHash = 0;\n  if (SQ_FAILED(math_recursive_hash_impl(v, obj, SQ_M_HASH_INIT, resultHash, 1)))\n    return SQ_ERROR;\n  sq_pushinteger(v, SQInteger(resultHash) & (~SQUnsignedInteger(0) >> 1));\n  return 1;\n}\n\nSQInteger sq_math_deep_hash(HSQUIRRELVM v)\n{\n  SQInteger argDepth = 200; // not a very deep by default to avoid stack overflows in case of circular references\n  if (sq_gettop(v) >= 3) {\n    if (SQ_FAILED(sq_getinteger(v, 3, &argDepth)))\n      return sq_throwerror(v, \"invalid param\");\n    if (argDepth < 1)\n      return sq_throwerror(v, \"hashing depth must be >= 1\");\n  }\n  HSQOBJECT obj;\n  sq_getstackobj(v, 2, &obj);\n  SQUnsignedInteger resultHash = 0;\n  if (SQ_FAILED(math_recursive_hash_impl(v, obj, SQ_M_HASH_INIT, resultHash, argDepth)))\n    return SQ_ERROR;\n  sq_pushinteger(v, SQInteger(resultHash) & (~SQUnsignedInteger(0) >> 1));\n  return 1;\n}\n"
  },
  {
    "path": "sqstdlib/sqstdhash.h",
    "content": "#pragma once\n\n#include <squirrel.h>\nSQInteger sq_math_hash(HSQUIRRELVM v);\nSQInteger sq_math_deep_hash(HSQUIRRELVM v);\n"
  },
  {
    "path": "sqstdlib/sqstdio.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <new>\n#include <stdio.h>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <assert.h>\n#include \"sqstdstream.h\"\n\n#define SQSTD_FILE_TYPE_TAG ((SQUnsignedInteger)(SQSTD_STREAM_TYPE_TAG | 0x00000001))\n//basic API\nSQFILE sqstd_fopen(const char *filename ,const char *mode)\n{\n    return (SQFILE)fopen(filename,mode);\n}\n\nSQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)\n{\n    SQInteger ret = (SQInteger)fread(buffer,size,count,(FILE *)file);\n    return ret;\n}\n\nSQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)\n{\n    return (SQInteger)fwrite(buffer,size,count,(FILE *)file);\n}\n\nSQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)\n{\n    SQInteger realorigin;\n    switch(origin) {\n        case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;\n        case SQ_SEEK_END: realorigin = SEEK_END; break;\n        case SQ_SEEK_SET: realorigin = SEEK_SET; break;\n        default: return -1; //failed\n    }\n    return fseek((FILE *)file,(long)offset,(int)realorigin);\n}\n\nSQInteger sqstd_ftell(SQFILE file)\n{\n    return ftell((FILE *)file);\n}\n\nSQInteger sqstd_fflush(SQFILE file)\n{\n    return fflush((FILE *)file);\n}\n\nSQInteger sqstd_fclose(SQFILE file)\n{\n    return fclose((FILE *)file);\n}\n\nSQInteger sqstd_feof(SQFILE file)\n{\n    return feof((FILE *)file);\n}\n\n//File\nstruct SQFile : public SQStream {\n    SQFile(SQAllocContext alloc_ctx)\n        : _alloc_ctx(alloc_ctx)\n        , _handle(nullptr)\n        , _owns(false)\n    {}\n\n    SQFile(SQAllocContext alloc_ctx, SQFILE file, bool owns)\n        : _alloc_ctx(alloc_ctx)\n        , _handle(file)\n        , _owns(owns)\n    {}\n\n    virtual ~SQFile() { Close(); }\n\n    bool Open(const char *filename ,const char *mode) {\n        Close();\n        if( (_handle = sqstd_fopen(filename,mode)) ) {\n            _owns = true;\n            return true;\n        }\n        return false;\n    }\n\n    void Close() {\n        if(_handle && _owns) {\n            sqstd_fclose(_handle);\n            _handle = NULL;\n            _owns = false;\n        }\n    }\n\n    SQInteger Read(void *buffer,SQInteger size) override {\n        return sqstd_fread(buffer,1,size,_handle);\n    }\n\n    SQInteger Write(const void *buffer,SQInteger size) override {\n        return sqstd_fwrite(const_cast<void*>(buffer), 1, size, _handle);\n    }\n\n    SQInteger Flush() override {\n        return sqstd_fflush(_handle);\n    }\n\n    SQInteger Tell() override {\n        return sqstd_ftell(_handle);\n    }\n\n    SQInteger Len() override {\n        SQInteger prevpos=Tell();\n        Seek(0,SQ_SEEK_END);\n        SQInteger size=Tell();\n        Seek(prevpos,SQ_SEEK_SET);\n        return size;\n    }\n\n    SQInteger Seek(SQInteger offset, SQInteger origin) override {\n        return sqstd_fseek(_handle,offset,origin);\n    }\n\n    bool IsValid() override { return _handle?true:false; }\n    bool EOS() override { return Tell()==Len()?true:false;}\n    SQFILE GetHandle() {return _handle;}\n\npublic:\n    SQAllocContext _alloc_ctx;\n\nprivate:\n    SQFILE _handle;\n    bool _owns;\n};\n\nstatic SQInteger _file__typeof(HSQUIRRELVM v)\n{\n    sq_pushstring(v,\"file\",-1);\n    return 1;\n}\n\nstatic SQInteger _file_releasehook(HSQUIRRELVM SQ_UNUSED_ARG(vm), SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))\n{\n    SQFile *self = (SQFile*)p;\n    SQAllocContext alloc_ctx = self->_alloc_ctx;\n    self->~SQFile();\n    sq_free(alloc_ctx, self,sizeof(SQFile));\n    return 1;\n}\n\nstatic bool _file_is_valid_mode(const char *mode)\n{\n    static const char *ok[] = {\n        \"r\", \"w\", \"a\", \"r+\", \"w+\", \"a+\",\n        \"rb\", \"wb\", \"ab\", \"rt\", \"wt\", \"at\",\n        \"r+b\", \"w+b\", \"a+b\", \"rb+\", \"wb+\", \"ab+\",\n        \"r+t\", \"w+t\", \"a+t\", \"rt+\", \"wt+\", \"at+\", nullptr };\n    if (!mode)\n        return false;\n    for (int i = 0; ok[i]; ++i)\n        if (!strcmp(mode, ok[i]))\n            return true;\n    return false;\n}\n\nstatic SQInteger _file_constructor(HSQUIRRELVM v)\n{\n    const char *filename,*mode;\n    bool owns = true;\n    SQFile *f;\n    SQFILE newf;\n    if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {\n        sq_getstring(v, 2, &filename);\n        sq_getstring(v, 3, &mode);\n        if(!_file_is_valid_mode(mode))\n            return sq_throwerror(v, \"invalid file mode\");\n        newf = sqstd_fopen(filename, mode);\n        if(!newf) return sq_throwerror(v, \"cannot open file\");\n    } else if(sq_gettype(v,2) == OT_USERPOINTER) {\n        owns = !(sq_gettype(v,3) == OT_NULL);\n        sq_getuserpointer(v,2,&newf);\n    } else {\n        return sq_throwerror(v,\"wrong parameter\");\n    }\n\n    SQAllocContext alloc_ctx = sq_getallocctx(v);\n\n    f = new (sq_malloc(alloc_ctx, sizeof(SQFile)))SQFile(alloc_ctx,newf,owns);\n    if(SQ_FAILED(sq_setinstanceup(v,1,f))) {\n        f->~SQFile();\n        sq_free(alloc_ctx,f,sizeof(SQFile));\n        return sq_throwerror(v, \"cannot create blob with negative size\");\n    }\n    sq_setreleasehook(v,1,_file_releasehook);\n    return 0;\n}\n\nstatic SQInteger _file_close(HSQUIRRELVM v)\n{\n    SQFile *self = NULL;\n    if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG))\n        && self != NULL)\n    {\n        self->Close();\n    }\n    return 0;\n}\n\nstatic const SQRegFunctionFromStr _file_methods[] = {\n    { _file_constructor, \"constructor(path: string|userpointer, mode: string|int|null): instance\",\n      \"Two forms: (path: string, mode: string) opens the file via fopen with the given mode; \"\n      \"(handle: userpointer, own) wraps an existing FILE* and takes ownership (closes on destruction) \"\n      \"when `own` is non-null, or shares it without closing when `own` is null\" },\n\n    { _file__typeof, \"instance._typeof(): string\", \"Returns 'file'\" },\n    { _file_close,   \"instance.close()\", \"Closes the file if it is still open\" },\n    { NULL, NULL, NULL }\n};\n\n\n\nSQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)\n{\n    SQInteger top = sq_gettop(v);\n    sq_pushregistrytable(v);\n    sq_pushstring(v,\"std_file\",-1);\n    if(SQ_SUCCEEDED(sq_get(v,-2))) {\n        sq_remove(v,-2); //removes the registry\n        sq_pushroottable(v); // push the this\n        sq_pushuserpointer(v,file); //file\n        if(own){\n            sq_pushinteger(v,1); //true\n        }\n        else{\n            sq_pushnull(v); //false\n        }\n        if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {\n            sq_remove(v,-2);\n            return SQ_OK;\n        }\n    }\n    else\n        assert(0);\n    sq_settop(v,top);\n    return SQ_ERROR;\n}\n\nSQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)\n{\n    SQFile *fileobj = NULL;\n    if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {\n        *file = fileobj->GetHandle();\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"not a file\");\n}\n\n\n\n#define IO_BUFFER_SIZE 2048\nstruct IOBuffer {\n    unsigned char buffer[IO_BUFFER_SIZE];\n    SQInteger size;\n    SQInteger ptr;\n    SQFILE file;\n};\n\nSQInteger _read_byte(IOBuffer *iobuffer)\n{\n    if(iobuffer->ptr < iobuffer->size) {\n\n        SQInteger ret = iobuffer->buffer[iobuffer->ptr];\n        iobuffer->ptr++;\n        return ret;\n    }\n    else {\n        if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )\n        {\n            SQInteger ret = iobuffer->buffer[0];\n            iobuffer->ptr = 1;\n            return ret;\n        }\n    }\n\n    return 0;\n}\n\nSQInteger _read_two_bytes(IOBuffer *iobuffer)\n{\n    if(iobuffer->ptr < iobuffer->size) {\n        if(iobuffer->size < 2) return 0;\n        SQInteger ret = *((const wchar_t*)&iobuffer->buffer[iobuffer->ptr]);\n        iobuffer->ptr += 2;\n        return ret;\n    }\n    else {\n        if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 )\n        {\n            if(iobuffer->size < 2) return 0;\n            SQInteger ret = *((const wchar_t*)&iobuffer->buffer[0]);\n            iobuffer->ptr = 2;\n            return ret;\n        }\n    }\n\n    return 0;\n}\n\n\nSQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)\n{\n    SQInteger ret;\n    if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;\n    return -1;\n}\n\nSQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)\n{\n    return sqstd_fwrite(p,1,size,(SQFILE)file);\n}\n\nstatic char *readFileData(HSQUIRRELVM v, SQFILE f, SQInteger &s) {\n    sqstd_fseek(f, 0, SQ_SEEK_SET);\n    SQInteger size = sqstd_fseek(f, 0, SQ_SEEK_END);\n    char *buffer = (char *)sq_malloc(sq_getallocctx(v), size * sizeof(char));\n\n    sqstd_fseek(f, 0, SQ_SEEK_SET);\n    s = sqstd_fread(buffer, sizeof(char), size, f);\n\n    return buffer;\n}\n\nSQRESULT sqstd_loadfile(HSQUIRRELVM v,const char *filename,SQBool printerror)\n{\n    SQFILE file = sqstd_fopen(filename,\"rb\");\n\n    if(file){\n        SQInteger size = 0;\n        char *buffer = readFileData(v, file, size);\n        SQRESULT r = SQ_ERROR;\n\n        if(SQ_SUCCEEDED(sq_compile(v,buffer,size,filename,printerror))){\n            r = SQ_OK;\n        }\n        sq_free(sq_getallocctx(v), buffer, size);\n        sqstd_fclose(file);\n        return r;\n    }\n    return sq_throwerror(v,\"cannot open the file\");\n}\n\nSQRESULT sqstd_dofile(HSQUIRRELVM v,const char *filename,SQBool retval,SQBool printerror)\n{\n    //at least one entry must exist in order for us to push it as the environment\n    if(sq_gettop(v) == 0)\n        return sq_throwerror(v,\"environment table expected\");\n\n    if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {\n        sq_push(v,-2);\n        if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {\n            sq_remove(v,retval?-2:-1); //removes the closure\n            return 1;\n        }\n        sq_pop(v,1); //removes the closure\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const char *filename)\n{\n    SQFILE file = sqstd_fopen(filename,\"wb+\");\n    if(!file) return sq_throwerror(v,\"cannot open the file\");\n    if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {\n        sqstd_fclose(file);\n        return SQ_OK;\n    }\n    sqstd_fclose(file);\n    return SQ_ERROR; //forward the error\n}\n\nstatic const SQRegFunctionFromStr iolib_funcs[] = {\n    { NULL, NULL, NULL }\n};\n\nSQRESULT sqstd_register_iolib(HSQUIRRELVM v)\n{\n    SQInteger top = sq_gettop(v);\n    //create delegate\n    declare_stream(v,\"file\",(SQUserPointer)SQSTD_FILE_TYPE_TAG,\"std_file\",_file_methods,iolib_funcs);\n    sq_pushstring(v,\"stdout\",-1);\n    sqstd_createfile(v,stdout,SQFalse);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,\"stdin\",-1);\n    sqstd_createfile(v,stdin,SQFalse);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,\"stderr\",-1);\n    sqstd_createfile(v,stderr,SQFalse);\n    sq_newslot(v,-3,SQFalse);\n    sq_settop(v,top);\n    return SQ_OK;\n}\n"
  },
  {
    "path": "sqstdlib/sqstdmath.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <math.h>\n#include <stdlib.h>\n#include <sqstdmath.h>\n#include <float.h>\n#include <assert.h>\n#include <squirrel/sqvm.h>\n#include <squirrel/sqstate.h>\n#include <chrono>\n#include \"sqstdhash.h\"\n\n#define SINGLE_ARG_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \\\n    SQFloat f; \\\n    sq_getfloat(v,2,&f); \\\n    sq_pushfloat(v,(SQFloat)_funcname(f)); \\\n    return 1; \\\n}\n\n#define TWO_ARGS_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \\\n    SQFloat p1,p2; \\\n    sq_getfloat(v,2,&p1); \\\n    sq_getfloat(v,3,&p2); \\\n    sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \\\n    return 1; \\\n}\n\n#define SQ_MAX_INT_RANDOM 0x7FFFFFFF\n\n\nstatic void math_randomize_seed(HSQUIRRELVM v) {\n    SQUnsignedInteger32 s = SQUnsignedInteger32(size_t(v->_sharedstate)) * 123 + SQUnsignedInteger32(size_t(&v));\n    s ^= SQUnsignedInteger32(std::chrono::high_resolution_clock::now().time_since_epoch().count());\n    v->_sharedstate->rand_seed += s ^ (s >> 10);\n}\n\nstatic SQInteger math_srand(HSQUIRRELVM v)\n{\n    SQInteger i;\n    if(SQ_FAILED(sq_getinteger(v,2,&i)))\n        return sq_throwerror(v,\"invalid param\");\n    v->_sharedstate->rand_seed = SQUnsignedInteger32(i);\n    return 0;\n}\n\n// Constants 1664525, 1013904223 are based on the multiplier and increment suggested by Numerical Recipes\n// and used by the PCG family of random number generators.\n// This LCG has a full period of 2^32 and a good spectral test value of M_8 = 0.73201\n\nstatic SQInteger math_rand(HSQUIRRELVM v)\n{\n    SQUnsignedInteger32 seed = v->_sharedstate->rand_seed = 1664525 * v->_sharedstate->rand_seed + 1013904223;\n    sq_pushinteger(v, (seed ^ (seed >> 16u)) & SQ_MAX_INT_RANDOM);\n    return 1;\n}\n\nstatic SQInteger math_abs(HSQUIRRELVM v)\n{\n    SQObject arg;\n    sq_getstackobj(v, 2, &arg);\n    if (sq_type(arg) == OT_FLOAT)\n        sq_pushfloat(v, fabs(_float(arg)));\n    else\n        sq_pushinteger(v, abs(_integer(arg)));\n    return 1;\n}\n\nstatic SQInteger math_acos(HSQUIRRELVM v) {\n    SQFloat f;\n    sq_getfloat(v, 2, &f);\n    if (f < SQFloat(-1))\n      f = SQFloat(-1);\n    if (f > SQFloat(1))\n      f = SQFloat(1);\n    sq_pushfloat(v, (SQFloat)acos(f));\n    return 1;\n}\n\nstatic SQInteger math_asin(HSQUIRRELVM v) {\n    SQFloat f;\n    sq_getfloat(v, 2, &f);\n    if (f < SQFloat(-1))\n      f = SQFloat(-1);\n    if (f > SQFloat(1))\n      f = SQFloat(1);\n    sq_pushfloat(v, (SQFloat)asin(f));\n    return 1;\n}\n\nSINGLE_ARG_FUNC(sqrt)\nSINGLE_ARG_FUNC(fabs)\nSINGLE_ARG_FUNC(sin)\nSINGLE_ARG_FUNC(cos)\nSINGLE_ARG_FUNC(log)\nSINGLE_ARG_FUNC(log10)\nSINGLE_ARG_FUNC(tan)\nSINGLE_ARG_FUNC(atan)\nTWO_ARGS_FUNC(atan2)\nTWO_ARGS_FUNC(pow)\nSINGLE_ARG_FUNC(floor)\nSINGLE_ARG_FUNC(ceil)\nSINGLE_ARG_FUNC(round)\nSINGLE_ARG_FUNC(exp)\n\ntemplate<SQInteger CmpRes>\nstatic SQInteger math_min_max(HSQUIRRELVM v)\n{\n  SQInteger nArgs = sq_gettop(v);\n  SQObject objRes;\n  sq_getstackobj(v, 2, &objRes);\n\n  for (SQInteger i = 3; i <= nArgs; ++i) {\n    SQObject cur;\n    sq_getstackobj(v, i, &cur);\n    if (!(sq_type(cur) & SQOBJECT_NUMERIC)) {\n      sq_throwparamtypeerror(v, i, _RT_FLOAT | _RT_INTEGER, sq_type(cur));\n      return SQ_ERROR;\n    }\n\n    SQInteger cres = 0;\n    if (!sq_cmpraw(v, cur, objRes, cres))\n      return sq_throwerror(v, \"Internal error, comparison failed\");\n\n    if (cres == CmpRes)\n      objRes = cur;\n  }\n\n  sq_pushobject(v, objRes);\n  return 1;\n}\n\nstatic SQInteger math_min(HSQUIRRELVM v)\n{\n  return math_min_max<-1>(v);\n}\n\nstatic SQInteger math_max(HSQUIRRELVM v)\n{\n  return math_min_max<+1>(v);\n}\n\nstatic SQInteger math_clamp(HSQUIRRELVM v)\n{\n  SQObject x, lo, hi;\n  SQInteger cres = 0;\n\n  sq_getstackobj(v, 2, &x);\n  sq_getstackobj(v, 3, &lo);\n  sq_getstackobj(v, 4, &hi);\n\n  const char *cmpFailedErrText = \"Internal error, comparison failed\";\n\n  if (!sq_cmpraw(v, lo, hi, cres))\n    return sq_throwerror(v, cmpFailedErrText);\n\n  if (cres > 0)\n    return sq_throwerror(v, \"Invalid clamp range: min>max\");\n\n  if (!sq_cmpraw(v, x, lo, cres))\n    return sq_throwerror(v, cmpFailedErrText);\n\n  if (cres < 0) {\n    sq_pushobject(v, lo);\n    return 1;\n  }\n\n  if (!sq_cmpraw(v, x, hi, cres))\n    return sq_throwerror(v, cmpFailedErrText);\n\n  if (cres > 0) {\n    sq_pushobject(v, hi);\n    return 1;\n  }\n\n  sq_pushobject(v, x);\n  return 1;\n}\n\n#ifndef M_PI\n#define M_PI (3.14159265358979323846)\n#endif\n\nstatic const SQRegFunctionFromStr mathlib_funcs[] = {\n    { math_sqrt,   \"pure sqrt(x: number): number\",   \"Returns the square root of x\" },\n    { math_sin,    \"pure sin(x: number): number\",    \"Returns the sine of x (in radians)\" },\n    { math_cos,    \"pure cos(x: number): number\",    \"Returns the cosine of x (in radians)\" },\n    { math_asin,   \"pure asin(x: number): number\",   \"Returns the arcsine of x\" },\n    { math_acos,   \"pure acos(x: number): number\",   \"Returns the arccosine of x\" },\n    { math_log,    \"pure log(x: number): number\",    \"Returns the natural logarithm of x\" },\n    { math_log10,  \"pure log10(x: number): number\",  \"Returns the base-10 logarithm of x\" },\n    { math_tan,    \"pure tan(x: number): number\",    \"Returns the tangent of x (in radians)\" },\n    { math_atan,   \"pure atan(x: number): number\",   \"Returns the arctangent of x\" },\n    { math_atan2,  \"pure atan2(y: number, x: number): number\", \"Returns the arctangent of y/x using the signs to determine the quadrant\" },\n    { math_pow,    \"pure pow(x: number, y: number): number\", \"Returns x raised to the power y\" },\n    { math_floor,  \"pure floor(x: number): number\",  \"Rounds x downward to the nearest integer\" },\n    { math_ceil,   \"pure ceil(x: number): number\",   \"Rounds x upward to the nearest integer\" },\n    { math_round,  \"pure round(x: number): number\",  \"Rounds x to the nearest integer\" },\n    { math_exp,    \"pure exp(x: number): number\",    \"Returns e raised to the power of x\" },\n    { math_srand,  \"srand(seed: int)\",               \"Sets the seed for rand()\" },\n    { math_rand,   \"rand(): int\",                    \"Returns a random integer in range 0..RAND_MAX\" },\n    { math_fabs,   \"pure fabs(x: number): float\",    \"Returns the absolute value of float(x)\" },\n    { math_abs,    \"pure abs(x: number): number\",    \"Returns the absolute value of x\" },\n    { math_min,    \"pure min(x: number, y: number, ...: number): number\", \"Returns the minimum value from the arguments\" },\n    { math_max,    \"pure max(x: number, y: number, ...: number): number\", \"Returns the maximum value from the arguments\" },\n    { math_clamp,  \"pure clamp(x: number, min: number, max: number): number\", \"Clamps x to the range [min, max]\" },\n    { sq_math_hash, \"pure hash(obj): int\",           \"Returns a hash value for the given object\" },\n    { sq_math_deep_hash, \"pure deep_hash(obj, [depth: int]): int\", \"Returns a hash value for the given object, hashing nested objects up to the specified depth\" },\n    { NULL, NULL, NULL }\n};\n\nSQRESULT sqstd_register_mathlib(HSQUIRRELVM v)\n{\n    math_randomize_seed(v);\n\n    SQInteger i = 0;\n    while (mathlib_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, mathlib_funcs[i].f, 0, mathlib_funcs[i].declstring, mathlib_funcs[i].docstring);\n        i++;\n    }\n\n    // Constants\n    sq_pushstring(v,\"RAND_MAX\",-1);\n    sq_pushinteger(v,SQ_MAX_INT_RANDOM);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,\"PI\",-1);\n    sq_pushfloat(v,(SQFloat)M_PI);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,\"FLT_MAX\",-1);\n    sq_pushfloat(v,(SQFloat)FLT_MAX);\n    sq_newslot(v,-3,SQFalse);\n    sq_pushstring(v,\"FLT_MIN\",-1);\n    sq_pushfloat(v,(SQFloat)FLT_MIN);\n    sq_newslot(v,-3,SQFalse);\n\n    return SQ_OK;\n}\n"
  },
  {
    "path": "sqstdlib/sqstdrex.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <string.h>\n#include <ctype.h>\n#include <setjmp.h>\n#include <sqstdstring.h>\n#include <sq_char_class.h>\n\n#define SQREX_DEBUG 0\n\n#if SQREX_DEBUG\n#include <stdio.h>\n\nstatic const char *g_nnames[] =\n{\n    \"NONE\",\"OP_GREEDY\",   \"OP_OR\",\n    \"OP_EXPR\",\"OP_NOCAPEXPR\",\"OP_DOT\",   \"OP_CLASS\",\n    \"OP_CCLASS\",\"OP_NCLASS\",\"OP_RANGE\",\"OP_CHAR\",\n    \"OP_EOL\",\"OP_BOL\",\"OP_WB\",\"OP_MB\"\n};\n\n#endif\n\n#define SQ_MAX_CHAR 0xFF\n\n#define OP_GREEDY       (SQ_MAX_CHAR+1) // * + ? {n}\n#define OP_OR           (SQ_MAX_CHAR+2)\n#define OP_EXPR         (SQ_MAX_CHAR+3) //parentesis ()\n#define OP_NOCAPEXPR    (SQ_MAX_CHAR+4) //parentesis (?:)\n#define OP_DOT          (SQ_MAX_CHAR+5)\n#define OP_CLASS        (SQ_MAX_CHAR+6)\n#define OP_CCLASS       (SQ_MAX_CHAR+7)\n#define OP_NCLASS       (SQ_MAX_CHAR+8) //negates class the [^\n#define OP_RANGE        (SQ_MAX_CHAR+9)\n//#define OP_CHAR       (SQ_MAX_CHAR+10)\n#define OP_EOL          (SQ_MAX_CHAR+11)\n#define OP_BOL          (SQ_MAX_CHAR+12)\n#define OP_WB           (SQ_MAX_CHAR+13)\n#define OP_MB           (SQ_MAX_CHAR+14) //match balanced\n\n#define SQREX_SYMBOL_ANY_CHAR ('.')\n#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')\n#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')\n#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')\n#define SQREX_SYMBOL_BRANCH ('|')\n#define SQREX_SYMBOL_END_OF_STRING ('$')\n#define SQREX_SYMBOL_BEGINNING_OF_STRING ('^')\n#define SQREX_SYMBOL_ESCAPE_CHAR ('\\\\')\n\n\ntypedef int SQRexNodeType;\n\ntypedef struct tagSQRexNode{\n    SQRexNodeType type;\n    SQInteger left;\n    SQInteger right;\n    SQInteger next;\n}SQRexNode;\n\nstruct SQRex{\n    SQAllocContext _alloc_ctx;\n    const char *_eol;\n    const char *_bol;\n    const char *_p;\n    SQInteger _first;\n    SQRexNode *_nodes;\n    SQInteger _nallocated;\n    SQInteger _nsize;\n    SQInteger _depth;\n    SQInteger _nsubexpr;\n    SQRexMatch *_matches;\n    SQInteger _currsubexp;\n    void *_jmpbuf;\n    const char **_error;\n};\n\nstatic SQInteger sqstd_rex_list(SQRex *exp);\n\nstatic SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)\n{\n    SQRexNode n;\n    n.type = type;\n    n.next = n.right = n.left = -1;\n    if(type == OP_EXPR)\n        n.right = exp->_nsubexpr++;\n    if(exp->_nallocated < (exp->_nsize + 1)) {\n        SQInteger oldsize = exp->_nallocated;\n        exp->_nallocated *= 2;\n        exp->_nodes = (SQRexNode *)sq_realloc(exp->_alloc_ctx,exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));\n    }\n    exp->_nodes[exp->_nsize++] = n;\n    SQInteger newid = exp->_nsize - 1;\n    return (SQInteger)newid;\n}\n\nstatic void sqstd_rex_error(SQRex *exp,const char *error)\n{\n    if(exp->_error) *exp->_error = error;\n    longjmp(*((jmp_buf*)exp->_jmpbuf),-1);\n}\n\nstatic void sqstd_rex_expect(SQRex *exp, SQInteger n){\n    if((*exp->_p) != n)\n        sqstd_rex_error(exp, \"expected paren\");\n    exp->_p++;\n}\n\nstatic char sqstd_rex_escapechar(SQRex *exp)\n{\n    if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){\n        exp->_p++;\n        if(*exp->_p == '\\0') sqstd_rex_error(exp,\"letter expected\");\n        switch(*exp->_p) {\n        case 'v': exp->_p++; return '\\v';\n        case 'n': exp->_p++; return '\\n';\n        case 't': exp->_p++; return '\\t';\n        case 'r': exp->_p++; return '\\r';\n        case 'f': exp->_p++; return '\\f';\n        default: return (*exp->_p++);\n        }\n    } else if(!sq_isprint(*exp->_p)) sqstd_rex_error(exp,\"letter expected\");\n    return (*exp->_p++);\n}\n\nstatic SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)\n{\n    SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);\n    exp->_nodes[n].left = classid;\n    return n;\n}\n\nstatic SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)\n{\n    char t;\n    if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {\n        exp->_p++;\n        switch(*exp->_p) {\n            case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\\n');\n            case 't': exp->_p++; return sqstd_rex_newnode(exp,'\\t');\n            case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\\r');\n            case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\\f');\n            case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\\v');\n            case 'a': case 'A': case 'w': case 'W': case 's': case 'S':\n            case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':\n            case 'p': case 'P': case 'l': case 'u':\n                {\n                t = *exp->_p; exp->_p++;\n                return sqstd_rex_charclass(exp,t);\n                }\n            case 'm':\n                {\n                     exp->_p++; //skip 'm'\n                     if(*exp->_p == '\\0') sqstd_rex_error(exp,\"balanced chars expected\");\n                     char cb = *exp->_p; //cb = character begin match\n                     exp->_p++;\n                     if(*exp->_p == '\\0') sqstd_rex_error(exp,\"balanced chars expected\");\n                     char ce = *exp->_p; //ce = character end match\n                     exp->_p++; //points to the next char to be parsed\n                     if ( cb == ce ) sqstd_rex_error(exp,\"open/close char can't be the same\");\n                     SQInteger node =  sqstd_rex_newnode(exp,OP_MB);\n                     exp->_nodes[node].left = cb;\n                     exp->_nodes[node].right = ce;\n                     return node;\n                }\n            case 0:\n                sqstd_rex_error(exp,\"letter expected for argument of escape sequence\");\n                break;\n            case 'b':\n            case 'B':\n                if(!isclass) {\n                    SQInteger node = sqstd_rex_newnode(exp,OP_WB);\n                    exp->_nodes[node].left = *exp->_p;\n                    exp->_p++;\n                    return node;\n                }\n                [[fallthrough]];\n            default:\n                t = *exp->_p; exp->_p++;\n                return sqstd_rex_newnode(exp,t);\n        }\n    }\n    else if(!sq_isprint(*exp->_p)) {\n\n        sqstd_rex_error(exp,\"letter expected\");\n    }\n    t = *exp->_p; exp->_p++;\n    return sqstd_rex_newnode(exp,t);\n}\nstatic SQInteger sqstd_rex_class(SQRex *exp)\n{\n    SQInteger ret = -1;\n    SQInteger first = -1,chain;\n    if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){\n        ret = sqstd_rex_newnode(exp,OP_NCLASS);\n        exp->_p++;\n    }else ret = sqstd_rex_newnode(exp,OP_CLASS);\n\n    if(*exp->_p == ']') sqstd_rex_error(exp,\"empty class\");\n    chain = ret;\n    while(*exp->_p != ']' && *exp->_p != '\\0') {\n        if(*exp->_p == '-' && first != -1){\n            SQInteger r;\n            exp->_p++; // skip '-'\n            if(*exp->_p == ']') sqstd_rex_error(exp,\"unfinished range\");\n            r = sqstd_rex_newnode(exp,OP_RANGE);\n            if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,\"cannot use character classes in ranges\");\n            exp->_nodes[r].left = exp->_nodes[first].type;\n            SQInteger t = sqstd_rex_escapechar(exp);\n            if(exp->_nodes[r].left > t) sqstd_rex_error(exp,\"invalid range\");\n            exp->_nodes[r].right = t;\n            exp->_nodes[chain].next = r;\n            chain = r;\n            first = -1;\n        }\n        else{\n            if(first!=-1){\n                SQInteger c = first;\n                exp->_nodes[chain].next = c;\n                chain = c;\n                first = sqstd_rex_charnode(exp,SQTrue);\n            }\n            else{\n                first = sqstd_rex_charnode(exp,SQTrue);\n            }\n        }\n    }\n    if(*exp->_p == '\\0') sqstd_rex_error(exp,\"unterminated character class\");\n    if(first!=-1){\n        SQInteger c = first;\n        exp->_nodes[chain].next = c;\n    }\n    /* hack? */\n    exp->_nodes[ret].left = exp->_nodes[ret].next;\n    exp->_nodes[ret].next = -1;\n    return ret;\n}\n\nstatic SQInteger sqstd_rex_parsenumber(SQRex *exp)\n{\n    SQInteger ret = *exp->_p-'0';\n    SQInteger positions = 10;\n    exp->_p++;\n    while(sq_isdigit(*exp->_p)) {\n        ret = ret*10+(*exp->_p++-'0');\n        if(positions==1000000000) sqstd_rex_error(exp,\"overflow in numeric constant\");\n        positions *= 10;\n    };\n    return ret;\n}\n\nstatic SQInteger sqstd_rex_element(SQRex *exp)\n{\n    exp->_depth++;\n\n    struct AutoDec {\n        AutoDec(SQInteger *varPtr) : varPtr(varPtr) {}\n        ~AutoDec() { (*varPtr)--; }\n        SQInteger *varPtr;\n    } autodec(&exp->_depth);\n\n    if(exp->_depth > 200) sqstd_rex_error(exp, \"pattern exceeds maximum allowed nesting depth\");\n    if(exp->_nsize > 2000) sqstd_rex_error(exp, \"pattern too complex\");\n    SQInteger ret = -1;\n    switch(*exp->_p)\n    {\n    case '(': {\n        SQInteger expr;\n        exp->_p++;\n\n\n        if(*exp->_p =='?') {\n            exp->_p++;\n            sqstd_rex_expect(exp,':');\n            expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);\n        }\n        else\n            expr = sqstd_rex_newnode(exp,OP_EXPR);\n        SQInteger newn = sqstd_rex_list(exp);\n        exp->_nodes[expr].left = newn;\n        ret = expr;\n        sqstd_rex_expect(exp,')');\n              }\n              break;\n    case '[':\n        exp->_p++;\n        ret = sqstd_rex_class(exp);\n        sqstd_rex_expect(exp,']');\n        break;\n    case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;\n    case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;\n    default:\n        ret = sqstd_rex_charnode(exp,SQFalse);\n        break;\n    }\n\n\n    SQBool isgreedy = SQFalse;\n    unsigned short p0 = 0, p1 = 0;\n    switch(*exp->_p){\n        case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;\n        case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;\n        case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break;\n        case '{':\n            exp->_p++;\n            {\n                if(!sq_isdigit(*exp->_p)) sqstd_rex_error(exp,\"number expected\");\n                SQInteger n = sqstd_rex_parsenumber(exp);\n                if(n > 0xFFFE) sqstd_rex_error(exp,\"quantifier value too large\");\n                p0 = (unsigned short)n;\n            }\n            /*******************************/\n            switch(*exp->_p) {\n        case '}':\n            p1 = p0; exp->_p++;\n            break;\n        case ',':\n            exp->_p++;\n            p1 = 0xFFFF;\n            if(sq_isdigit(*exp->_p)){\n                SQInteger n = sqstd_rex_parsenumber(exp);\n                if(n > 0xFFFE) sqstd_rex_error(exp,\"quantifier value too large\");\n                p1 = (unsigned short)n;\n            }\n            sqstd_rex_expect(exp,'}');\n            if(p0 > p1) sqstd_rex_error(exp,\"invalid quantifier range: min > max\");\n            break;\n        default:\n            sqstd_rex_error(exp,\", or } expected\");\n            }\n            /*******************************/\n            isgreedy = SQTrue;\n            break;\n\n    }\n    if(isgreedy) {\n        SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);\n        exp->_nodes[nnode].left = ret;\n        exp->_nodes[nnode].right = ((SQInteger)p0<<16)|p1;\n        ret = nnode;\n    }\n\n    if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\\0')) {\n        SQInteger nnode = sqstd_rex_element(exp);\n        exp->_nodes[ret].next = nnode;\n    }\n\n    return ret;\n}\n\nstatic SQInteger sqstd_rex_list(SQRex *exp)\n{\n    SQInteger ret=-1,e;\n    if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {\n        exp->_p++;\n        ret = sqstd_rex_newnode(exp,OP_BOL);\n    }\n    e = sqstd_rex_element(exp);\n    if(ret != -1) {\n        exp->_nodes[ret].next = e;\n    }\n    else ret = e;\n\n    if(*exp->_p == SQREX_SYMBOL_BRANCH) {\n        SQInteger temp,tright;\n        exp->_p++;\n        temp = sqstd_rex_newnode(exp,OP_OR);\n        exp->_nodes[temp].left = ret;\n        tright = sqstd_rex_list(exp);\n        exp->_nodes[temp].right = tright;\n        ret = temp;\n    }\n    return ret;\n}\n\nstatic SQBool sqstd_rex_matchcclass(SQInteger cclass,char c)\n{\n    switch(cclass) {\n    case 'a': return sq_isalpha(c)?SQTrue:SQFalse;\n    case 'A': return !sq_isalpha(c)?SQTrue:SQFalse;\n    case 'w': return (sq_isalnum(c) || c == '_')?SQTrue:SQFalse;\n    case 'W': return (!sq_isalnum(c) && c != '_')?SQTrue:SQFalse;\n    case 's': return sq_isspace(c)?SQTrue:SQFalse;\n    case 'S': return !sq_isspace(c)?SQTrue:SQFalse;\n    case 'd': return sq_isdigit(c)?SQTrue:SQFalse;\n    case 'D': return !sq_isdigit(c)?SQTrue:SQFalse;\n    case 'x': return sq_isxdigit(c)?SQTrue:SQFalse;\n    case 'X': return !sq_isxdigit(c)?SQTrue:SQFalse;\n    case 'c': return sq_iscntrl(c)?SQTrue:SQFalse;\n    case 'C': return !sq_iscntrl(c)?SQTrue:SQFalse;\n    case 'p': return sq_ispunct(c)?SQTrue:SQFalse;\n    case 'P': return !sq_ispunct(c)?SQTrue:SQFalse;\n    case 'l': return sq_islower(c)?SQTrue:SQFalse;\n    case 'u': return sq_isupper(c)?SQTrue:SQFalse;\n    }\n    return SQFalse; /*cannot happen*/\n}\n\nstatic SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,char c)\n{\n    do {\n        switch(node->type) {\n            case OP_RANGE:\n                if((unsigned char)c >= node->left && (unsigned char)c <= node->right) return SQTrue;\n                break;\n            case OP_CCLASS:\n                if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;\n                break;\n            default:\n                if(c == node->type)return SQTrue;\n        }\n    } while((node->next != -1) && (node = &exp->_nodes[node->next]));\n    return SQFalse;\n}\n\nstatic const char *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const char *str,SQRexNode *next)\n{\n\n    SQRexNodeType type = node->type;\n    switch(type) {\n    case OP_GREEDY: {\n        //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;\n        SQRexNode *greedystop = NULL;\n        SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;\n        const char *s=str, *good = str;\n\n        if(node->next != -1) {\n            greedystop = &exp->_nodes[node->next];\n        }\n        else {\n            greedystop = next;\n        }\n\n        while((nmaches == 0xFFFF || nmaches < p1)) {\n\n            const char *stop;\n            const char *prev = s;\n            if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))\n                break;\n            nmaches++;\n            good=s;\n            if(s == prev)\n                break; // zero-width match, don't loop\n            if(greedystop) {\n                //checks that 0 matches satisfy the expression(if so skips)\n                //if not would always stop(for instance if is a '?')\n                if(greedystop->type != OP_GREEDY ||\n                ((greedystop->right >> 16)&0x0000FFFF) != 0)\n                {\n                    SQRexNode *gnext = NULL;\n                    if(greedystop->next != -1) {\n                        gnext = &exp->_nodes[greedystop->next];\n                    }else if(next && next->next != -1){\n                        gnext = &exp->_nodes[next->next];\n                    }\n                    stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);\n                    if(stop) {\n                        //if satisfied stop it\n                        if(p0 == p1 && p0 == nmaches) break;\n                        else if(nmaches >= p0 && p1 == 0xFFFF) break;\n                        else if(nmaches >= p0 && nmaches <= p1) break;\n                    }\n                }\n            }\n\n            if(s >= exp->_eol)\n                break;\n        }\n        if(p0 == p1 && p0 == nmaches) return good;\n        else if(nmaches >= p0 && p1 == 0xFFFF) return good;\n        else if(nmaches >= p0 && nmaches <= p1) return good;\n        return NULL;\n    }\n    case OP_OR: {\n            const char *asd = str;\n            SQRexNode *temp=&exp->_nodes[node->left];\n            while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\n                if(temp->next != -1)\n                    temp = &exp->_nodes[temp->next];\n                else\n                    return asd;\n            }\n            asd = str;\n            temp = &exp->_nodes[node->right];\n            while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) {\n                if(temp->next != -1)\n                    temp = &exp->_nodes[temp->next];\n                else\n                    return asd;\n            }\n            return NULL;\n    }\n    case OP_EXPR:\n    case OP_NOCAPEXPR:{\n            SQRexNode *n = &exp->_nodes[node->left];\n            const char *cur = str;\n            SQInteger capture = -1;\n            if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\n                capture = exp->_currsubexp;\n                exp->_matches[capture].begin = cur;\n                exp->_currsubexp++;\n            }\n            SQInteger tempcap = exp->_currsubexp;\n            do {\n                SQRexNode *subnext = NULL;\n                if(n->next != -1) {\n                    subnext = &exp->_nodes[n->next];\n                }else {\n                    subnext = next;\n                }\n                if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {\n                    if(capture != -1){\n                        exp->_matches[capture].begin = 0;\n                        exp->_matches[capture].len = 0;\n                    }\n                    return NULL;\n                }\n            } while((n->next != -1) && (n = &exp->_nodes[n->next]));\n\n            exp->_currsubexp = tempcap;\n            if(capture != -1)\n                exp->_matches[capture].len = cur - exp->_matches[capture].begin;\n            return cur;\n    }\n    case OP_WB: {\n        SQBool isWordBoundary;\n        if(str == exp->_bol) {\n            isWordBoundary = (str < exp->_eol && !sq_isspace(*str)) ? SQTrue : SQFalse;\n        } else if(str == exp->_eol) {\n            isWordBoundary = !sq_isspace(*(str-1)) ? SQTrue : SQFalse;\n        } else {\n            isWordBoundary = (sq_isspace(*str) != sq_isspace(*(str-1))) ? SQTrue : SQFalse;\n        }\n        return (node->left == 'b') ? (isWordBoundary ? str : NULL) : (isWordBoundary ? NULL : str);\n    }\n    case OP_BOL:\n        if(str == exp->_bol) return str;\n        return NULL;\n    case OP_EOL:\n        if(str == exp->_eol) return str;\n        return NULL;\n    case OP_DOT:{\n        if (str == exp->_eol) return NULL;\n        str++;\n                }\n        return str;\n    case OP_NCLASS:\n    case OP_CLASS:\n        if (str == exp->_eol) return NULL;\n        if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {\n            str++;\n            return str;\n        }\n        return NULL;\n    case OP_CCLASS:\n        if (str == exp->_eol) return NULL;\n        if(sqstd_rex_matchcclass(node->left,*str)) {\n            str++;\n            return str;\n        }\n        return NULL;\n    case OP_MB:\n        {\n            SQInteger cb = node->left; //char that opens a balanced expression\n            if(str == exp->_eol || *str != cb) return NULL; // string doesnt start with open char\n            SQInteger ce = node->right; //char that closes a balanced expression\n            SQInteger cont = 1;\n            const char *streol = exp->_eol;\n            while (++str < streol) {\n              if (*str == ce) {\n                if (--cont == 0) {\n                    return ++str;\n                }\n              }\n              else if (*str == cb) cont++;\n            }\n        }\n        return NULL; // string ends out of balance\n    default: /* char */\n        if (str == exp->_eol) return NULL;\n        if(*str != node->type) return NULL;\n        str++;\n        return str;\n    }\n    return NULL;\n}\n\n/* public api */\nSQRex *sqstd_rex_compile(SQAllocContext alloc_ctx, const char *pattern,const char **error)\n{\n    SQRex * volatile exp = (SQRex *)sq_malloc(alloc_ctx, sizeof(SQRex)); // \"volatile\" is needed for setjmp()\n    exp->_alloc_ctx = alloc_ctx;\n    exp->_eol = exp->_bol = NULL;\n    exp->_p = pattern;\n    exp->_nallocated = (SQInteger)strlen(pattern) * sizeof(char);\n    if(exp->_nallocated < 4) exp->_nallocated = 4;\n    exp->_nodes = (SQRexNode *)sq_malloc(alloc_ctx, exp->_nallocated * sizeof(SQRexNode));\n    exp->_nsize = 0;\n    exp->_depth = 0;\n    exp->_matches = 0;\n    exp->_nsubexpr = 0;\n    exp->_first = sqstd_rex_newnode(exp,OP_EXPR);\n    exp->_error = error;\n    exp->_jmpbuf = sq_malloc(alloc_ctx, sizeof(jmp_buf));\n    if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\n        SQInteger res = sqstd_rex_list(exp);\n        exp->_nodes[exp->_first].left = res;\n        if(*exp->_p!='\\0')\n            sqstd_rex_error(exp,\"unexpected character\");\n#if SQREX_DEBUG\n        {\n            SQInteger nsize,i;\n            SQRexNode *t;\n            nsize = exp->_nsize;\n            t = &exp->_nodes[0];\n            printf(\"\\n\");\n            for(i = 0;i < nsize; i++) {\n                if(exp->_nodes[i].type>SQ_MAX_CHAR)\n                    printf(\"[%02d] %10s \", (SQInt32)i,g_nnames[exp->_nodes[i].type-SQ_MAX_CHAR]);\n                else\n                    printf(\"[%02d] %10c \", (SQInt32)i,exp->_nodes[i].type);\n                printf(\"left %02d right %02d next %02d\\n\", (SQInt32)exp->_nodes[i].left, (SQInt32)exp->_nodes[i].right, (SQInt32)exp->_nodes[i].next);\n            }\n            printf(\"\\n\");\n        }\n#endif\n        exp->_matches = (SQRexMatch *) sq_malloc(alloc_ctx, exp->_nsubexpr * sizeof(SQRexMatch));\n        memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));\n    }\n    else{\n        sqstd_rex_free(exp);\n        return NULL;\n    }\n    return exp;\n}\n\nvoid sqstd_rex_free(SQRex *exp)\n{\n    if(exp) {\n        if(exp->_nodes) sq_free(exp->_alloc_ctx, exp->_nodes,exp->_nallocated * sizeof(SQRexNode));\n        if(exp->_jmpbuf) sq_free(exp->_alloc_ctx, exp->_jmpbuf,sizeof(jmp_buf));\n        if(exp->_matches) sq_free(exp->_alloc_ctx, exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));\n        sq_free(exp->_alloc_ctx, exp, sizeof(SQRex));\n    }\n}\n\nSQBool sqstd_rex_match(SQRex* exp,const char* text)\n{\n    const char* res = NULL;\n    exp->_bol = text;\n    exp->_eol = text + strlen(text);\n    exp->_currsubexp = 0;\n    res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL);\n    if(res == NULL || res != exp->_eol)\n        return SQFalse;\n    return SQTrue;\n}\n\nSQBool sqstd_rex_searchrange(SQRex* exp,const char* text_begin,const char* text_end,const char** out_begin, const char** out_end)\n{\n    const char *cur = NULL;\n    SQInteger node;\n    if(text_begin >= text_end) return SQFalse;\n    exp->_bol = text_begin;\n    exp->_eol = text_end;\n    do {\n        node = exp->_first;\n        cur = text_begin;\n        while(node != -1) {\n            exp->_currsubexp = 0;\n            cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL);\n            if(!cur)\n                break;\n            node = exp->_nodes[node].next;\n        }\n        text_begin++;\n    } while(cur == NULL && text_begin != text_end);\n\n    if(cur == NULL)\n        return SQFalse;\n\n    --text_begin;\n\n    if(out_begin) *out_begin = text_begin;\n    if(out_end) *out_end = cur;\n    return SQTrue;\n}\n\nSQBool sqstd_rex_search(SQRex* exp,const char* text, const char** out_begin, const char** out_end)\n{\n    return sqstd_rex_searchrange(exp,text,text + strlen(text),out_begin,out_end);\n}\n\nSQInteger sqstd_rex_getsubexpcount(SQRex* exp)\n{\n    return exp->_nsubexpr;\n}\n\nSQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)\n{\n    if( n<0 || n >= exp->_nsubexpr) return SQFalse;\n    *subexp = exp->_matches[n];\n    return SQTrue;\n}\n\n"
  },
  {
    "path": "sqstdlib/sqstdserialization.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel/sqpcheader.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <sqstdblob.h>\n#include <squirrel/sqvm.h>\n#include <squirrel/sqstate.h>\n#include <squirrel/sqfuncproto.h>\n#include <squirrel/sqclosure.h>\n#include <squirrel/sqtable.h>\n#include <squirrel/sqclass.h>\n#include <squirrel/sqarray.h>\n#include <squirrel/sqvm.h>\n#include \"sqstdstream.h\"\n#include \"sqstdblobimpl.h\"\n#include <unordered_map>\n#include <vector>\n\n#define STDLIB std\n\n#define SQ_DESER_MAX_OBJECT_SIZE (80 * 1024 * 1024)\n\nstruct SQStreamSerializer {\n    enum DataType {\n        TP_NULL = 0 << 4,\n        TP_BOOL = 1 << 4,\n        TP_INTEGER = 2 << 4,\n        TP_FLOAT = 3 << 4,\n        TP_STRING = 4 << 4,\n        TP_ARRAY = 5 << 4,\n        TP_TABLE = 6 << 4,\n        TP_INSTANCE = 7 << 4,\n    };\n\n    enum {\n        START_MARKER = 0xEA,\n        END_MARKER = 0xFA,\n        MAX_DEPTH = 200,\n    };\n\n    struct ClassDesc {\n        int index; // -1 if not serialized yet\n        const char *className;\n    };\n\n    HSQUIRRELVM vm;\n    SQStream *stream;\n    const char *errorString;\n    STDLIB::unordered_map<char *, uint32_t> stringTable; // string -> index mapping\n    STDLIB::vector<SQObjectPtr> stringList; // to keep track of strings\n    STDLIB::unordered_map<SQClass *, ClassDesc> classTable;\n    STDLIB::vector<SQObjectPtr> classList; // to keep track of classes\n    SQObjectPtr availableClasses; // null or a table of available classes (class_name -> class)\n    SQObjectPtr getstateProcName;\n    SQObjectPtr setstateProcName;\n    uint32_t stringCounter;\n    uint32_t classCounter;\n    uint32_t depth;\n\n    SQStreamSerializer() : vm(nullptr), stream(nullptr), errorString(nullptr), stringCounter(0), depth(0),\n        classCounter(0) {}\n\n    int getCountOfParams(SQObjectPtr obj) {\n        if (sq_isclosure(obj))\n            return _closure(obj)->_function->_nparameters;\n        else if (sq_isnativeclosure(obj))\n            return _nativeclosure(obj)->_nparamscheck;\n        else\n            return -1;\n    }\n\n    bool fillAvailableClassNamesOnDemand() {\n        if (!classTable.empty())\n            return true;\n\n        if (sq_isnull(availableClasses))\n            return true;\n\n        if (!sq_istable(availableClasses)) {\n            errorString = \"Available classes must be a table (class_name -> class)\";\n            return false;\n        }\n\n        SQTable *tbl = _table(availableClasses);\n        SQTable::_HashNode *node = tbl->_nodes;\n        uint32_t count = tbl->_numofnodes_minus_one + 1;\n\n        for (uint32_t i = 0; i < count; ++i) {\n            SQObjectPtr key = node[i].key;\n            if (!sq_isstring(key))\n                continue;\n\n            SQObjectPtr value = node[i].val;\n            if (!sq_isclass(value))\n                continue;\n\n            const char *className = _stringval(key);\n            SQClass *cls = _class(value);\n            classTable[cls] = { -1, className };\n        }\n\n        getstateProcName = SQString::Create(_ss(vm), \"__getstate\");\n        setstateProcName = SQString::Create(_ss(vm), \"__setstate\");\n        return true;\n    }\n\n    bool serializeObject(const SQObject &obj) {\n        if (sq_isnull(obj)) {\n            uint8_t v = TP_NULL | 1;\n            stream->Write(&v, sizeof(v));\n        }\n        else if (sq_isbool(obj)) {\n            uint8_t v = TP_BOOL | (_integer(obj) ? 1 : 0);\n            stream->Write(&v, sizeof(v));\n        }\n        else if (sq_isinteger(obj)) {\n            uint8_t v = TP_INTEGER;\n            SQInteger iv = _integer(obj);\n            if (iv >= -1 && iv <= 2) {\n                v |= iv + 1; // map -1, 0, 1, 2 to 0, 1, 2, 3\n                stream->Write(&v, sizeof(v));\n            }\n            else if (iv >= INT8_MIN && iv <= INT8_MAX) {\n                v |= 4; // 4 for 1-byte integer\n                stream->Write(&v, sizeof(v));\n                int8_t iv8 = static_cast<int8_t>(iv);\n                stream->Write(&iv8, sizeof(int8_t));\n            }\n            else if (iv >= INT16_MIN && iv <= INT16_MAX) {\n                v |= 5; // 5 for 2-byte integer\n                stream->Write(&v, sizeof(v));\n                int16_t iv16 = static_cast<int16_t>(iv);\n                stream->Write(&iv16, sizeof(int16_t));\n            }\n            else if (iv >= INT32_MIN && iv <= INT32_MAX) {\n                v |= 6; // 6 for 4-byte integer\n                stream->Write(&v, sizeof(v));\n                int32_t iv32 = static_cast<int32_t>(iv);\n                stream->Write(&iv, sizeof(int32_t));\n            }\n            else {\n                v |= 7; // 7 for 8-byte integer\n                stream->Write(&v, sizeof(v));\n                int64_t iv64 = static_cast<int64_t>(iv);\n                stream->Write(&iv64, sizeof(int64_t));\n            }\n        }\n        else if (sq_isfloat(obj)) {\n            uint8_t v = TP_FLOAT;\n            SQFloat fv = _float(obj);\n            if (fv == SQFloat(-1.0)) {\n                v |= 0; // -1.0\n                stream->Write(&v, sizeof(v));\n            }\n            else if (fv == SQFloat(-0.5)) {\n                v |= 1; // -0.5\n                stream->Write(&v, sizeof(v));\n            }\n            else if (fv == SQFloat(0.0)) {\n                v |= 2; // 0.0\n                stream->Write(&v, sizeof(v));\n            }\n            else if (fv == SQFloat(0.5)) {\n                v |= 3; // 0.5\n                stream->Write(&v, sizeof(v));\n            }\n            else if (fv == SQFloat(1.0)) {\n                v |= 4; // 1.0\n                stream->Write(&v, sizeof(v));\n            }\n            else if (fv == SQFloat(2.0)) {\n                v |= 5; // 2.0\n                stream->Write(&v, sizeof(v));\n            }\n            else {\n            #ifdef SQUSEDOUBLE\n                v |= 7; // 8-byte float\n                stream->Write(&v, sizeof(v));\n                double dfv = static_cast<double>(fv);\n                stream->Write(&dfv, sizeof(double));\n            #else\n                v |= 6; // 4-byte float\n                stream->Write(&v, sizeof(v));\n                float ffv = static_cast<float>(fv);\n                stream->Write(&ffv, sizeof(float));\n            #endif\n            }\n        }\n        else if (sq_isstring(obj)) {\n            uint8_t v = TP_STRING;\n            SQInteger len = _string(obj)->_len;\n            if (len == 0) {\n                v |= 0; // empty string\n                stream->Write(&v, sizeof(v));\n            }\n            else {\n                // check if the string is new or already in the table\n                char *str = _stringval(obj);\n                auto it = stringTable.find(str);\n                if (it == stringTable.end()) {\n                    if (len <= UINT8_MAX) {\n                        v |= 1; // 1-byte string\n                        stream->Write(&v, sizeof(v));\n                        uint8_t index = static_cast<uint8_t>(len);\n                        stream->Write(&index, sizeof(uint8_t));\n                        stream->Write(str, len * sizeof(char));\n                    }\n                    else if (len <= UINT16_MAX) {\n                        v |= 2; // 2-byte string\n                        stream->Write(&v, sizeof(v));\n                        uint16_t index = static_cast<uint16_t>(len);\n                        stream->Write(&index, sizeof(uint16_t));\n                        stream->Write(str, len * sizeof(char));\n                    }\n                    else {\n                        v |= 3; // 4-byte string\n                        stream->Write(&v, sizeof(v));\n                        uint32_t index = static_cast<uint32_t>(len);\n                        stream->Write(&index, sizeof(uint32_t));\n                        stream->Write(str, len * sizeof(char));\n                    }\n\n                    stringTable[str] = stringCounter++;\n                }\n                else {\n                    uint32_t index = it->second;\n                    if (index <= UINT8_MAX) {\n                        v |= 4; // 1-byte index\n                        stream->Write(&v, sizeof(v));\n                        uint8_t idx = static_cast<uint8_t>(index);\n                        stream->Write(&idx, sizeof(uint8_t));\n                    }\n                    else if (index <= UINT16_MAX) {\n                        v |= 5; // 2-byte index\n                        stream->Write(&v, sizeof(v));\n                        uint16_t idx = static_cast<uint16_t>(index);\n                        stream->Write(&idx, sizeof(uint16_t));\n                    }\n                    else {\n                        v |= 6; // 4-byte index\n                        stream->Write(&v, sizeof(v));\n                        uint32_t idx = static_cast<uint32_t>(index);\n                        stream->Write(&idx, sizeof(uint32_t));\n                    }\n                }\n            }\n        }\n        else if (sq_isarray(obj)) {\n            depth++;\n            if (depth > MAX_DEPTH) {\n                errorString = \"Maximum serialization depth exceeded\";\n                return false;\n            }\n\n            uint8_t v = TP_ARRAY;\n            SQArray *arr = _array(obj);\n            SQInteger size = arr->Size();\n\n            if (size == 0) {\n                v |= 0; // empty array\n                stream->Write(&v, sizeof(v));\n            }\n            else if (size <= UINT8_MAX) {\n                v |= 1; // 1-byte size\n                stream->Write(&v, sizeof(v));\n                uint8_t size8 = static_cast<uint8_t>(size);\n                stream->Write(&size8, sizeof(uint8_t));\n            }\n            else {\n                v |= 2; // 4-byte size\n                stream->Write(&v, sizeof(v));\n                uint32_t size32 = static_cast<uint32_t>(size);\n                stream->Write(&size32, sizeof(uint32_t));\n            }\n\n            for (SQInteger i = 0; i < size; ++i)\n                if (!serializeObject(arr->_values[i]))\n                    return false;\n\n            depth--;\n        }\n        else if (sq_istable(obj)) {\n            depth++;\n            if (depth > MAX_DEPTH) {\n                errorString = \"Maximum serialization depth exceeded\";\n                return false;\n            }\n\n            uint8_t v = TP_TABLE;\n            SQTable *tbl = _table(obj);\n            SQInteger size = tbl->CountUsed();\n\n            if (size == 0) {\n                v |= 0; // empty table\n                stream->Write(&v, sizeof(v));\n            }\n            else if (size <= UINT8_MAX) {\n                v |= 1; // 1-byte size\n                stream->Write(&v, sizeof(v));\n                uint8_t size8 = static_cast<uint8_t>(size);\n                stream->Write(&size8, sizeof(uint8_t));\n            }\n            else {\n                v |= 2; // 4-byte size\n                stream->Write(&v, sizeof(v));\n                uint32_t size32 = static_cast<uint32_t>(size);\n                stream->Write(&size32, sizeof(uint32_t));\n            }\n\n            SQTable::_HashNode *node = tbl->_nodes;\n            uint32_t count = tbl->_numofnodes_minus_one + 1;\n\n            for (uint32_t i = 0; i < count; ++i) {\n                if (sq_type(node[i].key) & OT_FREE_TABLE_SLOT)\n                    continue;\n                if (!serializeObject(node[i].key))\n                    return false;\n                if (!serializeObject(node[i].val))\n                    return false;\n            }\n\n            depth--;\n        }\n        else if (sq_isinstance(obj)) {\n            depth++;\n            if (depth > MAX_DEPTH) {\n                errorString = \"Maximum serialization depth exceeded\";\n                return false;\n            }\n\n            SQClass *cls = _instance(obj)->_class;\n            if (!fillAvailableClassNamesOnDemand())\n                return false;\n\n            auto it = classTable.find(cls);\n            if (it == classTable.end()) {\n                errorString = \"Unsupported class for serialization\";\n                return false;\n            }\n\n            SQObjectPtr closure;\n            if (_instance(obj)->Get(getstateProcName, closure)) {\n                if (!sq_isclosure(closure) && !sq_isnativeclosure(closure)) {\n                    errorString = \"Instance method __getstate must be a closure\";\n                    return false;\n                }\n            }\n            else {\n                errorString = \"Instance must have __getstate method for serialization\";\n                return false;\n            }\n\n            ClassDesc &classDesc = it->second;\n\n            if (classDesc.index == -1) {\n                // New class, write class name\n                int classNameLen = strlen(classDesc.className);\n                if (classNameLen > UINT8_MAX) {\n                    errorString = \"Class name too long for serialization\";\n                    return false;\n                }\n\n                uint8_t classNameLen8 = static_cast<uint8_t>(classNameLen);\n                uint8_t v = TP_INSTANCE | 0x0F; // 0x0F indicates a new class\n                stream->Write(&v, sizeof(v));\n                stream->Write(&classNameLen8, sizeof(classNameLen8));\n                stream->Write(classDesc.className, classNameLen * sizeof(char));\n\n                classDesc.index = classCounter++;\n\n                if (classCounter >= 0x0EFF) {\n                    errorString = \"Too many different classes for serialization\";\n                    return false;\n                }\n            }\n            else {\n                // existing class, write index\n                assert(classDesc.index >= 0 && classDesc.index < 0x0EFF);\n                uint8_t v = TP_INSTANCE | (0x0F & (classDesc.index >> 8));\n                uint8_t restOfIndex = static_cast<uint8_t>(classDesc.index & 0xFF);\n                stream->Write(&v, sizeof(v));\n                stream->Write(&restOfIndex, sizeof(restOfIndex));\n            }\n\n            SQInteger referenceStackTop = sq_gettop(vm);\n\n\n            int countOfParams = getCountOfParams(closure);\n\n            sq_pushobject(vm, closure);\n            sq_pushobject(vm, obj); // this\n            if (countOfParams > 1)\n                sq_pushobject(vm, availableClasses);\n            SQInteger top = sq_gettop(vm);\n            SQRESULT res = sq_call(vm, countOfParams > 1 ? 2 : 1, SQTrue, SQTrue);\n            if (SQ_FAILED(res)) {\n                errorString = \"Failed to call __getstate method\";\n                sq_pop(vm, countOfParams > 1 ? 2 : 1); // pop arguments\n                return false;\n            }\n\n            SQObject state;\n            sq_getstackobj(vm, -1, &state);\n\n            if (!serializeObject(state))\n                return false;\n\n            sq_pop(vm, 2);\n\n            SQInteger newTop = sq_gettop(vm);\n            if (newTop != referenceStackTop) {\n                assert(!\"Unexpected stack size after __getstate call\");\n                errorString = \"Unexpected stack size after __getstate call\";\n                return false;\n            }\n\n            depth--;\n            return true;\n        }\n        else {\n            errorString = \"Unsupported object type for serialization\";\n            return false;\n        }\n\n        return true;\n    }\n\n    SQRESULT serialize(HSQUIRRELVM vm_, SQStream *dest_, SQObjectPtr obj, SQObjectPtr available_classes) {\n        vm = vm_;\n        stream = dest_;\n        errorString = nullptr;\n        stringCounter = 0;\n        classCounter = 0;\n        stringTable.clear();\n        classTable.clear();\n        stringList.clear();\n        classList.clear();\n        availableClasses = available_classes;\n        depth = 0;\n\n        uint8_t startMarker = START_MARKER;\n        stream->Write(&startMarker, sizeof(startMarker));\n\n        if (!serializeObject(obj))\n            return sq_throwerror(vm, errorString ? errorString : \"Serialization failed\");\n\n        uint8_t endMarker = END_MARKER;\n        stream->Write(&endMarker, sizeof(endMarker));\n        return SQ_OK;\n    }\n\n    bool unexpectedEndOfData()\n    {\n        errorString = \"Unexpected end of data during deserialization\";\n        return false;\n    }\n\n    bool deserializeObject()\n    {\n        uint8_t t = 0;\n        if (stream->Read(&t, sizeof(t)) != sizeof(t))\n            return unexpectedEndOfData();\n\n        unsigned v = t & 0x0F;\n\n        switch (t & 0xF0) {\n            case TP_NULL:\n                assert(v == 1);\n                sq_pushnull(vm);\n                return true;\n\n            case TP_BOOL: {\n                assert(v <= 1);\n                sq_pushbool(vm, v);\n                return true;\n            }\n\n            case TP_INTEGER: {\n                switch (v) {\n                    case 0: sq_pushinteger(vm, -1); return true;\n                    case 1: sq_pushinteger(vm, 0); return true;\n                    case 2: sq_pushinteger(vm, 1); return true;\n                    case 3: sq_pushinteger(vm, 2); return true;\n                    case 4: {\n                        int8_t iv8 = 0;\n                        if (stream->Read(&iv8, sizeof(iv8)) != sizeof(iv8))\n                            return unexpectedEndOfData();\n                        sq_pushinteger(vm, iv8);\n                        return true;\n                    }\n                    case 5: {\n                        int16_t iv16 = 0;\n                        if (stream->Read(&iv16, sizeof(iv16)) != sizeof(iv16))\n                            return unexpectedEndOfData();\n                        sq_pushinteger(vm, iv16);\n                        return true;\n                    }\n                    case 6: {\n                        int32_t iv32 = 0;\n                        if (stream->Read(&iv32, sizeof(iv32)) != sizeof(iv32))\n                            return unexpectedEndOfData();\n                        sq_pushinteger(vm, iv32);\n                        return true;\n                    }\n                    case 7: {\n                        int64_t iv64 = 0;\n                        if (stream->Read(&iv64, sizeof(iv64)) != sizeof(iv64))\n                            return unexpectedEndOfData();\n                        sq_pushinteger(vm, iv64);\n                        return true;\n                    }\n                    default:\n                        errorString = \"Invalid integer type during deserialization\";\n                        return false;\n                }\n                break;\n            }\n\n            case TP_FLOAT: {\n                switch (v) {\n                    case 0: sq_pushfloat(vm, -1.0f); return true;\n                    case 1: sq_pushfloat(vm, -0.5f); return true;\n                    case 2: sq_pushfloat(vm, 0.0f); return true;\n                    case 3: sq_pushfloat(vm, 0.5f); return true;\n                    case 4: sq_pushfloat(vm, 1.0f); return true;\n                    case 5: sq_pushfloat(vm, 2.0f); return true;\n                    case 6: {\n                        float ffv = 0.0f;\n                        if (stream->Read(&ffv, sizeof(ffv)) != sizeof(ffv))\n                            return unexpectedEndOfData();\n                        sq_pushfloat(vm, static_cast<SQFloat>(ffv));\n                        return true;\n                    }\n                    case 7: {\n                        double dfv = 0.0;\n                        if (stream->Read(&dfv, sizeof(dfv)) != sizeof(dfv))\n                            return unexpectedEndOfData();\n                        sq_pushfloat(vm, static_cast<SQFloat>(dfv));\n                        return true;\n                    }\n                    default:\n                        errorString = \"Invalid float type during deserialization\";\n                        return false;\n                }\n                break;\n            }\n\n            case TP_STRING: {\n                uint32_t len = 0;\n                const char *data = nullptr;\n\n                if (v < 4) {\n                    switch (v) {\n                        case 0: sq_pushstring(vm, \"\", 0); return true; // Empty string\n                        case 1: {\n                            uint8_t len8 = 0;\n                            if (stream->Read(&len8, sizeof(len8)) != sizeof(len8))\n                                return unexpectedEndOfData();\n                            len = static_cast<uint32_t>(len8);\n                        }\n                        break;\n                        case 2: {\n                            uint16_t len16 = 0;\n                            if (stream->Read(&len16, sizeof(len16)) != sizeof(len16))\n                                return unexpectedEndOfData();\n                            len = static_cast<uint32_t>(len16);\n                        }\n                        break;\n                        case 3: {\n                            uint32_t len32 = 0;\n                            if (stream->Read(&len32, sizeof(len32)) != sizeof(len32))\n                                return unexpectedEndOfData();\n                            len = len32;\n                        }\n                        break;\n                    }\n                    if (len >= SQ_DESER_MAX_OBJECT_SIZE) {\n                        errorString = \"String too large during deserialization\";\n                        return false;\n                    }\n                    data = sq_getscratchpad(vm, len * sizeof(char));\n                    if (stream->Read((void *)data, len * sizeof(char)) != len * sizeof(char))\n                        return unexpectedEndOfData();\n\n                    SQObjectPtr s(SQString::Create(_ss(vm), data, len));\n                    stringList.push_back(s);\n                    vm->Push(s);\n\n                    return true;\n                }\n                else // v >= 4\n                {\n                    uint32_t index = 0;\n                    if (v == 4) {\n                        uint8_t idx8 = 0;\n                        if (stream->Read(&idx8, sizeof(idx8)) != sizeof(idx8))\n                            return unexpectedEndOfData();\n                        index = static_cast<uint32_t>(idx8);\n                    }\n                    else if (v == 5) {\n                        uint16_t idx16 = 0;\n                        if (stream->Read(&idx16, sizeof(idx16)) != sizeof(idx16))\n                            return unexpectedEndOfData();\n                        index = static_cast<uint32_t>(idx16);\n                    }\n                    else if (v == 6) {\n                        if (stream->Read(&index, sizeof(index)) != sizeof(index))\n                            return unexpectedEndOfData();\n                    }\n                    else {\n                        errorString = \"Invalid string type during deserialization\";\n                        return false;\n                    }\n\n                    if (index >= stringList.size()) {\n                        errorString = \"String index out of bounds during deserialization\";\n                        return false;\n                    }\n\n                    vm->Push(stringList[index]);\n                    return true;\n                }\n            }\n\n            case TP_ARRAY: {\n                uint32_t size = 0;\n                if (v == 0) {\n                    sq_newarray(vm, 0); // empty array\n                    return true;\n                }\n                else if (v == 1) {\n                    uint8_t size8 = 0;\n                    if (stream->Read(&size8, sizeof(size8)) != sizeof(size8))\n                        return unexpectedEndOfData();\n                    size = static_cast<uint32_t>(size8);\n                }\n                else if (v == 2) {\n                    uint32_t size32 = 0;\n                    if (stream->Read(&size32, sizeof(size32)) != sizeof(size32))\n                        return unexpectedEndOfData();\n                    size = size32;\n                }\n                else {\n                    errorString = \"Invalid array type during deserialization\";\n                    return false;\n                }\n\n                if (size >= SQ_DESER_MAX_OBJECT_SIZE) {\n                    errorString = \"Array too large during deserialization\";\n                    return false;\n                }\n\n                sq_newarray(vm, size);\n                for (uint32_t i = 0; i < size; ++i) {\n                    sq_pushinteger(vm, i);\n                    if (!deserializeObject()) {\n                        sq_pop(vm, 2);\n                        return false;\n                    }\n                    sq_rawset(vm, -3);\n                }\n                return true;\n            }\n\n            case TP_TABLE: {\n                uint32_t size = 0;\n                if (v == 0) {\n                    sq_newtable(vm); // empty table\n                    return true;\n                }\n                else if (v == 1) {\n                    uint8_t size8 = 0;\n                    if (stream->Read(&size8, sizeof(size8)) != sizeof(size8))\n                        return unexpectedEndOfData();\n                    size = static_cast<uint32_t>(size8);\n                }\n                else if (v == 2) {\n                    uint32_t size32 = 0;\n                    if (stream->Read(&size32, sizeof(size32)) != sizeof(size32))\n                        return unexpectedEndOfData();\n                    size = size32;\n                }\n                else {\n                    errorString = \"Invalid table type during deserialization\";\n                    return false;\n                }\n\n                if (size >= SQ_DESER_MAX_OBJECT_SIZE) {\n                    errorString = \"Table too large during deserialization\";\n                    return false;\n                }\n\n                sq_newtableex(vm, size);\n                for (uint32_t i = 0; i < size; ++i) {\n                    if (!deserializeObject()) { // key\n                        sq_pop(vm, 1);\n                        return false;\n                    }\n\n                    if (!deserializeObject()) { // value\n                        sq_pop(vm, 2);\n                        return false;\n                    }\n\n                    sq_rawset(vm, -3);\n                }\n                return true;\n            }\n\n            case TP_INSTANCE: {\n                fillAvailableClassNamesOnDemand();\n                uint32_t index = 0;\n                if (v == 0x0F) {\n                    // New class, read class name\n                    uint8_t classNameLen8 = 0;\n                    if (stream->Read(&classNameLen8, sizeof(classNameLen8)) != sizeof(classNameLen8))\n                        return unexpectedEndOfData();\n                    uint32_t classNameLen = static_cast<uint32_t>(classNameLen8);\n                    char *className = sq_getscratchpad(vm, classNameLen * sizeof(char));\n                    if (stream->Read(className, classNameLen * sizeof(char)) != classNameLen * sizeof(char))\n                        return unexpectedEndOfData();\n\n                    SQString *classNameStr = SQString::Create(_ss(vm), className, classNameLen);\n\n                    if (!sq_istable(availableClasses)) {\n                        errorString = \"Instance found during deserialization, but available classes not set or not a table\";\n                        return false;\n                    }\n\n                    SQTable *tbl = _table(availableClasses);\n                    SQObjectPtr classObj;\n                    if (!tbl->Get(SQObjectPtr(classNameStr), classObj)) {\n                        errorString = \"Class not found in available classes during deserialization\";\n                        return false;\n                    }\n\n                    assert(sq_isclass(classObj)); // must be already checked in fillAvailableClassNamesOnDemand()\n\n                    classList.push_back(classObj);\n                    index = classList.size() - 1;\n\n                    // check number of arguments required by the class constructor (must accept 1 argument - the instance itself)\n                    SQObjectPtr constructor;\n                    if (_class(classObj)->GetConstructor(constructor)) {\n                      if (!isClassConstructorValid(constructor))\n                        return false;\n                    }\n                }\n                else {\n                    uint8_t restOfIndex = 0;\n                    if (stream->Read(&restOfIndex, sizeof(restOfIndex)) != sizeof(restOfIndex))\n                        return unexpectedEndOfData();\n                    index = ((v & 0x0F) << 8) | static_cast<uint32_t>(restOfIndex);\n                    if (index >= classList.size()) {\n                        errorString = \"Class index out of bounds during deserialization\";\n                        return false;\n                    }\n                }\n\n                SQObjectPtr classObj = classList[index];\n\n                SQObjectPtr setStateClosure;\n                if (_class(classObj)->Get(setstateProcName, setStateClosure)) {\n                    if (!sq_isclosure(setStateClosure) && !sq_isnativeclosure(setStateClosure)) {\n                        errorString = \"Class method __setstate must be a closure\";\n                        return false;\n                    }\n                }\n                else {\n                    errorString = \"Class must have __setstate method for deserialization\";\n                    return false;\n                }\n\n                // create instance\n\n                SQInteger stackbase = sq_gettop(vm);\n\n                sq_pushobject(vm, classObj);\n                sq_pushnull(vm); // environment\n                if (SQ_FAILED(sq_call(vm, 1, SQTrue, SQTrue))) {\n                    errorString = \"Failed to instantiate class during deserialization\";\n                    sq_settop(vm, stackbase);\n                    return false;\n                }\n\n                sq_remove(vm, -2); // remove class from stack, instance stays on stack\n\n                sq_pushobject(vm, setStateClosure);\n                sq_push(vm, -2); // instance\n\n                if (!deserializeObject()) {\n                    sq_pop(vm, 2);\n                    return false;\n                }\n\n                int countOfSetStateParams = getCountOfParams(setStateClosure);\n                if (countOfSetStateParams > 2)\n                    sq_pushobject(vm, availableClasses);\n\n                SQInteger top = sq_gettop(vm);\n                SQRESULT res = sq_call(vm, countOfSetStateParams > 2 ? 3 : 2, SQTrue, SQTrue);\n                if (SQ_FAILED(res)) {\n                    errorString = \"Failed to call __setstate method\";\n                    sq_settop(vm, stackbase); // restore stack\n                    return false;\n                }\n\n                sq_settop(vm, stackbase + 1); // instance is left on the stack\n                return true;\n            }\n\n            default:\n                errorString = \"Unsupported object type during deserialization\";\n                return false;\n        }\n    }\n\n    bool isClassConstructorValid(SQObjectPtr &constructor)\n    {\n      if (sq_isclosure(constructor))\n      {\n        SQFunctionProto *func = _closure(constructor)->_function;\n        SQInteger paramssize = func->_nparameters;\n        SQInteger ndef = func->_ndefaultparams;\n        SQInteger nargs = 1;\n        if (func->_varparams)\n          paramssize--;\n\n        if (paramssize != nargs && !(ndef && nargs < paramssize && (paramssize - nargs) <= ndef))\n        {\n          errorString = \"Class constructor must accept call with all default arguments during deserialization\";\n          return false;\n        }\n        return true;\n      }\n      else if (sq_isnativeclosure(constructor))\n      {\n        SQNativeClosure *nativeClosure = _nativeclosure(constructor);\n        if (nativeClosure->_nparamscheck > 1)\n        {\n          errorString = \"Class constructor must accept call with all default arguments during deserialization\";\n          return false;\n        }\n        return true;\n      }\n\n      errorString = \"Class constructor must be a closure or native closure during deserialization\";\n      return false;\n    }\n\n    SQRESULT deserialize(HSQUIRRELVM vm_, SQStream *src_, SQObjectPtr available_classes) {  // parsed value is left on the stack\n        vm = vm_;\n        stream = src_;\n        errorString = nullptr;\n        stringCounter = 0;\n        classCounter = 0;\n        stringTable.clear();\n        classTable.clear();\n        stringList.clear();\n        classList.clear();\n        availableClasses = available_classes;\n        depth = 0;\n\n        uint8_t startMarker = 0;\n        if (stream->Read(&startMarker, sizeof(startMarker)) != sizeof(startMarker))\n            return sq_throwerror(vm, \"Unexpected end of data during deserialization\");\n        if (startMarker != START_MARKER)\n            return sq_throwerror(vm, \"Invalid start marker during deserialization\");\n\n        if (!deserializeObject())\n            return sq_throwerror(vm, errorString ? errorString : \"Deserialization failed\");\n\n        uint8_t endMarker = 0;\n        if (stream->Read(&endMarker, sizeof(endMarker)) != sizeof(endMarker))\n            return sq_throwerror(vm, \"Unexpected end of data during deserialization\");\n        if (endMarker != END_MARKER)\n            return sq_throwerror(vm, \"Invalid end marker during deserialization\");\n\n        return SQ_OK;\n    }\n};\n\n\nSQRESULT sqstd_serialize_object_to_stream(HSQUIRRELVM vm, SQStream *dest, SQObjectPtr obj, SQObjectPtr available_classes) {\n    SQStreamSerializer serializer;\n    return serializer.serialize(vm, dest, obj, available_classes);\n}\n\nSQRESULT sqstd_deserialize_object_from_stream(HSQUIRRELVM vm, SQStream *src, SQObjectPtr available_classes) {\n    int prevTop = sq_gettop(vm);\n    SQStreamSerializer serializer;\n    SQRESULT res = serializer.deserialize(vm, src, available_classes);\n    sq_settop(vm, prevTop + 1);\n    return res;\n}\n\n"
  },
  {
    "path": "sqstdlib/sqstdserialization.h",
    "content": "/*  see copyright notice in squirrel.h */\n#pragma once\n#include <squirrel/sqpcheader.h>\n\nSQRESULT sqstd_serialize_object_to_stream(HSQUIRRELVM vm, SQStream *dest, SQObjectPtr obj, SQObjectPtr available_classes);\nSQRESULT sqstd_deserialize_object_from_stream(HSQUIRRELVM vm, SQStream *src, SQObjectPtr available_classes);\n"
  },
  {
    "path": "sqstdlib/sqstdstream.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel/sqpcheader.h>\n#include <new>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <squirrel.h>\n#include <sqstdio.h>\n#include <sqstdblob.h>\n#include \"sqstdstream.h\"\n#include \"sqstdblobimpl.h\"\n#include \"sqstdserialization.h\"\n#include <squirrel/sqvm.h>\n\n#define SETUP_STREAM(v) \\\n    SQStream *self = NULL; \\\n    if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)))) \\\n        return sq_throwerror(v,\"invalid type tag\"); \\\n    if(!self || !self->IsValid())  \\\n        return sq_throwerror(v,\"the stream is invalid\");\n\nSQInteger _stream_readblob(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQUserPointer data,blobp;\n    SQInteger size,res;\n    sq_getinteger(v,2,&size);\n    if(size > self->Len()) {\n        size = self->Len();\n    }\n    data = sq_getscratchpad(v,size);\n    res = self->Read(data,size);\n    if(res <= 0)\n        return sq_throwerror(v,\"no data left to read\");\n    blobp = sqstd_createblob(v,res);\n    memcpy(blobp,data,res);\n    return 1;\n}\n\n#define SAFE_READN(ptr,len) { \\\n    if(self->Read(ptr,len) != len) return sq_throwerror(v,\"io error\"); \\\n    }\nSQInteger _stream_readn(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQInteger format;\n    sq_getinteger(v, 2, &format);\n    switch(format) {\n    case 'l': {\n        SQInteger i;\n        SAFE_READN(&i, sizeof(i));\n        sq_pushinteger(v, i);\n              }\n        break;\n    case 'i': {\n        SQInt32 i;\n        SAFE_READN(&i, sizeof(i));\n        sq_pushinteger(v, i);\n              }\n        break;\n    case 's': {\n        short s;\n        SAFE_READN(&s, sizeof(short));\n        sq_pushinteger(v, s);\n              }\n        break;\n    case 'w': {\n        unsigned short w;\n        SAFE_READN(&w, sizeof(unsigned short));\n        sq_pushinteger(v, w);\n              }\n        break;\n    case 'c': {\n        signed char c;\n        SAFE_READN(&c, sizeof(signed char));\n        sq_pushinteger(v, c);\n              }\n        break;\n    case 'b': {\n        unsigned char c;\n        SAFE_READN(&c, sizeof(unsigned char));\n        sq_pushinteger(v, c);\n              }\n        break;\n    case 'f': {\n        float f;\n        SAFE_READN(&f, sizeof(float));\n        sq_pushfloat(v, f);\n              }\n        break;\n    case 'd': {\n        double d;\n        SAFE_READN(&d, sizeof(double));\n        sq_pushfloat(v, (SQFloat)d);\n              }\n        break;\n    default:\n        return sq_throwerror(v, \"invalid format\");\n    }\n    return 1;\n}\n\nSQInteger _stream_writeblob(HSQUIRRELVM v)\n{\n    SQUserPointer data;\n    SQInteger size;\n    SETUP_STREAM(v);\n    if(SQ_FAILED(sqstd_getblob(v,2,&data)))\n        return sq_throwerror(v,\"invalid parameter\");\n    size = sqstd_getblobsize(v,2);\n    if(self->Write(data,size) != size)\n        return sq_throwerror(v,\"io error\");\n    sq_pushinteger(v,size);\n    return 1;\n}\n\nSQInteger _stream_writestring(HSQUIRRELVM v)\n{\n    const char * str;\n    SQInteger len;\n    SETUP_STREAM(v);\n    if (SQ_FAILED(sq_getstringandsize(v, 2, &str, &len)))\n        return sq_throwerror(v, \"invalid parameter\");\n\n    SQInteger size = len * sizeof(char);\n    if (self->Write((void *)str, size) != size)\n        return sq_throwerror(v,\"io error\");\n    sq_pushinteger(v, len);\n    return 1;\n}\n\nSQInteger _stream_writen(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQInteger format, ti;\n    SQFloat tf;\n    sq_getinteger(v, 3, &format);\n    switch(format) {\n    case 'l': {\n        SQInteger i;\n        sq_getinteger(v, 2, &ti);\n        i = ti;\n        self->Write(&i, sizeof(SQInteger));\n              }\n        break;\n    case 'i': {\n        SQInt32 i;\n        sq_getinteger(v, 2, &ti);\n        i = (SQInt32)ti;\n        self->Write(&i, sizeof(SQInt32));\n              }\n        break;\n    case 's': {\n        short s;\n        sq_getinteger(v, 2, &ti);\n        s = (short)ti;\n        self->Write(&s, sizeof(short));\n              }\n        break;\n    case 'w': {\n        unsigned short w;\n        sq_getinteger(v, 2, &ti);\n        w = (unsigned short)ti;\n        self->Write(&w, sizeof(unsigned short));\n              }\n        break;\n    case 'c': {\n        signed char c;\n        sq_getinteger(v, 2, &ti);\n        c = (signed char)ti;\n        self->Write(&c, sizeof(signed char));\n                  }\n        break;\n    case 'b': {\n        unsigned char b;\n        sq_getinteger(v, 2, &ti);\n        b = (unsigned char)ti;\n        self->Write(&b, sizeof(unsigned char));\n              }\n        break;\n    case 'f': {\n        float f;\n        sq_getfloat(v, 2, &tf);\n        f = (float)tf;\n        self->Write(&f, sizeof(float));\n              }\n        break;\n    case 'd': {\n        double d;\n        sq_getfloat(v, 2, &tf);\n        d = tf;\n        self->Write(&d, sizeof(double));\n              }\n        break;\n    default:\n        return sq_throwerror(v, \"invalid format\");\n    }\n    return 0;\n}\n\nSQInteger _stream_seek(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQInteger offset, origin = SQ_SEEK_SET;\n    sq_getinteger(v, 2, &offset);\n    if(sq_gettop(v) > 2) {\n        SQInteger t;\n        sq_getinteger(v, 3, &t);\n        switch(t) {\n            case 'b': origin = SQ_SEEK_SET; break;\n            case 'c': origin = SQ_SEEK_CUR; break;\n            case 'e': origin = SQ_SEEK_END; break;\n            default: return sq_throwerror(v,\"invalid origin\");\n        }\n    }\n    sq_pushinteger(v, self->Seek(offset, origin));\n    return 1;\n}\n\nSQInteger _stream_tell(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    sq_pushinteger(v, self->Tell());\n    return 1;\n}\n\nSQInteger _stream_len(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    sq_pushinteger(v, self->Len());\n    return 1;\n}\n\nSQInteger _stream_flush(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    if(!self->Flush())\n        sq_pushinteger(v, 1);\n    else\n        sq_pushnull(v);\n    return 1;\n}\n\nSQInteger _stream_eos(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    if(self->EOS())\n        sq_pushinteger(v, 1);\n    else\n        sq_pushnull(v);\n    return 1;\n}\n\n\nSQInteger _stream_writeobject(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQObjectPtr obj = stack_get(v, 2);\n    SQObjectPtr availableClasses;\n    if (sq_gettop(v) > 2)\n        availableClasses = stack_get(v, 3);\n\n    SQRESULT res = sqstd_serialize_object_to_stream(v, self, obj, availableClasses);\n    return SQ_FAILED(res) ? res : 0;\n}\n\nSQInteger _stream_readobject(HSQUIRRELVM v)\n{\n    SETUP_STREAM(v);\n    SQObjectPtr availableClasses;\n    if (sq_gettop(v) > 1)\n        availableClasses = stack_get(v, 2);\n    SQRESULT res = sqstd_deserialize_object_from_stream(v, self, availableClasses);\n    return SQ_FAILED(res) ? res : 1;\n}\n\n\nSQInteger _stream__cloned(HSQUIRRELVM v)\n{\n    return sq_throwerror(v,\"this object cannot be cloned\");\n}\n\nstatic const SQRegFunctionFromStr _stream_methods[] = {\n    { _stream_readblob,    \"instance.readblob(size: int): instance\",         \"Reads up to size bytes and returns them as a blob\" },\n    { _stream_readn,       \"instance.readn(format: int): number\",            \"Reads a value of the given numeric format and returns it\" },\n    { _stream_writeblob,   \"instance.writeblob(blob: instance): int\",        \"Writes the given blob and returns the number of bytes written\" },\n    { _stream_writestring, \"instance.writestring(str: string): int\",         \"Writes the string and returns the number of characters written\" },\n    { _stream_writen,      \"instance.writen(value: number, format: int)\",    \"Writes a numeric value in the given format\" },\n    { _stream_seek,        \"instance.seek(offset: int, [origin: int]): int\", \"Seeks to the given offset; origin is 'b' (begin), 'c' (current) or 'e' (end)\" },\n    { _stream_tell,        \"instance.tell(): int\",                           \"Returns the current stream position\" },\n    { _stream_len,         \"instance.len(): int\",                            \"Returns the stream length\" },\n    { _stream_eos,         \"instance.eos(): int|null\",                       \"Returns non-null if the stream is at end-of-stream\" },\n    { _stream_flush,       \"instance.flush(): int|null\",                     \"Flushes the stream and returns non-null on success\" },\n    { _stream_writeobject, \"instance.writeobject(obj, [classes: table|null])\",    \"Serializes the object to the stream\" },\n    { _stream_readobject,  \"instance.readobject([classes: table|null]): any\",     \"Deserializes an object from the stream\" },\n    { _stream__cloned,     \"instance._cloned(other)\",                        \"Stream cloning is not supported\" },\n    { NULL, NULL, NULL }\n};\n\nSQRESULT sqstd_init_streamclass(HSQUIRRELVM v)\n{\n    sq_pushregistrytable(v);\n    sq_pushstring(v,\"std_stream\",-1);\n    if(SQ_FAILED(sq_get(v,-2))) {\n        sq_pushstring(v,\"std_stream\",-1);\n        sq_newclass(v,SQFalse);\n        sq_settypetag(v,-1,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG));\n        SQInteger i = 0;\n        while(_stream_methods[i].f) {\n            sq_new_closure_slot_from_decl_string(v, _stream_methods[i].f, 0, _stream_methods[i].declstring, _stream_methods[i].docstring);\n            i++;\n        }\n        sq_newslot(v,-3,SQFalse); // put to registry table\n\n        sq_pushstring(v,\"stream\",-1);\n        sq_pushstring(v,\"std_stream\",-1);\n        sq_get(v,-3);\n        sq_newslot(v,-4,SQFalse); // put to destination table (and name the class 'stream')\n    }\n    else {\n        sq_pop(v,1); //result\n    }\n    sq_pop(v,1);\n    return SQ_OK;\n}\n\nSQRESULT declare_stream(HSQUIRRELVM v,const char* name,SQUserPointer typetag,const char* reg_name,const SQRegFunctionFromStr *methods,const SQRegFunctionFromStr *globals)\n{\n    if(sq_gettype(v,-1) != OT_TABLE)\n        return sq_throwerror(v,\"table expected\");\n    SQInteger top = sq_gettop(v);\n    //create base stream class\n    sqstd_init_streamclass(v);\n    sq_pushregistrytable(v);\n    sq_pushstring(v,reg_name,-1);\n    sq_pushstring(v,\"std_stream\",-1);\n    if(SQ_SUCCEEDED(sq_get(v,-3))) {\n        sq_newclass(v,SQTrue);\n        sq_settypetag(v,-1,typetag);\n        SQInteger i = 0;\n        while(methods[i].f) {\n            sq_new_closure_slot_from_decl_string(v, methods[i].f, 0, methods[i].declstring, methods[i].docstring);\n            i++;\n        }\n        sq_newslot(v,-3,SQFalse);\n        sq_pop(v,1);\n\n        i = 0;\n        while(globals[i].f) {\n            sq_new_closure_slot_from_decl_string(v, globals[i].f, 0, globals[i].declstring, globals[i].docstring);\n            i++;\n        }\n        //register the class in the target table\n        sq_pushstring(v,name,-1);\n        sq_pushregistrytable(v);\n        sq_pushstring(v,reg_name,-1);\n        sq_get(v,-2);\n        sq_remove(v,-2);\n        sq_newslot(v,-3,SQFalse);\n\n        sq_settop(v,top);\n        return SQ_OK;\n    }\n    sq_settop(v,top);\n    return SQ_ERROR;\n}\n"
  },
  {
    "path": "sqstdlib/sqstdstream.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTD_STREAM_H_\n#define _SQSTD_STREAM_H_\n\nSQInteger _stream_readblob(HSQUIRRELVM v);\nSQInteger _stream_readline(HSQUIRRELVM v);\nSQInteger _stream_readn(HSQUIRRELVM v);\nSQInteger _stream_writeblob(HSQUIRRELVM v);\nSQInteger _stream_writestring(HSQUIRRELVM v);\nSQInteger _stream_writen(HSQUIRRELVM v);\nSQInteger _stream_seek(HSQUIRRELVM v);\nSQInteger _stream_tell(HSQUIRRELVM v);\nSQInteger _stream_len(HSQUIRRELVM v);\nSQInteger _stream_eos(HSQUIRRELVM v);\nSQInteger _stream_flush(HSQUIRRELVM v);\nSQInteger _stream_writeobject(HSQUIRRELVM v);\nSQInteger _stream_readobject(HSQUIRRELVM v);\n\nSQRESULT declare_stream(HSQUIRRELVM v,const char* name,SQUserPointer typetag,const char* reg_name,const SQRegFunctionFromStr *methods,const SQRegFunctionFromStr *globals);\n#endif /*_SQSTD_STREAM_H_*/\n"
  },
  {
    "path": "sqstdlib/sqstdstring.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <sqstdstring.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <assert.h>\n#include <stdarg.h>\n#include <sqstringlib.h>\n#include <sq_char_class.h>\n\n#define MAX_FORMAT_LEN  20\n#define MAX_WFORMAT_LEN 3\n#define ADDITIONAL_FORMAT_SPACE (100*sizeof(char))\n\nstatic SQUserPointer rex_typetag = NULL;\n\nstatic SQBool isfmtchr(char ch)\n{\n    switch(ch) {\n    case '-': case '+': case ' ': case '#': case '0': return SQTrue;\n    }\n    return SQFalse;\n}\n\nstatic SQInteger validate_format(HSQUIRRELVM v, char *fmt, const char *src, SQInteger n,SQInteger &width)\n{\n    char *dummy;\n    char swidth[MAX_WFORMAT_LEN];\n    SQInteger wc = 0;\n    SQInteger start = n;\n    fmt[0] = '%';\n    while (isfmtchr(src[n])) n++;\n    while (sq_isdigit(src[n])) {\n        swidth[wc] = src[n];\n        n++;\n        wc++;\n        if(wc>=MAX_WFORMAT_LEN)\n            return sq_throwerror(v,\"width format too long\");\n    }\n    swidth[wc] = '\\0';\n    if(wc > 0) {\n        width = scstrtol(swidth,&dummy,10);\n    }\n    else\n        width = 0;\n    if (src[n] == '.') {\n        n++;\n\n        wc = 0;\n        while (sq_isdigit(src[n])) {\n            swidth[wc] = src[n];\n            n++;\n            wc++;\n            if(wc>=MAX_WFORMAT_LEN)\n                return sq_throwerror(v,\"precision format too long\");\n        }\n        swidth[wc] = '\\0';\n        if(wc > 0) {\n            width += scstrtol(swidth,&dummy,10);\n\n        }\n    }\n    if (n-start > MAX_FORMAT_LEN )\n        return sq_throwerror(v,\"format too long\");\n    memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(char));\n    fmt[(n-start)+2] = '\\0';\n    return n;\n}\n\nSQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,char **output)\n{\n    const char *format;\n    char *dest;\n    char fmt[MAX_FORMAT_LEN + 5];\n    const SQRESULT res = sq_getstring(v,nformatstringidx,&format);\n    if (SQ_FAILED(res)) {\n        return res; // propagate the error\n    }\n    SQInteger format_size = sq_getsize(v,nformatstringidx);\n    SQInteger allocated = (format_size+2)*sizeof(char);\n    dest = sq_getscratchpad(v,allocated);\n    SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0;\n    //while(format[n] != '\\0')\n    while(n < format_size)\n    {\n        if(format[n] != '%') {\n            assert(i < allocated);\n            dest[i++] = format[n];\n            n++;\n        }\n        else if(format[n+1] == '%') { //handles %%\n                dest[i++] = '%';\n                n += 2;\n        }\n        else {\n            n++;\n            if( nparam > sq_gettop(v) )\n                return sq_throwerror(v,\"not enough parameters for the given format string\");\n            n = validate_format(v,fmt,format,n,w);\n            if(n < 0) return -1;\n            SQInteger addlen = 0;\n            SQInteger valtype = 0;\n            const char *ts = NULL;\n            SQInteger ti = 0;\n            SQFloat tf = 0;\n            switch(format[n]) {\n            case 's':\n                if(SQ_FAILED(sq_getstring(v,nparam,&ts)))\n                    return sq_throwerror(v,\"string expected for the specified format\");\n                addlen = (sq_getsize(v,nparam)*sizeof(char))+((w+1)*sizeof(char));\n                valtype = 's';\n                break;\n            case 'i': case 'd': case 'o': case 'u':  case 'x':  case 'X':\n#ifdef _SQ64\n                {\n                size_t flen = strlen(fmt);\n                SQInteger fpos = flen - 1;\n                char f = fmt[fpos];\n                const char *prec = (const char *)_PRINT_INT_PREC;\n                while(*prec != '\\0') {\n                    fmt[fpos++] = *prec++;\n                }\n                fmt[fpos++] = f;\n                fmt[fpos++] = '\\0';\n                }\n#endif\n            case 'c':\n                if(SQ_FAILED(sq_getinteger(v,nparam,&ti)))\n                    return sq_throwerror(v,\"integer expected for the specified format\");\n                addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(char));\n                valtype = 'i';\n                break;\n            case 'f': case 'g': case 'G': case 'e':  case 'E':\n                if(SQ_FAILED(sq_getfloat(v,nparam,&tf)))\n                    return sq_throwerror(v,\"float expected for the specified format\");\n                addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(char));\n                valtype = 'f';\n                break;\n            default:\n                return sq_throwerror(v,\"invalid format\");\n            }\n            n++;\n            allocated += addlen + sizeof(char);\n            dest = sq_getscratchpad(v,allocated);\n            switch(valtype) {\n            case 's': i += scsprintf(&dest[i],allocated,fmt,ts); break;\n            case 'i': i += scsprintf(&dest[i],allocated,fmt,ti); break;\n            case 'f': {\n                int len = scsprintf(&dest[i], allocated, fmt, tf);\n                for (; len > 0; len--, i++)\n                    if (dest[i] == ',')\n                        dest[i] = '.';\n                break;\n                }\n            };\n            nparam ++;\n        }\n    }\n    *outlen = i;\n    dest[i] = '\\0';\n    *output = dest;\n    return SQ_OK;\n}\n\nvoid sqstd_pushstringf(HSQUIRRELVM v,const char *s,...)\n{\n    SQInteger n=256;\n    va_list args;\nbegin:\n    va_start(args,s);\n    char *b=sq_getscratchpad(v,n);\n    SQInteger r=vsnprintf(b,n,s,args);\n    va_end(args);\n    if (r>=n) {\n        n=r+1;//required+null\n        goto begin;\n    } else if (r<0) {\n        sq_pushnull(v);\n    } else {\n        sq_pushstring(v,b,r);\n    }\n}\n\nstatic SQInteger _string_printf(HSQUIRRELVM v)\n{\n    char *dest = NULL;\n    SQInteger length = 0;\n    if(SQ_FAILED(sqstd_format(v,2,&length,&dest)))\n        return -1;\n\n    SQPRINTFUNCTION printfunc = sq_getprintfunc(v);\n    if(printfunc) printfunc(v,\"%s\",dest);\n\n    return 0;\n}\n\nstatic SQInteger _string_format(HSQUIRRELVM v)\n{\n    char *dest = NULL;\n    SQInteger length = 0;\n    if(SQ_FAILED(sqstd_format(v,2,&length,&dest)))\n        return -1;\n    sq_pushstring(v,dest,length);\n    return 1;\n}\n\n#define IMPL_STRING_FUNC(name) static SQInteger _string_##name(HSQUIRRELVM v) { return _sq_string_ ## name ## _impl(v, 2); }\n\nIMPL_STRING_FUNC(strip)\nIMPL_STRING_FUNC(lstrip)\nIMPL_STRING_FUNC(rstrip)\nIMPL_STRING_FUNC(split_by_chars)\nIMPL_STRING_FUNC(escape)\nIMPL_STRING_FUNC(startswith)\nIMPL_STRING_FUNC(endswith)\n\n#undef IMPL_STRING_FUNC\n\n#define SETUP_REX(v) \\\n    SQRex *self = NULL; \\\n    if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer *)&self,rex_typetag))) { \\\n        return sq_throwerror(v,\"invalid type tag\"); \\\n    }\n\nstatic SQInteger _rexobj_releasehook(HSQUIRRELVM SQ_UNUSED_ARG(vm), SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))\n{\n    SQRex *self = ((SQRex *)p);\n    sqstd_rex_free(self);\n    return 1;\n}\n\nstatic SQInteger _regexp_match(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    const char *str;\n    sq_getstring(v,2,&str);\n    if(sqstd_rex_match(self,str) == SQTrue)\n    {\n        sq_pushbool(v,SQTrue);\n        return 1;\n    }\n    sq_pushbool(v,SQFalse);\n    return 1;\n}\n\nstatic void _addrexmatch(HSQUIRRELVM v,const char *str,const char *begin,const char *end)\n{\n    sq_newtable(v);\n    sq_pushstring(v,\"begin\",-1);\n    sq_pushinteger(v,begin - str);\n    sq_rawset(v,-3);\n    sq_pushstring(v,\"end\",-1);\n    sq_pushinteger(v,end - str);\n    sq_rawset(v,-3);\n}\n\nstatic SQInteger _regexp_search(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    const char *str,*begin,*end;\n    SQInteger start = 0;\n    sq_getstring(v,2,&str);\n    if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);\n    if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {\n        _addrexmatch(v,str,begin,end);\n        return 1;\n    }\n    return 0;\n}\n\nstatic SQInteger _regexp_capture(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    const char *str,*begin,*end;\n    SQInteger start = 0;\n    sq_getstring(v,2,&str);\n    if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);\n    if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {\n        SQInteger n = sqstd_rex_getsubexpcount(self);\n        SQRexMatch match;\n        sq_newarray(v,0);\n        for(SQInteger i = 0;i < n; i++) {\n            sqstd_rex_getsubexp(self,i,&match);\n            if(match.len > 0)\n                _addrexmatch(v,str,match.begin,match.begin+match.len);\n            else\n                _addrexmatch(v,str,str,str); //empty match\n            sq_arrayappend(v,-2);\n        }\n        return 1;\n    }\n    return 0;\n}\n\nstatic SQInteger _regexp_subexpcount(HSQUIRRELVM v)\n{\n    SETUP_REX(v);\n    sq_pushinteger(v,sqstd_rex_getsubexpcount(self));\n    return 1;\n}\n\nstatic SQInteger _regexp_constructor(HSQUIRRELVM v)\n{\n    SQRex *self = NULL;\n    if (SQ_FAILED(sq_getinstanceup(v, 1, (SQUserPointer *)&self, rex_typetag))) {\n        return sq_throwerror(v, \"invalid type tag\");\n    }\n    if (self != NULL) {\n        return sq_throwerror(v, \"invalid regexp object\");\n    }\n    const char *error,*pattern;\n    sq_getstring(v,2,&pattern);\n    SQRex *rex = sqstd_rex_compile(sq_getallocctx(v),pattern,&error);\n    if(!rex) return sq_throwerror(v,error);\n    sq_setinstanceup(v,1,rex);\n    sq_setreleasehook(v,1,_rexobj_releasehook);\n    return 0;\n}\n\nstatic SQInteger _regexp__typeof(HSQUIRRELVM v)\n{\n    sq_pushstring(v,\"regexp\",-1);\n    return 1;\n}\n\nstatic const SQRegFunctionFromStr rexobj_funcs[] = {\n    { _regexp_constructor, \"constructor(pattern: string): instance\" },\n    { _regexp_match, \"instance.match(str: string): bool\" },\n    { _regexp_search, \"instance.search(str: string, [start: int]): table|null\" },\n    { _regexp_capture, \"instance.capture(str: string, [start: int]): array|null\" },\n    { _regexp_subexpcount, \"instance.subexpcount(): int\" },\n    { _regexp__typeof, \"instance._typeof(): string\" },\n    { NULL, NULL }\n};\n\nstatic const SQRegFunctionFromStr stringlib_funcs[] = {\n    { _string_format, \"pure format(fmt: string, ...): string\" },\n    { _string_printf, \"printf(fmt: string, ...)\" },\n    { _string_strip, \"pure strip(str: string): string\" },\n    { _string_lstrip, \"pure lstrip(str: string): string\" },\n    { _string_rstrip, \"pure rstrip(str: string): string\" },\n    { _string_split_by_chars, \"split_by_chars(str: string, separators: string, [skip_empty: bool]): array\" },\n    { _string_escape, \"pure escape(str: string): string\" },\n    { _string_startswith, \"pure startswith(str: string, prefix: string): bool\" },\n    { _string_endswith, \"pure endswith(str: string, suffix: string): bool\" },\n    { NULL, NULL },\n};\n#undef _DECL_FUNC\n\n\nSQRESULT sqstd_register_stringlib(HSQUIRRELVM v)\n{\n    sq_pushstring(v, \"regexp\", -1);\n    sq_newclass(v, SQFalse);\n    rex_typetag = (SQUserPointer)rexobj_funcs;\n    sq_settypetag(v, -1, rex_typetag);\n    SQInteger i = 0;\n    while (rexobj_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, rexobj_funcs[i].f, 0, rexobj_funcs[i].declstring, rexobj_funcs[i].docstring);\n        i++;\n    }\n    sq_newslot(v, -3, SQFalse);\n\n    i = 0;\n    while (stringlib_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, stringlib_funcs[i].f, 0, stringlib_funcs[i].declstring, stringlib_funcs[i].docstring);\n        i++;\n    }\n    return SQ_OK;\n}\n"
  },
  {
    "path": "sqstdlib/sqstdsystem.cpp",
    "content": "/* see copyright notice in squirrel.h */\n#include <squirrel.h>\n#include <time.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <sqstdsystem.h>\n\n\nstatic SQInteger _system_getenv(HSQUIRRELVM v)\n{\n    const char *s;\n    if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){\n        sq_pushstring(v,getenv(s),-1);\n        return 1;\n    }\n    return 0;\n}\n\nstatic SQInteger _system_system(HSQUIRRELVM v)\n{\n    const char *s;\n    if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){\n        sq_pushinteger(v,system(s));\n        return 1;\n    }\n    return sq_throwerror(v,\"wrong param\");\n}\n\nstatic SQInteger _system_setenv(HSQUIRRELVM v)\n{\n    const char *envname,*envval;\n    sq_getstring(v,2,&envname);\n    sq_getstring(v,3,&envval);\n    #if defined(_MSC_VER)\n    int res = _putenv_s(envname,envval);\n    #else\n    int res = setenv(envname,envval,1);\n    #endif\n    if (res != 0)\n        return sq_throwerror(v,\"setenv() failed\");\n    return 0;\n}\n\nstatic SQInteger _system_remove(HSQUIRRELVM v)\n{\n    const char *s;\n    sq_getstring(v,2,&s);\n    if(remove(s)==-1)\n        return sq_throwerror(v,\"remove() failed\");\n    return 0;\n}\n\nstatic SQInteger _system_rename(HSQUIRRELVM v)\n{\n    const char *oldn,*newn;\n    sq_getstring(v,2,&oldn);\n    sq_getstring(v,3,&newn);\n    if(rename(oldn,newn)==-1)\n        return sq_throwerror(v,\"rename() failed\");\n    return 0;\n}\n\n\nstatic const SQRegFunctionFromStr systemlib_funcs[] = {\n    { _system_getenv, \"getenv(name: string): string|null\",            \"Returns the value of the environment variable or null\" },\n    { _system_setenv, \"setenv(name: string, value: string)\",          \"Sets the environment variable to the given value\" },\n    { _system_system, \"system(cmd: string): int\",                     \"Executes a shell command and returns its exit code\" },\n    { _system_remove, \"remove(path: string)\",                         \"Deletes the file at the given path, throws error in case of fail\" },\n    { _system_rename, \"rename(old: string, new: string)\",             \"Renames the file from old to new path, throws error in case of fail\" },\n    { NULL, NULL, NULL }\n};\n#undef _DECL_FUNC\n\n\nSQRESULT sqstd_register_command_line_args(HSQUIRRELVM v, int argc, char ** argv)\n{\n    sq_pushroottable(v);\n    sq_pushstring(v, \"__argv\", -1);\n    sq_newarray(v, 0);\n    for (int idx = 0; idx < argc; idx++)\n    {\n        sq_pushstring(v, argv[idx], -1);\n        sq_arrayappend(v, -2);\n    }\n    sq_newslot(v, -3, SQFalse);\n    sq_pop(v,1);\n\n    return SQ_OK;\n}\n\n\nSQRESULT sqstd_register_systemlib(HSQUIRRELVM v)\n{\n    SQInteger i = 0;\n    while (systemlib_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, systemlib_funcs[i].f, 0, systemlib_funcs[i].declstring, systemlib_funcs[i].docstring);\n        i++;\n    }\n    return SQ_OK;\n}\n"
  },
  {
    "path": "squirrel/CMakeLists.txt",
    "content": "set(SQUIRREL_SRC sqapi.cpp\n                 sqbaselib.cpp\n                 sqclass.cpp\n                 sqdebug.cpp\n                 sqmem.cpp\n                 sqobject.cpp\n                 sqstate.cpp\n                 sqtable.cpp\n                 sqvm.cpp\n                 sqdedupshrinker.cpp\n                 sqstringlib.cpp\n                 sqext.cpp)\n\nif (ENABLE_VAR_TRACE)\n  list(APPEND SQUIRREL_SRC vartrace.cpp)\n  add_definitions(-DSQ_VAR_TRACE_ENABLED=1)\nelse ()\n  list(APPEND SQUIRREL_SRC vartracestub.cpp)\n  add_definitions(-DSQ_VAR_TRACE_ENABLED=0)\nendif()\n\n\nadd_library(squirrel STATIC ${SQUIRREL_SRC})\nadd_library(squirrel::squirrel ALIAS squirrel)\ntarget_include_directories(squirrel PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\"\n  \"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\"\n  PRIVATE\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/internal>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/squirrel>\"\n  )\n"
  },
  {
    "path": "squirrel/ast_tools/ast_indent_render.h",
    "content": "#pragma once\n#include <cstdio> // for snprintf\n#include \"sqio.h\"\n#include <compiler/ast.h>\n#include <compiler/sqtypeparser.h>\n\nnamespace SQCompilation {\n\nclass IndentedTreeRenderer : public Visitor {\n    OutputStream* _out;\n    SQInteger _indent;\n    sqvector<int> indents;\n    sqvector<int> vertLines;\n    bool collectIndentsPass;\n    int lineNum;\n    char loc[32];\n    char scratchpad[1024];\n\n    void indent() {\n        if (collectIndentsPass) {\n            indents.push_back(_indent);\n            return;\n        }\n\n        while (vertLines.size() <= _indent)\n            vertLines.push_back(0);\n\n        if (_indent > 0) {\n            if (lineNum == 0 || (_indent > indents[lineNum - 1])) {\n                int breakPos = lineNum;\n                for (int i = lineNum; i < indents.size(); i++) {\n                    if (indents[i] == _indent)\n                        breakPos = i;\n                    if (indents[i] < _indent)\n                        break;\n                }\n                vertLines[_indent - 1] = breakPos - lineNum + 1;\n                if (vertLines[_indent - 1] == 1)\n                    vertLines[_indent - 1] = 0;\n            }\n\n            for (SQInteger i = 0; i < _indent; ++i) {\n                if (vertLines[i] > 1)\n                    _out->writeString(i == _indent - 1 ? \"|-\" : \"| \");\n                else if (vertLines[i] == 1)\n                    _out->writeString(\"`-\");\n                else\n                    _out->writeString(\"  \");\n\n                if (vertLines[i] > 0)\n                    vertLines[i]--;\n            }\n        }\n        lineNum++;\n    }\n\n    const char* treeopToStr(TreeOp op) {\n        switch (op) {\n        case TO_NULLC: return \"??\";\n        case TO_ASSIGN: return \"=\";\n        case TO_OROR: return \"||\";\n        case TO_ANDAND: return \"&&\";\n        case TO_OR: return \"|\";\n        case TO_XOR: return \"^\";\n        case TO_AND: return \"&\";\n        case TO_NE: return \"!=\";\n        case TO_EQ: return \"==\";\n        case TO_3CMP: return \"<=>\";\n        case TO_GE: return \">=\";\n        case TO_GT: return \">\";\n        case TO_LE: return \"<=\";\n        case TO_LT: return \"<\";\n        case TO_IN: return \"IN\";\n        case TO_INSTANCEOF: return \"INSTANCEOF\";\n        case TO_USHR: return \">>>\";\n        case TO_SHR: return \">>\";\n        case TO_SHL: return \"<<\";\n        case TO_MUL: return \"*\";\n        case TO_DIV: return \"/\";\n        case TO_MOD: return \"%\";\n        case TO_ADD: return \"+\";\n        case TO_SUB: case TO_NEG: return \"-\";\n        case TO_NOT: return \"!\";\n        case TO_BNOT: return \"~\";\n        case TO_TYPEOF: return \"TYPEOF\";\n        case TO_RESUME: return \"RESUME\";\n        case TO_CLONE: return \"CLONE\";\n        case TO_DELETE: return \"DELETE\";\n        case TO_NEWSLOT: return \"<-\";\n        case TO_PLUSEQ: return \"+=\";\n        case TO_MINUSEQ: return \"-=\";\n        case TO_MULEQ: return \"*=\";\n        case TO_DIVEQ: return \"/=\";\n        case TO_MODEQ: return \"%=\";\n        case TO_STATIC_MEMO: return \"STATIC_MEMO\";\n        case TO_INLINE_CONST: return \"INLINE_CONST\";\n        case TO_PAREN: return \"(\";\n        default: return \"<UNKNOWN_OP>\";\n        }\n    }\n\n    void writeFmtString(const char* fmt, ...) {\n        if (collectIndentsPass)\n            return;\n        char buf[256];\n        va_list args;\n        va_start(args, fmt);\n        vsnprintf(buf, sizeof(buf), fmt, args);\n        va_end(args);\n        _out->writeString(buf);\n    }\n\n    void writeIndentedFmtString(const char* fmt, ...) {\n        indent();\n        if (collectIndentsPass)\n            return;\n        char buf[256];\n        va_list args;\n        va_start(args, fmt);\n        vsnprintf(buf, sizeof(buf), fmt, args);\n        va_end(args);\n        _out->writeString(buf);\n    }\n\npublic:\n    bool printNodesLocation;\n\n    IndentedTreeRenderer(OutputStream* output) : _out(output), _indent(0), indents(nullptr), vertLines(nullptr),\n        collectIndentsPass(false), printNodesLocation(true), lineNum(0), loc(\"\"), scratchpad(\"\") {}\n\n    void render(Node* n) {\n        if (n) {\n            collectIndentsPass = true;\n            n->visit(this);\n            collectIndentsPass = false;\n            n->visit(this);\n        } else {\n            indent();\n            _out->writeString(\"(null)\");\n        }\n    }\n\n    virtual void visitNode(Node* node) override {\n        TreeOp op = node->op();\n\n        if (printNodesLocation && !collectIndentsPass)\n            snprintf(loc, sizeof(loc), \"  [%d:%d]\", int(node->lineStart()), int(node->columnStart()));\n        else\n            loc[0] = 0;\n\n        switch (op) {\n            case TO_ID: {\n                Id* id = static_cast<Id*>(node);\n                writeIndentedFmtString(\"Id '%s'%s\\n\", id->name(), loc);\n                break;\n            }\n\n            case TO_LITERAL: {\n                LiteralExpr* lit = static_cast<LiteralExpr*>(node);\n                switch (lit->kind()) {\n                    case LK_STRING:\n                        writeIndentedFmtString(\"LiteralExpr LK_STRING \\\"%s\\\"%s\\n\", lit->s(), loc);\n                        break;\n                    case LK_FLOAT:\n                        writeIndentedFmtString(\"LiteralExpr LK_FLOAT %f%s\\n\", lit->f(), loc);\n                        break;\n                    case LK_INT:\n                        writeIndentedFmtString(\"LiteralExpr LK_INT %lld%s\\n\", (long long)lit->i(), loc);\n                        break;\n                    case LK_BOOL:\n                        writeIndentedFmtString(\"LiteralExpr LK_BOOL %s%s\\n\", lit->b() ? \"true\" : \"false\", loc);\n                        break;\n                    case LK_NULL:\n                        writeIndentedFmtString(\"LiteralExpr LK_NULL%s\\n\", loc);\n                        break;\n                    default:\n                        writeIndentedFmtString(\"LiteralExpr <UNKNOWN_LITERAL>%s\\n\", loc);\n                        break;\n                }\n                break;\n            }\n\n            case TO_NOT:\n            case TO_BNOT:\n            case TO_NEG:\n            case TO_TYPEOF:\n            case TO_RESUME:\n            case TO_CLONE:\n            case TO_PAREN:\n            case TO_DELETE:\n            case TO_STATIC_MEMO:\n            case TO_INLINE_CONST: {\n                UnExpr* expr = static_cast<UnExpr*>(node);\n                writeIndentedFmtString(\"UnExpr '%s'%s\\n\", treeopToStr(expr->op()), loc);\n                ++_indent;\n                expr->argument()->visit(this);\n                --_indent;\n                break;\n            }\n\n            case TO_CODE_BLOCK_EXPR: {\n                CodeBlockExpr* expr = static_cast<CodeBlockExpr*>(node);\n                writeIndentedFmtString(\"CodeBlockExpr%s\\n\", loc);\n                ++_indent;\n                expr->block()->visit(this);\n                --_indent;\n                break;\n            }\n\n            case TO_NULLC:\n            case TO_ASSIGN:\n            case TO_OROR:\n            case TO_ANDAND:\n            case TO_OR:\n            case TO_XOR:\n            case TO_AND:\n            case TO_NE:\n            case TO_EQ:\n            case TO_3CMP:\n            case TO_GE:\n            case TO_GT:\n            case TO_LE:\n            case TO_LT:\n            case TO_IN:\n            case TO_INSTANCEOF:\n            case TO_USHR:\n            case TO_SHR:\n            case TO_SHL:\n            case TO_MUL:\n            case TO_DIV:\n            case TO_MOD:\n            case TO_ADD:\n            case TO_SUB:\n            case TO_NEWSLOT:\n            case TO_PLUSEQ:\n            case TO_MINUSEQ:\n            case TO_MULEQ:\n            case TO_DIVEQ:\n            case TO_MODEQ:\n            {\n                BinExpr* expr = static_cast<BinExpr*>(node);\n                writeIndentedFmtString(\"BinExpr '%s'%s\\n\", treeopToStr(expr->op()), loc);\n                ++_indent;\n                writeIndentedFmtString(\"Left\\n\");\n                ++_indent;\n                expr->lhs()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Right\\n\");\n                ++_indent;\n                expr->rhs()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_TERNARY: {\n                TerExpr* expr = static_cast<TerExpr*>(node);\n                writeIndentedFmtString(\"TerExpr%s\\n\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Condition\\n\");\n                ++_indent;\n                expr->a()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"TrueBranch\\n\");\n                ++_indent;\n                expr->b()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"FalseBranch\\n\");\n                ++_indent;\n                expr->c()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_CALL: {\n                CallExpr* expr = static_cast<CallExpr*>(node);\n                writeIndentedFmtString(\"CallExpr%s\\n\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Callee\\n\");\n                ++_indent;\n                expr->callee()->visit(this);\n                --_indent;\n                --_indent;\n                if (!expr->arguments().empty()) {\n                    ++_indent;\n                    writeIndentedFmtString(\"Arguments\\n\");\n                    ++_indent;\n                    for (int i = 0; i < (int)expr->arguments().size(); ++i) {\n                        writeIndentedFmtString(\"Argument #%d\\n\", i + 1);\n                        ++_indent;\n                        expr->arguments()[i]->visit(this);\n                        --_indent;\n                    }\n                    --_indent;\n                    --_indent;\n                }\n                break;\n            }\n\n            case TO_GETFIELD: {\n                GetFieldExpr* expr = static_cast<GetFieldExpr*>(node);\n                writeIndentedFmtString(\"GetFieldExpr '%s' fieldName = '%s'%s\\n\", expr->isNullable() ? \"?.\":\".\", expr->fieldName(), loc);\n                ++_indent;\n                writeIndentedFmtString(\"Receiver\\n\");\n                ++_indent;\n                expr->receiver()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_SETFIELD: {\n                SetFieldExpr* expr = static_cast<SetFieldExpr*>(node);\n                writeIndentedFmtString(\"SetFieldExpr '%s' fieldName = '%s'%s\\n\", expr->isNullable() ? \"?.\" : \".\", expr->fieldName(), loc);\n                ++_indent;\n                writeIndentedFmtString(\"Receiver\\n\");\n                ++_indent;\n                expr->receiver()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_GETSLOT: {\n                GetSlotExpr* expr = static_cast<GetSlotExpr*>(node);\n                writeIndentedFmtString(\"GetSlotExpr '%s'%s\\n\", expr->isNullable() ? \"?[\" : \"[\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Receiver\\n\");\n                ++_indent;\n                expr->receiver()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Key\\n\");\n                ++_indent;\n                expr->key()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_SETSLOT: {\n                SetSlotExpr* expr = static_cast<SetSlotExpr*>(node);\n                writeIndentedFmtString(\"SetSlotExpr '%s'%s\\n\", expr->isNullable() ? \"?[\" : \"[\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Receiver\\n\");\n                ++_indent;\n                expr->receiver()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Key\\n\");\n                ++_indent;\n                expr->key()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Value\\n\");\n                ++_indent;\n                expr->value()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_INC: {\n                IncExpr* expr = static_cast<IncExpr*>(node);\n                writeIndentedFmtString(\"IncExpr %s '%s'%s\\n\",\n                    (expr->form() == IF_PREFIX) ? \"IF_PREFIX\" : \"IF_POSTFIX\", (expr->diff() < 0) ? \"--\" : \"++\", loc);\n                ++_indent;\n                expr->argument()->visit(this);\n                --_indent;\n                break;\n            }\n\n            case TO_ARRAY: {\n                ArrayExpr* expr = static_cast<ArrayExpr*>(node);\n                writeIndentedFmtString(\"ArrayExpr%s\\n\", loc);\n                if (!expr->initializers().empty()) {\n                    ++_indent;\n                    for (int i = 0; i < (int)expr->initializers().size(); ++i) {\n                        writeIndentedFmtString(\"Element #%d\\n\", i + 1);\n                        ++_indent;\n                        expr->initializers()[i]->visit(this);\n                        --_indent;\n                    }\n                    --_indent;\n                }\n                break;\n            }\n\n            case TO_COMMA: {\n                CommaExpr* expr = static_cast<CommaExpr*>(node);\n                writeIndentedFmtString(\"CommaExpr%s\\n\", loc);\n                ++_indent;\n                for (int i = 0; i < (int)expr->expressions().size(); ++i) {\n                    writeIndentedFmtString(\"Expression #%d\\n\", i + 1);\n                    ++_indent;\n                    expr->expressions()[i]->visit(this);\n                    --_indent;\n                }\n                --_indent;\n                break;\n            }\n\n\n            case TO_BLOCK: {\n                Block* block = static_cast<Block*>(node);\n                writeIndentedFmtString(\"Block isRoot = %d, isBody = %d%s\\n\", int(block->isRoot()), int(block->isBody()), loc);\n                ++_indent;\n                for (Statement* stmt : block->statements()) {\n                    stmt->visit(this);\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_IF: {\n                IfStatement* stmt = static_cast<IfStatement*>(node);\n                writeIndentedFmtString(\"IfStatement%s\\n\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Condition\\n\");\n                ++_indent;\n                stmt->condition()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"ThenBranch\\n\");\n                ++_indent;\n                stmt->thenBranch()->visit(this);\n                --_indent;\n                if (stmt->elseBranch()) {\n                    writeIndentedFmtString(\"ElseBranch\\n\");\n                    ++_indent;\n                    stmt->elseBranch()->visit(this);\n                    --_indent;\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_WHILE: {\n                WhileStatement* loop = static_cast<WhileStatement*>(node);\n                writeIndentedFmtString(\"WhileStatement%s\\n\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Condition\\n\");\n                ++_indent;\n                loop->condition()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Body\\n\");\n                ++_indent;\n                loop->body()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_DOWHILE: {\n                DoWhileStatement* loop = static_cast<DoWhileStatement*>(node);\n                writeIndentedFmtString(\"DoWhileStatement%s\\n\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"Body\\n\");\n                ++_indent;\n                loop->body()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Condition\\n\");\n                ++_indent;\n                loop->condition()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_FOR: {\n                ForStatement* loop = static_cast<ForStatement*>(node);\n                writeIndentedFmtString(\"ForStatement%s\\n\", loc);\n                ++_indent;\n                if (loop->initializer()) {\n                    writeIndentedFmtString(\"Initializer\\n\");\n                    ++_indent;\n                    loop->initializer()->visit(this);\n                    --_indent;\n                }\n                if (loop->condition()) {\n                    writeIndentedFmtString(\"Condition\\n\");\n                    ++_indent;\n                    loop->condition()->visit(this);\n                    --_indent;\n                }\n                if (loop->modifier()) {\n                    writeIndentedFmtString(\"Modifier\\n\");\n                    ++_indent;\n                    loop->modifier()->visit(this);\n                    --_indent;\n                }\n                writeIndentedFmtString(\"Body\\n\");\n                ++_indent;\n                loop->body()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_FOREACH: {\n                ForeachStatement* loop = static_cast<ForeachStatement*>(node);\n                writeIndentedFmtString(\"ForeachStatement%s\\n\", loc);\n                ++_indent;\n                if (loop->idx()) {\n                    writeIndentedFmtString(\"IndexVariable\\n\");\n                    ++_indent;\n                    loop->idx()->visit(this);\n                    --_indent;\n                }\n                writeIndentedFmtString(\"ValueVariable\\n\");\n                ++_indent;\n                loop->val()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Container\\n\");\n                ++_indent;\n                loop->container()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"Body\\n\");\n                ++_indent;\n                loop->body()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_TRY: {\n                TryStatement* tr = static_cast<TryStatement*>(node);\n                writeIndentedFmtString(\"TryStatement%s\\n\", loc);\n                ++_indent;\n                writeIndentedFmtString(\"TryBlock\\n\");\n                ++_indent;\n                tr->tryStatement()->visit(this);\n                --_indent;\n                writeIndentedFmtString(\"CatchBlock exceptionId = '%s'\\n\", tr->exceptionId()->name());\n                ++_indent;\n                tr->catchStatement()->visit(this);\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_RETURN: {\n                ReturnStatement* ret = static_cast<ReturnStatement*>(node);\n                writeIndentedFmtString(\"ReturnStatement%s\\n\", loc);\n                if (ret->argument()) {\n                    ++_indent;\n                    ret->argument()->visit(this);\n                    --_indent;\n                }\n                break;\n            }\n\n            case TO_THROW: {\n                ThrowStatement* thr = static_cast<ThrowStatement*>(node);\n                writeIndentedFmtString(\"ThrowStatement%s\\n\", loc);\n                if (thr->argument()) {\n                    ++_indent;\n                    thr->argument()->visit(this);\n                    --_indent;\n                }\n                break;\n            }\n\n            case TO_YIELD: {\n                YieldStatement* yield = static_cast<YieldStatement*>(node);\n                writeIndentedFmtString(\"YieldStatement%s\\n\", loc);\n                if (yield->argument()) {\n                    ++_indent;\n                    yield->argument()->visit(this);\n                    --_indent;\n                }\n                break;\n            }\n\n            case TO_BREAK: {\n                writeIndentedFmtString(\"BreakStatement%s\\n\", loc);\n                break;\n            }\n\n            case TO_CONTINUE: {\n                writeIndentedFmtString(\"ContinueStatement%s\\n\", loc);\n                break;\n            }\n\n            case TO_EMPTY: {\n                writeIndentedFmtString(\"EmptyStatement%s\\n\", loc);\n                break;\n            }\n\n            case TO_DIRECTIVE: {\n                writeIndentedFmtString(\"DirectiveStmt%s\\n\", loc);\n                break;\n            }\n\n            case TO_BASE: {\n                writeIndentedFmtString(\"BaseExpr%s\\n\", loc);\n                break;\n            }\n\n            case TO_EXPR_STMT: {\n                ExprStatement* estmt = static_cast<ExprStatement*>(node);\n                writeIndentedFmtString(\"ExprStatement%s\\n\", loc);\n                ++_indent;\n                estmt->expression()->visit(this);\n                --_indent;\n                break;\n            }\n\n\n            case TO_VAR: {\n                VarDecl* decl = static_cast<VarDecl*>(node);\n                sq_stringify_type_mask(scratchpad, sizeof(scratchpad), decl->getTypeMask());\n                const char* kind = decl->isAssignable() ? \"local\" : \"let\";\n                writeIndentedFmtString(\"VarDecl '%s', name = '%s', type = '%s'%s\\n\", kind, decl->name(), scratchpad, loc);\n                if (decl->expression()) {\n                    ++_indent;\n                    writeIndentedFmtString(\"Initializer\\n\");\n                    ++_indent;\n                    decl->expression()->visit(this);\n                    --_indent;\n                    --_indent;\n                }\n                break;\n            }\n\n            case TO_DECL_GROUP: {\n                DeclGroup* dgrp = static_cast<DeclGroup*>(node);\n                writeIndentedFmtString(\"DeclGroup%s\\n\", loc);\n                ++_indent;\n                for (auto& decl : dgrp->declarations()) {\n                    decl->visit(this);\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_ROOT_TABLE_ACCESS: {\n                writeIndentedFmtString(\"RootTableAccessExpr%s\\n\", loc);\n                break;\n            }\n\n            case TO_DESTRUCTURE: {\n                DestructuringDecl* dstr = static_cast<DestructuringDecl*>(node);\n                writeIndentedFmtString(\"DestructuringDecl type = '%s'%s\\n\",\n                    dstr->type() == DT_ARRAY ? \"array\" : (dstr->type() == DT_TABLE ? \"table\" : \"unknown\"), loc);\n                ++_indent;\n                if (dstr->initExpression()) {\n                    writeIndentedFmtString(\"Initializer\\n\");\n                    ++_indent;\n                    dstr->initExpression()->visit(this);\n                    --_indent;\n                }\n                for (auto& decl : dstr->declarations()) {\n                    decl->visit(this);\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_CONST: {\n                ConstDecl* constDecl = static_cast<ConstDecl*>(node);\n                writeIndentedFmtString(\"ConstDecl name = '%s', isGlobal = %d%s\\n\", constDecl->name(), int(constDecl->isGlobal()), loc);\n                ++_indent;\n                if (constDecl->value()) {\n                    constDecl->value()->visit(this);\n                } else {\n                    indent();\n                    _out->writeString(\"(null)\\n\");\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_ENUM: {\n                EnumDecl* enm = static_cast<EnumDecl*>(node);\n                writeIndentedFmtString(\"EnumDecl name = '%s', isGlobal = %d%s\\n\", enm->name(), int(enm->isGlobal()), loc);\n                ++_indent;\n                for (auto& c : enm->consts()) {\n                    writeIndentedFmtString(\"Member '%s'\\n\", c.id);\n                    ++_indent;\n                    if (c.val) {\n                        c.val->visit(this);\n                    } else {\n                        indent();\n                        _out->writeString(\"(null)\\n\");\n                    }\n                    --_indent;\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_TABLE: {\n                TableExpr* tbl = static_cast<TableExpr*>(node);\n                writeIndentedFmtString(\"TableExpr%s\\n\", loc);\n                ++_indent;\n                for (auto& m : tbl->members()) {\n                    writeIndentedFmtString(\"Field\\n\");\n                    ++_indent;\n                    writeIndentedFmtString(\"Key\\n\");\n                    ++_indent;\n                    m.key->visit(this);\n                    --_indent;\n                    writeIndentedFmtString(\"Value\\n\");\n                    ++_indent;\n                    m.value->visit(this);\n                    --_indent;\n                    --_indent;\n                }\n                --_indent;\n                break;\n            }\n\n            case TO_CLASS: {\n                ClassExpr* cls = static_cast<ClassExpr*>(node);\n                writeIndentedFmtString(\"ClassExpr%s\\n\", loc);\n                if (cls->classKey()) {\n                    ++_indent;\n                    writeIndentedFmtString(\"Key\\n\");\n                    ++_indent;\n                    cls->classKey()->visit(this);\n                    --_indent;\n                    --_indent;\n                } else {\n                    ++_indent;\n                    writeIndentedFmtString(\"Key: <anonymous>\\n\");\n                    --_indent;\n                }\n\n                if (cls->classBase()) {\n                    ++_indent;\n                    writeIndentedFmtString(\"Base\\n\");\n                    ++_indent;\n                    cls->classBase()->visit(this);\n                    --_indent;\n                    --_indent;\n                }\n\n                ++_indent;\n                writeIndentedFmtString(\"Members\\n\");\n                ++_indent;\n                for (auto& member : cls->members()) {\n                    member.value->visit(this);\n                }\n                --_indent;\n                --_indent;\n                break;\n            }\n\n            case TO_FUNCTION: {\n                FunctionExpr* fn = static_cast<FunctionExpr*>(node);\n                sq_stringify_type_mask(scratchpad, sizeof(scratchpad), fn->getResultTypeMask());\n\n                writeIndentedFmtString(\"%s name = '%s', pure = %d, nodiscard = %d, resultType = '%s'%s\\n\",\n                    fn->isLambda() ? \"FunctionExpr 'lambda'\" : \"FunctionExpr\",\n                    fn->name() ? fn->name() : \"<anonymous>\", fn->isPure(), fn->isNodiscard(), scratchpad, loc);\n\n                ++_indent;\n                writeIndentedFmtString(\"Parameters count = %d\\n\", (int)fn->parameters().size());\n                ++_indent;\n                for (int i = 0; i < (int)fn->parameters().size(); ++i) {\n                    sq_stringify_type_mask(scratchpad, sizeof(scratchpad), fn->parameters()[i]->getTypeMask());\n                    writeIndentedFmtString(\"Parameter #%d name = '%s', type = '%s'%s%s\\n\", i + 1, fn->parameters()[i]->name(), scratchpad,\n                        fn->parameters()[i]->isVararg() ? \"  (vararg)\" : \"\", fn->parameters()[i]->hasDefaultValue() ? \"  (has default)\" : \"\");\n                    if (fn->parameters()[i]->hasDefaultValue()) {\n                        ++_indent;\n                        writeIndentedFmtString(\"DefaultValue\\n\");\n                        ++_indent;\n                        fn->parameters()[i]->defaultValue()->visit(this);\n                        --_indent;\n                        --_indent;\n                    }\n\n                    if (fn->parameters()[i]->getDestructuring()) {\n                        ++_indent;\n                        writeIndentedFmtString(\"Destructuring\\n\");\n                        ++_indent;\n                        fn->parameters()[i]->getDestructuring()->visit(this);\n                        --_indent;\n                        --_indent;\n                    }\n                }\n\n                if (fn->isVararg()) {\n                    writeIndentedFmtString(\"Vararg...\\n\");\n                }\n\n                --_indent;\n                if (fn->body()) {\n                    writeIndentedFmtString(\"Body\\n\");\n                    ++_indent;\n                    fn->body()->visit(this);\n                    --_indent;\n                } else {\n                    writeIndentedFmtString(\"Body: <null>\\n\");\n                }\n\n                --_indent;\n                break;\n            }\n\n            case TO_IMPORT: {\n                ImportStmt* imp = static_cast<ImportStmt*>(node);\n                writeIndentedFmtString(\"ImportStmt module '%s'\", imp->moduleName);\n                if (imp->moduleAlias)\n                    writeFmtString(\" as '%s'\", imp->moduleAlias);\n                writeFmtString(\"%s\\n\", loc);\n\n                if (!imp->slots.empty()) {\n                    ++_indent;\n                    for (const SQModuleImportSlot& slot : imp->slots) {\n                        writeIndentedFmtString(\"'%s'\", slot.name);\n                        if (slot.alias)\n                            writeFmtString(\" as '%s'\", slot.alias);\n                        writeFmtString(\"\\n\");\n                    }\n                    --_indent;\n                }\n                break;\n            }\n\n            default: {\n                writeIndentedFmtString(\"ERROR: Unknown node type, op = %d%s\\n\", (int)op, loc);\n                break;\n            }\n        }\n    }\n};\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/CMakeLists.txt",
    "content": "set(COMPILER_SRC\n    ast.cpp\n    compilationcontext.cpp\n    parser.cpp\n    codegen.cpp\n    constgen.cpp\n    sqio.cpp\n    compiler.cpp\n    sqfuncstate.cpp\n    sqdump.cpp\n    optimizer.cpp\n    lexer.cpp\n    sqtypeparser.cpp\n    typeinference.cpp\n    optimizations/closureHoisting.cpp\n    static_analyzer/analyzer.cpp\n    static_analyzer/checker_visitor.cpp\n    static_analyzer/config.cpp\n    static_analyzer/function_ret_type_eval.cpp\n    static_analyzer/global_state.cpp\n    static_analyzer/name_shadowing_checker.cpp\n    static_analyzer/naming.cpp\n    static_analyzer/value_ref.cpp\n    static_analyzer/var_scope.cpp\n)\n\nadd_library(quirrel-compiler STATIC ${COMPILER_SRC})\nadd_library(quirrel::compiler ALIAS quirrel-compiler)\n\n# The compiler needs exceptions for error handling (CompilerError)\ntarget_compile_options(quirrel-compiler PRIVATE\n  \"$<$<CXX_COMPILER_ID:GNU,Clang>:-fexceptions>\"\n  \"$<$<CXX_COMPILER_ID:MSVC>:/EHsc>\"\n)\n\ntarget_include_directories(quirrel-compiler PUBLIC\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\"\n  \"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\"\n  PRIVATE\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/internal>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/helpers>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/squirrel/compiler>\"\n  \"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/squirrel>\"\n  )\n"
  },
  {
    "path": "squirrel/compiler/COPYRIGHT",
    "content": "Copyright (c) 2003-2017 Alberto Demichelis\nCopyright (c) 2016-2024 Gaijin Games KFT\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n-----------------------------------------------------\nEND OF COPYRIGHT\n"
  },
  {
    "path": "squirrel/compiler/arena.h",
    "content": "#pragma once\n\n#include \"squtils.h\"\n\n#include <cstring>\n#include <memory>\n\n#include <map>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n\n#define ALIGN_SIZE(len, align) (((len)+(align - 1)) & ~((align)-1))\n#define ALIGN_SIZE_TO_WORD(len) ALIGN_SIZE(len, 0x8)\n\nclass Arena {\npublic:\n\n    Arena(SQAllocContext alloc_ctx, const char *name, size_t chunkSize = 16<<10)\n        : _alloc_ctx(alloc_ctx), _name(name), _chunks(NULL)\n        , _chunkSize(chunkSize) {\n    }\n\n    Arena(const Arena&) = delete;\n    Arena& operator=(const Arena&) = delete;\n\n    ~Arena() {\n        release();\n    }\n\n    uint8_t *allocate(size_t size) {\n        size = ALIGN_SIZE_TO_WORD(size);\n\n        if (_chunks && size <= _chunks->left())\n            return _chunks->allocate(size);\n\n        // Request doesn't fit in current chunk - allocate new\n        size_t dataSize = (size > _chunkSize) ? size : _chunkSize;\n        size_t totalSize = sizeof(Chunk) + dataSize;\n        uint8_t *block = (uint8_t *)SQ_MALLOC(_alloc_ctx, totalSize);\n        assert(block);\n        uint8_t *data = block + sizeof(Chunk);\n        _chunks = new(block) Chunk(_chunks, data, dataSize, totalSize);\n        return _chunks->allocate(size);\n    }\n\n    bool tryExtend(void *ptr, size_t oldSize, size_t newSize) {\n        if (!_chunks) return false;\n        uint8_t *end = (uint8_t *)ptr + oldSize;\n        if (end == _chunks->_ptr && newSize - oldSize <= _chunks->left()) {\n            _chunks->_ptr += (newSize - oldSize);\n            return true;\n        }\n        return false;\n    }\n\n    void release() {\n        struct Chunk *ch = _chunks;\n        while (ch) {\n            struct Chunk *cur = ch;\n            ch = cur->_next;\n            SQ_FREE(_alloc_ctx, cur, cur->_totalSize);\n        }\n        _chunks = NULL;\n    }\n\nprivate:\n    struct Chunk {\n        struct Chunk *_next;\n        uint8_t *_start;\n        uint8_t *_ptr;\n        size_t _size;\n        size_t _totalSize; // sizeof(Chunk) + _size, for SQ_FREE\n\n        size_t allocated() const { return _ptr - _start; }\n        size_t left() const { return _size - allocated(); }\n\n        Chunk(struct Chunk *n, uint8_t *p, size_t s, size_t total)\n            : _next(n), _start(p), _ptr(p), _size(s), _totalSize(total) {\n        }\n\n        uint8_t *allocate(size_t size) {\n            assert(size <= left());\n            uint8_t *res = _ptr;\n            _ptr += size;\n            return res;\n        }\n    };\n\n    struct Chunk *_chunks;\n    SQAllocContext _alloc_ctx;\n    const char *_name;\n    size_t _chunkSize;\n};\n\n\nclass ArenaObj {\nprotected:\n    ArenaObj() = default;\n    ~ArenaObj() = default;\n\nprivate:\n    void *operator new(size_t /*size*/) = delete;\n\npublic:\n    void *operator new(size_t size, Arena *arena) {\n        return arena->allocate(size);\n    }\n\n    void operator delete(void * /*p*/, Arena * /*arena*/) { }\n    void operator delete(void * /*p*/) { }\n};\n\n\ntemplate<typename T>\nclass ArenaVector {\npublic:\n    using size_type = uint32_t;\n\n    ArenaVector(Arena *arena)\n        : _arena(arena)\n        , _vals(NULL)\n        , _size(0)\n        , _allocated(0)\n    {\n    }\n\n    // Implement if needed\n    ArenaVector(const ArenaVector&) = delete;\n    ArenaVector& operator=(const ArenaVector&) = delete;\n\n    ArenaVector(ArenaVector&& other) noexcept\n        : _arena(other._arena)\n        , _vals(other._vals)\n        , _size(other._size)\n        , _allocated(other._allocated)\n    {\n        other._vals = nullptr;\n        other._size = 0;\n        other._allocated = 0;\n    }\n\n    inline T &push_back(const T& val)\n    {\n        if (_allocated <= _size)\n            _realloc(_size * 2);\n        return *(new ((void *)&_vals[_size++]) T(val));\n    }\n    inline void pop_back()\n    {\n        _size--; _vals[_size].~T();\n    }\n\n    T& top() const { return _vals[_size - 1]; }\n    inline size_type size() const { return _size; }\n    bool empty() const { return (_size == 0); }\n\n    inline T &back() const { return _vals[_size - 1]; }\n    inline T& operator[](size_type pos) const { return _vals[pos]; }\n\n    void insert(size_type pos, T v) {\n      assert(pos <= _size);\n      if (_allocated <= _size) _realloc(_size * 2);\n      memmove(&_vals[pos + 1], &_vals[pos], (_size - pos) * sizeof(T));\n      new ((void *)&_vals[pos]) T(v);\n      _size += 1;\n    }\n\n    typedef T* iterator;\n    typedef const T* const_iterator;\n\n    iterator begin() { return _vals; }\n    const_iterator begin() const { return _vals; }\n    iterator end() { return _vals + _size; }\n    const_iterator end() const { return _vals + _size; }\n\n    void reserve(size_type newSize) {\n      if (newSize <= _allocated) return;\n      _realloc(newSize);\n    }\n\nprivate:\n\n    void _realloc(size_type newsize)\n    {\n        newsize = (newsize > 0) ? newsize : 4;\n        size_t newBytes = newsize * sizeof(T);\n        if (_vals) {\n            size_t oldBytes = ALIGN_SIZE_TO_WORD(_allocated * sizeof(T));\n            if (_arena->tryExtend(_vals, oldBytes, ALIGN_SIZE_TO_WORD(newBytes))) {\n                _allocated = newsize;\n                return;\n            }\n            T *newPtr = (T *)_arena->allocate(newBytes);\n            memcpy(newPtr, _vals, _size * sizeof(T));\n            _vals = newPtr;\n        } else {\n            _vals = (T *)_arena->allocate(newBytes);\n        }\n        _allocated = newsize;\n    }\n\n    Arena *_arena;\n\n    T *_vals;\n\n    size_type _size;\n    size_type _allocated;\n};\n\ntemplate <typename T>\nclass StdArenaAllocator {\npublic:\n  Arena *_arena;\n  typedef size_t size_type;\n  typedef T* pointer;\n  typedef const T* const_pointer;\n  typedef T value_type;\n\n  pointer allocate(const size_type n)\n  {\n    return (pointer)_arena->allocate(n * sizeof(T));\n  }\n\n  pointer allocate(const size_type n, const void *hint)\n  {\n    return allocate(n);\n  }\n\n  void deallocate(const_pointer p, const size_type n) {}\n\n  template<typename U>\n  bool operator==(const StdArenaAllocator<U> &other) const { return _arena == other._arena; }\n  template<typename U>\n  bool operator!=(const StdArenaAllocator<U> &other) const { return _arena != other._arena; }\n\n  template<typename O>\n  StdArenaAllocator(const StdArenaAllocator<O> &a) : StdArenaAllocator(a._arena) {}\n  StdArenaAllocator(Arena *arena) : _arena(arena) { assert(arena); }\n  ~StdArenaAllocator() {}\n};\n\ntemplate<typename K, typename V, typename Cmp = std::less<K>>\nstruct ArenaMap : public std::map<K, V, Cmp, StdArenaAllocator<std::pair<const K, V>>> {\n\n  typedef StdArenaAllocator<std::pair<const K, V>> Allocator;\n\n  ArenaMap(const Allocator &allocator) : std::map<K, V, Cmp, Allocator>(allocator) {}\n};\n\ntemplate<typename V, typename Cmp = std::less<V>>\nstruct ArenaSet : public std::set<V, Cmp, StdArenaAllocator<V>> {\n\n  typedef StdArenaAllocator<V> Allocator;\n\n  ArenaSet(const Allocator &allocator) : std::set<V, Cmp, Allocator>(allocator) {}\n};\n\ntemplate<typename V, typename Hasher = std::hash<V>, typename KeyEq = std::equal_to<V>>\nstruct ArenaUnorderedSet : public std::unordered_set<V, Hasher, KeyEq, StdArenaAllocator<V>> {\n\n  typedef StdArenaAllocator<V> Allocator;\n\n  ArenaUnorderedSet(const Allocator &allocator) : std::unordered_set<V, Hasher, KeyEq, Allocator>(allocator) {}\n};\n\ntemplate<typename K, typename V, typename Hasher = std::hash<K>, typename KeyEq = std::equal_to<K>>\nstruct ArenaUnorderedMap : public std::unordered_map<K, V, Hasher, KeyEq, StdArenaAllocator<std::pair<const K, V>>> {\n\n  typedef StdArenaAllocator<std::pair<const K, V>> Allocator;\n\n  ArenaUnorderedMap(const Allocator &allocator) : std::unordered_map<K, V, Hasher, KeyEq, Allocator>(allocator) {}\n};\n"
  },
  {
    "path": "squirrel/compiler/ast.cpp",
    "content": "#include \"ast.h\"\n\nnamespace SQCompilation {\n\n#define DEF_TREE_OP(arg) #arg\n\nconst char* sq_tree_op_names[] = {\n    TREE_OPS\n};\n#undef DEF_TREE_OP\n\n\nvoid Node::visitChildren(Visitor *visitor) {\n    switch (op())\n    {\n    case TO_BLOCK:      static_cast<Block *>(this)->visitChildren(visitor); return;\n    case TO_IF:         static_cast<IfStatement *>(this)->visitChildren(visitor); return;\n    case TO_WHILE:      static_cast<WhileStatement *>(this)->visitChildren(visitor); return;\n    case TO_DOWHILE:    static_cast<DoWhileStatement *>(this)->visitChildren(visitor); return;\n    case TO_FOR:        static_cast<ForStatement *>(this)->visitChildren(visitor); return;\n    case TO_FOREACH:    static_cast<ForeachStatement *>(this)->visitChildren(visitor); return;\n    case TO_SWITCH:     static_cast<SwitchStatement *>(this)->visitChildren(visitor); return;\n    case TO_RETURN:     static_cast<ReturnStatement *>(this)->visitChildren(visitor); return;\n    case TO_YIELD:      static_cast<YieldStatement *>(this)->visitChildren(visitor); return;\n    case TO_THROW:      static_cast<ThrowStatement *>(this)->visitChildren(visitor); return;\n    case TO_TRY:        static_cast<TryStatement *>(this)->visitChildren(visitor); return;\n    case TO_BREAK:      static_cast<BreakStatement *>(this)->visitChildren(visitor); return;\n    case TO_CONTINUE:   static_cast<ContinueStatement *>(this)->visitChildren(visitor); return;\n    case TO_EXPR_STMT:  static_cast<ExprStatement *>(this)->visitChildren(visitor); return;\n    case TO_EMPTY:      static_cast<EmptyStatement *>(this)->visitChildren(visitor); return;\n        //case TO_STATEMENT_MARK:\n    case TO_ID:         static_cast<Id *>(this)->visitChildren(visitor); return;\n    case TO_COMMA:      static_cast<CommaExpr *>(this)->visitChildren(visitor); return;\n    case TO_NULLC:\n    case TO_ASSIGN:\n    case TO_OROR:\n    case TO_ANDAND:\n    case TO_OR:\n    case TO_XOR:\n    case TO_AND:\n    case TO_NE:\n    case TO_EQ:\n    case TO_3CMP:\n    case TO_GE:\n    case TO_GT:\n    case TO_LE:\n    case TO_LT:\n    case TO_IN:\n    case TO_INSTANCEOF:\n    case TO_USHR:\n    case TO_SHR:\n    case TO_SHL:\n    case TO_MUL:\n    case TO_DIV:\n    case TO_MOD:\n    case TO_ADD:\n    case TO_SUB:\n    case TO_NEWSLOT:\n    case TO_PLUSEQ:\n    case TO_MINUSEQ:\n    case TO_MULEQ:\n    case TO_DIVEQ:\n    case TO_MODEQ:\n        static_cast<BinExpr *>(this)->visitChildren(visitor); return;\n    case TO_NOT:\n    case TO_BNOT:\n    case TO_NEG:\n    case TO_TYPEOF:\n    case TO_RESUME:\n    case TO_CLONE:\n    case TO_PAREN:\n    case TO_DELETE:\n    case TO_STATIC_MEMO:\n    case TO_INLINE_CONST:\n        static_cast<UnExpr *>(this)->visitChildren(visitor); return;\n    case TO_CODE_BLOCK_EXPR:\n        static_cast<CodeBlockExpr *>(this)->visitChildren(visitor); return;\n    case TO_LITERAL:\n        static_cast<LiteralExpr *>(this)->visitChildren(visitor); return;\n    case TO_BASE:\n        static_cast<BaseExpr *>(this)->visitChildren(visitor); return;\n    case TO_ROOT_TABLE_ACCESS:\n        static_cast<RootTableAccessExpr *>(this)->visitChildren(visitor); return;\n    case TO_INC:\n        static_cast<IncExpr *>(this)->visitChildren(visitor); return;\n    case TO_TABLE:\n        static_cast<TableExpr *>(this)->visitChildren(visitor); return;\n    case TO_CLASS:\n        static_cast<ClassExpr *>(this)->visitChildren(visitor); return;\n    case TO_FUNCTION:\n        static_cast<FunctionExpr *>(this)->visitChildren(visitor); return;\n    case TO_ARRAY:\n        static_cast<ArrayExpr *>(this)->visitChildren(visitor); return;\n    case TO_GETFIELD:\n        static_cast<GetFieldExpr *>(this)->visitChildren(visitor); return;\n    case TO_SETFIELD:\n        static_cast<SetFieldExpr *>(this)->visitChildren(visitor); return;\n    case TO_GETSLOT:\n        static_cast<GetSlotExpr *>(this)->visitChildren(visitor); return;\n    case TO_SETSLOT:\n        static_cast<SetSlotExpr *>(this)->visitChildren(visitor); return;\n    case TO_CALL:\n        static_cast<CallExpr *>(this)->visitChildren(visitor); return;\n    case TO_TERNARY:\n        static_cast<TerExpr *>(this)->visitChildren(visitor); return;\n        //case TO_EXPR_MARK:\n    case TO_VAR:\n        static_cast<VarDecl *>(this)->visitChildren(visitor); return;\n    case TO_PARAM:\n        static_cast<ParamDecl *>(this)->visitChildren(visitor); return;\n    case TO_CONST:\n        static_cast<ConstDecl *>(this)->visitChildren(visitor); return;\n    case TO_DECL_GROUP:\n        static_cast<DeclGroup *>(this)->visitChildren(visitor); return;\n    case TO_DESTRUCTURE:\n        static_cast<DestructuringDecl *>(this)->visitChildren(visitor); return;\n    case TO_ENUM:\n        static_cast<EnumDecl *>(this)->visitChildren(visitor); return;\n    default:\n        break;\n    }\n}\n\nvoid Node::transformChildren(Transformer *transformer) {\n  switch (op())\n  {\n  case TO_BLOCK:      static_cast<Block *>(this)->transformChildren(transformer); return;\n  case TO_IF:         static_cast<IfStatement *>(this)->transformChildren(transformer); return;\n  case TO_WHILE:      static_cast<WhileStatement *>(this)->transformChildren(transformer); return;\n  case TO_DOWHILE:    static_cast<DoWhileStatement *>(this)->transformChildren(transformer); return;\n  case TO_FOR:        static_cast<ForStatement *>(this)->transformChildren(transformer); return;\n  case TO_FOREACH:    static_cast<ForeachStatement *>(this)->transformChildren(transformer); return;\n  case TO_SWITCH:     static_cast<SwitchStatement *>(this)->transformChildren(transformer); return;\n  case TO_RETURN:     static_cast<ReturnStatement *>(this)->transformChildren(transformer); return;\n  case TO_YIELD:      static_cast<YieldStatement *>(this)->transformChildren(transformer); return;\n  case TO_THROW:      static_cast<ThrowStatement *>(this)->transformChildren(transformer); return;\n  case TO_TRY:        static_cast<TryStatement *>(this)->transformChildren(transformer); return;\n  case TO_BREAK:      static_cast<BreakStatement *>(this)->transformChildren(transformer); return;\n  case TO_CONTINUE:   static_cast<ContinueStatement *>(this)->transformChildren(transformer); return;\n  case TO_EXPR_STMT:  static_cast<ExprStatement *>(this)->transformChildren(transformer); return;\n  case TO_EMPTY:      static_cast<EmptyStatement *>(this)->transformChildren(transformer); return;\n    //case TO_STATEMENT_MARK:\n  case TO_ID:         static_cast<Id *>(this)->transformChildren(transformer); return;\n  case TO_COMMA:      static_cast<CommaExpr *>(this)->transformChildren(transformer); return;\n  case TO_NULLC:\n  case TO_ASSIGN:\n  case TO_OROR:\n  case TO_ANDAND:\n  case TO_OR:\n  case TO_XOR:\n  case TO_AND:\n  case TO_NE:\n  case TO_EQ:\n  case TO_3CMP:\n  case TO_GE:\n  case TO_GT:\n  case TO_LE:\n  case TO_LT:\n  case TO_IN:\n  case TO_INSTANCEOF:\n  case TO_USHR:\n  case TO_SHR:\n  case TO_SHL:\n  case TO_MUL:\n  case TO_DIV:\n  case TO_MOD:\n  case TO_ADD:\n  case TO_SUB:\n  case TO_NEWSLOT:\n  case TO_PLUSEQ:\n  case TO_MINUSEQ:\n  case TO_MULEQ:\n  case TO_DIVEQ:\n  case TO_MODEQ:\n    static_cast<BinExpr *>(this)->transformChildren(transformer); return;\n  case TO_NOT:\n  case TO_BNOT:\n  case TO_NEG:\n  case TO_TYPEOF:\n  case TO_RESUME:\n  case TO_CLONE:\n  case TO_PAREN:\n  case TO_DELETE:\n  case TO_STATIC_MEMO:\n  case TO_INLINE_CONST:\n    static_cast<UnExpr *>(this)->transformChildren(transformer); return;\n  case TO_CODE_BLOCK_EXPR:\n    static_cast<CodeBlockExpr *>(this)->transformChildren(transformer); return;\n  case TO_LITERAL:\n    static_cast<LiteralExpr *>(this)->transformChildren(transformer); return;\n  case TO_BASE:\n    static_cast<BaseExpr *>(this)->transformChildren(transformer); return;\n  case TO_ROOT_TABLE_ACCESS:\n    static_cast<RootTableAccessExpr *>(this)->transformChildren(transformer); return;\n  case TO_INC:\n    static_cast<IncExpr *>(this)->transformChildren(transformer); return;\n  case TO_TABLE:\n    static_cast<TableExpr *>(this)->transformChildren(transformer); return;\n  case TO_CLASS:\n    static_cast<ClassExpr *>(this)->transformChildren(transformer); return;\n  case TO_FUNCTION:\n    static_cast<FunctionExpr *>(this)->transformChildren(transformer); return;\n  case TO_ARRAY:\n    static_cast<ArrayExpr *>(this)->transformChildren(transformer); return;\n  case TO_GETFIELD:\n    static_cast<GetFieldExpr *>(this)->transformChildren(transformer); return;\n  case TO_SETFIELD:\n    static_cast<SetFieldExpr *>(this)->transformChildren(transformer); return;\n  case TO_GETSLOT:\n    static_cast<GetSlotExpr *>(this)->transformChildren(transformer); return;\n  case TO_SETSLOT:\n    static_cast<SetSlotExpr *>(this)->transformChildren(transformer); return;\n  case TO_CALL:\n    static_cast<CallExpr *>(this)->transformChildren(transformer); return;\n  case TO_TERNARY:\n    static_cast<TerExpr *>(this)->transformChildren(transformer); return;\n    //case TO_EXPR_MARK:\n  case TO_VAR:\n    static_cast<VarDecl *>(this)->transformChildren(transformer); return;\n  case TO_PARAM:\n    static_cast<ParamDecl *>(this)->transformChildren(transformer); return;\n  case TO_CONST:\n    static_cast<ConstDecl *>(this)->transformChildren(transformer); return;\n  case TO_DECL_GROUP:\n    static_cast<DeclGroup *>(this)->transformChildren(transformer); return;\n  case TO_DESTRUCTURE:\n    static_cast<DestructuringDecl *>(this)->transformChildren(transformer); return;\n  case TO_ENUM:\n    static_cast<EnumDecl *>(this)->transformChildren(transformer); return;\n  default:\n    break;\n  }\n}\n\nvoid UnExpr::visitChildren(Visitor *visitor) { _arg->visit(visitor); }\n\nvoid UnExpr::transformChildren(Transformer *transformer) {\n  _arg = _arg->transform(transformer)->asExpression();\n}\n\nvoid CodeBlockExpr::visitChildren(Visitor *visitor) { _block->visit(visitor); }\n\nvoid CodeBlockExpr::transformChildren(Transformer *transformer) {\n  _block = static_cast<Block *>(_block->transform(transformer));\n  assert(_block->op() == TO_BLOCK);\n}\n\nvoid BinExpr::visitChildren(Visitor *visitor) {\n    _lhs->visit(visitor);\n    _rhs->visit(visitor);\n}\n\nvoid BinExpr::transformChildren(Transformer *transformer) {\n  _lhs = _lhs->transform(transformer)->asExpression();\n  _rhs = _rhs->transform(transformer)->asExpression();\n}\n\nvoid TerExpr::visitChildren(Visitor *visitor) {\n    _a->visit(visitor);\n    _b->visit(visitor);\n    _c->visit(visitor);\n}\n\nvoid TerExpr::transformChildren(Transformer *transformer) {\n  _a = _a->transform(transformer)->asExpression();\n  _b = _b->transform(transformer)->asExpression();\n  _c = _c->transform(transformer)->asExpression();\n}\n\nvoid GetFieldExpr::visitChildren(Visitor *visitor) {\n    receiver()->visit(visitor);\n}\n\nvoid GetFieldExpr::transformChildren(Transformer *transformer) {\n  _receiver = receiver()->transform(transformer)->asExpression();\n}\n\nvoid SetFieldExpr::visitChildren(Visitor *visitor) {\n    receiver()->visit(visitor);\n    value()->visit(visitor);\n}\n\nvoid SetFieldExpr::transformChildren(Transformer *transformer) {\n  _receiver = receiver()->transform(transformer)->asExpression();\n  _value = value()->transform(transformer)->asExpression();\n}\n\nvoid GetSlotExpr::visitChildren(Visitor *visitor) {\n    receiver()->visit(visitor);\n    key()->visit(visitor);\n}\n\nvoid GetSlotExpr::transformChildren(Transformer *transformer) {\n  _receiver = receiver()->transform(transformer)->asExpression();\n  _key = key()->transform(transformer)->asExpression();\n}\n\nvoid SetSlotExpr::visitChildren(Visitor *visitor) {\n    receiver()->visit(visitor);\n    key()->visit(visitor);\n    value()->visit(visitor);\n}\n\nvoid SetSlotExpr::transformChildren(Transformer *transformer) {\n  _receiver = receiver()->transform(transformer)->asExpression();\n  _key = key()->transform(transformer)->asExpression();\n  _val = value()->transform(transformer)->asExpression();\n}\n\nvoid IncExpr::visitChildren(Visitor *visitor) { _arg->visit(visitor); }\n\nvoid IncExpr::transformChildren(Transformer *transformer) {\n  _arg = _arg->transform(transformer)->asExpression();\n}\n\nvoid CallExpr::visitChildren(Visitor *visitor) {\n    _callee->visit(visitor);\n    for (auto arg : arguments())\n        arg->visit(visitor);\n}\n\nvoid CallExpr::transformChildren(Transformer *transformer) {\n  _callee = _callee->transform(transformer)->asExpression();\n\n  for (auto &arg : arguments())\n    arg = arg->transform(transformer)->asExpression();\n}\n\nvoid ArrayExpr::visitChildren(Visitor *visitor) {\n    for (auto init : initializers())\n        init->visit(visitor);\n}\n\nvoid ArrayExpr::transformChildren(Transformer *transformer) {\n  for (auto &init : initializers())\n    init = init->transform(transformer)->asExpression();\n}\n\nvoid CommaExpr::visitChildren(Visitor *visitor) {\n    for (auto expr : expressions())\n        expr->visit(visitor);\n}\n\nvoid CommaExpr::transformChildren(Transformer *transformer) {\n  for (auto &expr : expressions())\n    expr = expr->transform(transformer)->asExpression();\n}\n\nvoid ValueDecl::visitChildren(Visitor *visitor) {\n    if (_expr) _expr->visit(visitor);\n}\n\nvoid ValueDecl::transformChildren(Transformer *transformer) {\n  if (_expr) {\n    _expr = _expr->transform(transformer)->asExpression();\n  }\n}\n\nvoid TableExpr::visitChildren(Visitor *visitor) {\n    for (auto &member : members()) {\n        member.key->visit(visitor);\n        member.value->visit(visitor);\n    }\n}\n\nvoid TableExpr::transformChildren(Transformer *transformer) {\n  for (auto &member : members()) {\n    member.key = member.key->transform(transformer)->asExpression();\n    member.value = member.value->transform(transformer)->asExpression();\n  }\n}\n\nvoid ClassExpr::visitChildren(Visitor *visitor)  {\n    if (_key) _key->visit(visitor);\n    if (_base) _base->visit(visitor);\n    TableExpr::visitChildren(visitor);\n}\n\nvoid ClassExpr::transformChildren(Transformer *transformer) {\n  if (_key) _key = _key->transform(transformer)->asExpression();\n  if (_base) _base = _base->transform(transformer)->asExpression();\n  TableExpr::transformChildren(transformer);\n}\n\nvoid FunctionExpr::visitChildren(Visitor *visitor) {\n    for (auto param : parameters())\n        param->visit(visitor);\n\n    for (auto param : parameters())\n       if (param->getDestructuring())\n           param->getDestructuring()->visit(visitor);\n\n    body()->visit(visitor);\n}\n\nvoid FunctionExpr::transformChildren(Transformer *transformer) {\n  for (auto &param : parameters()) {\n    param = param->transform(transformer)->asDeclaration()->asParam();\n  }\n\n  for (auto param : parameters())\n    if (param->getDestructuring())\n      param->setDestructuring(param->getDestructuring()->transform(transformer)->asDestructuringDecl());\n\n  setBody(body()->transform(transformer)->asStatement()->asBlock());\n}\n\nvoid FunctionExpr::setBody(Block *body) {\n    _body = body;\n    body->setIsBody();\n    setSpanEnd(body->sourceSpan().end);\n}\n\nFunctionExpr *ClassExpr::findConstructor() const {\n  for (const auto &m : members()) {\n    if (m.value->op() == TO_FUNCTION) {\n      FunctionExpr *f = m.value->asFunctionExpr();\n      if (f->name() && strcmp(f->name(), \"constructor\") == 0)\n        return f;\n    }\n  }\n  return nullptr;\n}\n\nvoid ConstDecl::visitChildren(Visitor *visitor) {\n  _value->visit(visitor);\n}\n\nvoid ConstDecl::transformChildren(Transformer *transformer) {\n  _value = _value->transform(transformer)->asExpression();\n}\n\nvoid DeclGroup::visitChildren(Visitor *visitor) {\n    for (auto decl : declarations())\n        decl->visit(visitor);\n}\n\nvoid DeclGroup::transformChildren(Transformer *transformer) {\n\n  for (auto &decl : declarations())\n    decl = decl->transform(transformer)->asDeclaration()->asVarDecl();\n}\n\nvoid DestructuringDecl::visitChildren(Visitor *visitor) {\n    DeclGroup::visitChildren(visitor);\n    _expr->visit(visitor);\n}\n\nvoid DestructuringDecl::transformChildren(Transformer *transformer) {\n  DeclGroup::transformChildren(transformer);\n  _expr = _expr->transform(transformer)->asExpression();\n}\n\nvoid Block::visitChildren(Visitor *visitor) {\n\n    for (auto stmt : statements())\n        stmt->visit(visitor);\n}\n\nvoid Block::transformChildren(Transformer *transformer) {\n\n  for (auto &stmt : statements())\n    stmt = stmt->transform(transformer)->asStatement();\n}\n\nvoid IfStatement::visitChildren(Visitor *visitor) {\n    _cond->visit(visitor);\n    _thenB->visit(visitor);\n    if (_elseB) _elseB->visit(visitor);\n}\n\nvoid IfStatement::transformChildren(Transformer *transformer) {\n  _cond = _cond->transform(transformer)->asExpression();\n  _thenB = _thenB->transform(transformer)->asStatement();\n  if (_elseB) _elseB = _elseB->transform(transformer)->asStatement();\n}\n\nvoid LoopStatement::visitChildren(Visitor *visitor) {\n    _body->visit(visitor);\n}\n\nvoid LoopStatement::transformChildren(Transformer *transformer) {\n  _body = _body->transform(transformer)->asStatement();\n}\n\nvoid WhileStatement::visitChildren(Visitor *visitor) {\n    _cond->visit(visitor);\n    LoopStatement::visitChildren(visitor);\n}\n\nvoid WhileStatement::transformChildren(Transformer *transformer) {\n  _cond = _cond->transform(transformer)->asExpression();\n  LoopStatement::transformChildren(transformer);\n}\n\nvoid DoWhileStatement::visitChildren(Visitor *visitor) {\n    LoopStatement::visitChildren(visitor);\n    _cond->visit(visitor);\n}\n\nvoid DoWhileStatement::transformChildren(Transformer *transformer) {\n  LoopStatement::transformChildren(transformer);\n  _cond = _cond->transform(transformer)->asExpression();\n}\n\nvoid ForStatement::visitChildren(Visitor *visitor) {\n    if (_init) _init->visit(visitor);\n    if (_cond) _cond->visit(visitor);\n    if (_mod) _mod->visit(visitor);\n\n    LoopStatement::visitChildren(visitor);\n}\n\nvoid ForStatement::transformChildren(Transformer *transformer) {\n  if (_init) _init = _init->transform(transformer);\n  if (_cond) _cond = _cond->transform(transformer)->asExpression();\n  if (_mod) _mod = _mod->transform(transformer)->asExpression();\n\n  LoopStatement::transformChildren(transformer);\n}\n\nvoid ForeachStatement::visitChildren(Visitor *visitor) {\n    if (_idx) _idx->visit(visitor);\n    if (_val) _val->visit(visitor);\n    if (_container) _container->visit(visitor);\n\n    LoopStatement::visitChildren(visitor);\n}\n\nvoid ForeachStatement::transformChildren(Transformer *transformer) {\n  if (_idx) _idx = _idx->transform(transformer)->asDeclaration()->asVarDecl();\n  if (_val) _val = _val->transform(transformer)->asDeclaration()->asVarDecl();\n  if (_container) _container = _container->transform(transformer)->asExpression();\n\n  LoopStatement::transformChildren(transformer);\n}\n\nvoid SwitchStatement::visitChildren(Visitor *visitor) {\n    _expr->visit(visitor);\n\n    for (auto &c : cases()) {\n        c.val->visit(visitor);\n        c.stmt->visit(visitor);\n    }\n\n    if (_defaultCase.stmt) {\n        _defaultCase.stmt->visit(visitor);\n    }\n}\n\nvoid SwitchStatement::transformChildren(Transformer *transformer) {\n  _expr = _expr->transform(transformer)->asExpression();\n\n  for (auto &c : cases()) {\n    c.val = c.val->transform(transformer)->asExpression();\n    c.stmt = c.stmt->transform(transformer)->asStatement();\n  }\n\n  if (_defaultCase.stmt) {\n    _defaultCase.stmt = _defaultCase.stmt->transform(transformer)->asStatement();\n  }\n}\n\nvoid TryStatement::visitChildren(Visitor *visitor) {\n    _tryStmt->visit(visitor);\n    visitor->visitId(_exception);\n    _catchStmt->visit(visitor);\n}\n\nvoid TryStatement::transformChildren(Transformer *transformer) {\n  _tryStmt = _tryStmt->transform(transformer)->asStatement();\n  _exception = _exception->transform(transformer)->asId();\n  _catchStmt = _catchStmt->transform(transformer)->asStatement();\n}\n\nvoid TerminateStatement::visitChildren(Visitor *visitor) {\n    if (_arg) _arg->visit(visitor);\n}\n\nvoid TerminateStatement::transformChildren(Transformer *transformer) {\n  if (_arg) _arg = _arg->transform(transformer)->asExpression();\n}\n\nvoid ExprStatement::visitChildren(Visitor *visitor) { _expr->visit(visitor); }\n\nvoid ExprStatement::transformChildren(Transformer *transformer) {\n  _expr = _expr->transform(transformer)->asExpression();\n}\n\nconst char* treeopStr(enum TreeOp op) {\n  switch (op)\n  {\n  case TO_NULLC: return \"??\";\n  case TO_ASSIGN: return \"=\";\n  case TO_OROR: return \"||\";\n  case TO_ANDAND: return \"&&\";\n  case TO_OR: return \"|\";\n  case TO_XOR: return \"^\";\n  case TO_AND: return \"&\";\n  case TO_NE: return \"!=\";\n  case TO_EQ: return \"==\";\n  case TO_3CMP: return \"<=>\";\n  case TO_GE: return \">=\";\n  case TO_GT: return \">\";\n  case TO_LE: return \"<=\";\n  case TO_LT: return \"<\";\n  case TO_USHR: return \">>>\";\n  case TO_SHR: return \">>\";\n  case TO_SHL: return \"<<\";\n  case TO_MUL: return \"*\";\n  case TO_DIV: return \"/\";\n  case TO_MOD: return \"%\";\n  case TO_ADD: return \"+\";\n  case TO_SUB:\n  case TO_NEG: return \"-\";\n  case TO_NOT: return \"!\";\n  case TO_BNOT: return \"~\";\n  case TO_NEWSLOT: return \"<-\";\n  case TO_PLUSEQ: return \"+=\";\n  case TO_MINUSEQ: return \"-=\";\n  case TO_MULEQ: return \"*=\";\n  case TO_DIVEQ: return \"/=\";\n  case TO_MODEQ: return \"%=\";\n  default: return nullptr;\n  }\n}\n\n};\n"
  },
  {
    "path": "squirrel/compiler/ast.h",
    "content": "#pragma once\n\n#include <assert.h>\n#include \"squirrel.h\"\n#include \"squtils.h\"\n#include \"arena.h\"\n#include \"sqobject.h\"\n#include \"sourceloc.h\"\n\n// NOTE: There are some checkers that rely on the order of this list so re-arrange it carefully\n\n#define TREE_OPS \\\n    DEF_TREE_OP(BLOCK), \\\n    DEF_TREE_OP(IF), \\\n    DEF_TREE_OP(WHILE), \\\n    DEF_TREE_OP(DOWHILE), \\\n    DEF_TREE_OP(FOR), \\\n    DEF_TREE_OP(FOREACH), \\\n    DEF_TREE_OP(SWITCH), \\\n    DEF_TREE_OP(RETURN), \\\n    DEF_TREE_OP(YIELD), \\\n    DEF_TREE_OP(THROW), \\\n    DEF_TREE_OP(TRY), \\\n    DEF_TREE_OP(BREAK), \\\n    DEF_TREE_OP(CONTINUE), \\\n    DEF_TREE_OP(EXPR_STMT), \\\n    DEF_TREE_OP(EMPTY), \\\n    DEF_TREE_OP(DIRECTIVE), \\\n    DEF_TREE_OP(IMPORT), \\\n    \\\n    DEF_TREE_OP(STATEMENT_MARK), \\\n    \\\n    DEF_TREE_OP(ID), \\\n    DEF_TREE_OP(COMMA), \\\n    DEF_TREE_OP(NULLC), \\\n    DEF_TREE_OP(ASSIGN), \\\n    DEF_TREE_OP(OROR), \\\n    DEF_TREE_OP(ANDAND), \\\n    DEF_TREE_OP(OR), \\\n    DEF_TREE_OP(XOR), \\\n    DEF_TREE_OP(AND), \\\n    DEF_TREE_OP(NE), \\\n    DEF_TREE_OP(EQ), \\\n    DEF_TREE_OP(3CMP), \\\n    DEF_TREE_OP(GE), \\\n    DEF_TREE_OP(GT), \\\n    DEF_TREE_OP(LE), \\\n    DEF_TREE_OP(LT), \\\n    DEF_TREE_OP(IN), \\\n    DEF_TREE_OP(INSTANCEOF), \\\n    DEF_TREE_OP(USHR), \\\n    DEF_TREE_OP(SHR), \\\n    DEF_TREE_OP(SHL), \\\n    DEF_TREE_OP(MUL), \\\n    DEF_TREE_OP(DIV), \\\n    DEF_TREE_OP(MOD), \\\n    DEF_TREE_OP(ADD), \\\n    DEF_TREE_OP(SUB), \\\n    DEF_TREE_OP(NEWSLOT), \\\n    DEF_TREE_OP(PLUSEQ), \\\n    DEF_TREE_OP(MINUSEQ), \\\n    DEF_TREE_OP(MULEQ), \\\n    DEF_TREE_OP(DIVEQ), \\\n    DEF_TREE_OP(MODEQ), \\\n    DEF_TREE_OP(NOT), \\\n    DEF_TREE_OP(BNOT), \\\n    DEF_TREE_OP(NEG), \\\n    DEF_TREE_OP(TYPEOF), \\\n    DEF_TREE_OP(STATIC_MEMO), \\\n    DEF_TREE_OP(INLINE_CONST), \\\n    DEF_TREE_OP(RESUME), \\\n    DEF_TREE_OP(CLONE), \\\n    DEF_TREE_OP(PAREN), \\\n    DEF_TREE_OP(CODE_BLOCK_EXPR), \\\n    DEF_TREE_OP(DELETE), \\\n    DEF_TREE_OP(LITERAL), \\\n    DEF_TREE_OP(BASE), \\\n    DEF_TREE_OP(ROOT_TABLE_ACCESS), \\\n    DEF_TREE_OP(INC), \\\n    DEF_TREE_OP(ARRAY), \\\n    DEF_TREE_OP(TABLE), \\\n    DEF_TREE_OP(CLASS), \\\n    DEF_TREE_OP(FUNCTION), \\\n    DEF_TREE_OP(GETFIELD), \\\n    DEF_TREE_OP(SETFIELD), \\\n    DEF_TREE_OP(GETSLOT), \\\n    DEF_TREE_OP(SETSLOT), \\\n    DEF_TREE_OP(CALL), \\\n    DEF_TREE_OP(TERNARY), \\\n    DEF_TREE_OP(EXTERNAL_VALUE), \\\n    \\\n    DEF_TREE_OP(EXPR_MARK), \\\n    \\\n    DEF_TREE_OP(VAR), \\\n    DEF_TREE_OP(PARAM), \\\n    DEF_TREE_OP(CONST), \\\n    DEF_TREE_OP(DECL_GROUP), \\\n    DEF_TREE_OP(DESTRUCTURE), \\\n    DEF_TREE_OP(ENUM), \\\n    DEF_TREE_OP(DECLARATION_MARK), \\\n\nenum TreeOp {\n#define DEF_TREE_OP(arg) TO_##arg\n    TREE_OPS\n#undef DEF_TREE_OP\n\n};\n\nnamespace SQCompilation {\n\nextern const char* sq_tree_op_names[];\n\n\nclass Visitor;\nclass Transformer;\n\nclass Expr;\nclass Statement;\nclass Decl;\nclass DestructuringDecl;\n\nclass Id;\nclass GetFieldExpr;\nclass GetSlotExpr;\n\n\nclass Node : public ArenaObj {\nprotected:\n    Node(enum TreeOp op, SourceSpan span) : _op(op), _span(span) {}\n\npublic:\n    ~Node() {}\n\n    enum TreeOp op() const { return _op; }\n\n    template<typename V>\n    void visit(V *visitor);\n\n    template<typename T>\n    Node *transform(T *transformer);\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    bool isDeclaration() const { return TO_EXPR_MARK < op() && op() < TO_DECLARATION_MARK; }\n    bool isStatement() const { return _op < TO_STATEMENT_MARK; }\n    bool isExpression() const { return TO_STATEMENT_MARK < _op && _op < TO_EXPR_MARK; }\n    bool isStatementOrDeclaration() const { return isStatement() || isDeclaration(); }\n\n    inline Expr *asExpression() const { assert(isExpression()); return (Expr *)(this); }\n    inline Statement *asStatement() const { assert(isStatement() || isDeclaration()); return (Statement *)(this); }\n    inline Decl *asDeclaration() const { assert(isDeclaration()); return (Decl *)(this); }\n\n    Id *asId() { assert(_op == TO_ID); return (Id*)this; }\n    const Id *asId() const { assert(_op == TO_ID); return (const Id*)this; }\n    GetFieldExpr *asGetField() const { assert(_op == TO_GETFIELD); return (GetFieldExpr*)this; }\n    GetSlotExpr *asGetSlot() const { assert(_op == TO_GETSLOT); return (GetSlotExpr*)this; }\n    DestructuringDecl *asDestructuringDecl() const { assert(_op == TO_DESTRUCTURE); return (DestructuringDecl*)this; }\n\n    SourceSpan sourceSpan() const { return _span; }\n\n    // Only for incrementally-built nodes\n    void setSpanEnd(SourceLoc end) { _span.end = end; }\n\n    // Convenience accessors\n    int lineStart() const { return _span.start.line; }\n    int lineEnd() const { return _span.end.line; }\n    int columnStart() const { return _span.start.column; }\n    int columnEnd() const { return _span.end.column; }\n    int textWidth() const { return _span.textWidth(); }\n\nprivate:\n    enum TreeOp _op;\n    SourceSpan _span;\n};\n\n\nstruct DocObject {\n    DocObject() : docString(nullptr) {}\n    void setDocString(const char *doc_string) { docString = doc_string; }\n    const char *getDocString() const { return docString; }\n    bool isEmpty() const { return docString == nullptr; }\n    // TODO: set/get DocTable (use SQObjectPtr ?)\nprivate:\n    const char *docString;\n};\n\n\nclass AccessExpr;\nclass LiteralExpr;\nclass BinExpr;\nclass CallExpr;\nclass ExternalValueExpr;\nclass TableExpr;\nclass ClassExpr;\nclass FunctionExpr;\n\nclass Expr : public Node {\nprotected:\n    Expr(enum TreeOp op, SourceSpan span) : Node(op, span), _typeMask(~0u), _typeInferred(false) {}\n    unsigned _typeMask;\n    bool _typeInferred;\n\npublic:\n    unsigned getTypeMask() const { return _typeMask; }\n    void setTypeMask(unsigned m) { _typeMask = m; }\n    bool isTypeInferred() const { return _typeInferred; }\n    void setTypeInferred() { _typeInferred = true; }\n\n    bool isAccessExpr() const { return TO_GETFIELD <= op() && op() <= TO_SETSLOT; }\n    AccessExpr *asAccessExpr() const { assert(isAccessExpr()); return (AccessExpr*)this; }\n    LiteralExpr *asLiteral() const { assert(op() == TO_LITERAL); return (LiteralExpr *)this; }\n    BinExpr *asBinExpr() const { assert(TO_NULLC <= op() && op() <= TO_MODEQ); return (BinExpr *)this; }\n    CallExpr *asCallExpr() const { assert(op() == TO_CALL); return (CallExpr *)this; }\n    ExternalValueExpr *asExternal() const { assert(op() == TO_EXTERNAL_VALUE); return (ExternalValueExpr *)this; }\n    TableExpr *asTableExpr() const { assert(op() == TO_TABLE || op() == TO_CLASS); return (TableExpr *)this; }\n    ClassExpr *asClassExpr() const { assert(op() == TO_CLASS); return (ClassExpr *)this; }\n    FunctionExpr *asFunctionExpr() const { assert(op() == TO_FUNCTION); return (FunctionExpr *)this; }\n};\n\n\nclass Id : public Expr {\npublic:\n    Id(SourceSpan span, const char *name) : Expr(TO_ID, span), _name(name) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n\n    const char *name() const { return _name; }\n\nprivate:\n    const char *_name;\n};\n\nclass UnExpr : public Expr {\npublic:\n    UnExpr(enum TreeOp op, SourceLoc opStart, Expr *arg)\n        : Expr(op, {opStart, arg->sourceSpan().end}), _arg(arg) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *argument() const { return _arg; }\n\nprivate:\n    Expr *_arg;\n};\n\nclass BinExpr : public Expr {\npublic:\n    BinExpr(enum TreeOp op, Expr *lhs, Expr *rhs)\n        : Expr(op, SourceSpan::merge(lhs->sourceSpan(), rhs->sourceSpan())), _lhs(lhs), _rhs(rhs) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *lhs() const { return _lhs; }\n    Expr *rhs() const { return _rhs; }\n\nprivate:\n    Expr *_lhs;\n    Expr *_rhs;\n};\n\nclass TerExpr : public Expr {\npublic:\n    TerExpr(Expr *a, Expr *b, Expr *c)\n        : Expr(TO_TERNARY, SourceSpan::merge(a->sourceSpan(), c->sourceSpan())), _a(a), _b(b), _c(c) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *a() const { return _a; }\n    Expr *b() const { return _b; }\n    Expr *c() const { return _c; }\n\nprivate:\n    Expr *_a;\n    Expr *_b;\n    Expr *_c;\n};\n\nclass FieldAccessExpr;\n\nclass AccessExpr : public Expr {\nprotected:\n    AccessExpr(enum TreeOp op, SourceSpan span, Expr *receiver, bool nullable)\n        : Expr(op, span), _receiver(receiver), _nullable(nullable) {}\npublic:\n\n    bool isFieldAccessExpr() const { return op() == TO_GETFIELD || op() == TO_SETFIELD; }\n    FieldAccessExpr *asFieldAccessExpr() const { assert(isFieldAccessExpr()); return (FieldAccessExpr *)this; }\n\n    bool isNullable() const { return _nullable; }\n    Expr *receiver() const { return _receiver; }\n\nprotected:\n    Expr *_receiver;\n    bool _nullable;\n};\n\nclass FieldAccessExpr : public AccessExpr {\nprotected:\n    FieldAccessExpr(enum TreeOp op, SourceSpan span, Expr *receiver, const char *field, bool nullable)\n        : AccessExpr(op, span, receiver, nullable), _fieldName(field) {}\n\npublic:\n\n    bool canBeLiteral(bool typeMethod) const { return receiver()->op() != TO_BASE && !isNullable() && !typeMethod; }\n    const char *fieldName() const { return _fieldName; }\n\nprivate:\n    const char *_fieldName;\n\n};\n\nclass GetFieldExpr : public FieldAccessExpr {\n    bool _isTypeMethod;\npublic:\n    // Constructor computes span from receiver start to end of field name\n    GetFieldExpr(Expr *receiver, const char *field, bool nullable, bool is_type_method, SourceLoc end)\n        : FieldAccessExpr(TO_GETFIELD, {receiver->sourceSpan().start, end}, receiver, field, nullable)\n        , _isTypeMethod(is_type_method) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    bool isTypeMethod() const { return _isTypeMethod; }\n};\n\n\nclass SetFieldExpr : public FieldAccessExpr {\npublic:\n    // Constructor computes span from receiver start to value end\n    SetFieldExpr(Expr *receiver, const char *field, Expr *value, bool nullable)\n        : FieldAccessExpr(TO_SETFIELD, {receiver->sourceSpan().start, value->sourceSpan().end}, receiver, field, nullable)\n        , _value(value) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *value() const { return _value; }\n\nprotected:\n    Expr *_value;\n};\n\n\nclass SlotAccessExpr : public AccessExpr {\nprotected:\n    SlotAccessExpr(enum TreeOp op, SourceSpan span, Expr *receiver, Expr *key, bool nullable)\n        : AccessExpr(op, span, receiver, nullable), _key(key) {}\npublic:\n\n    Expr *key() const { return _key; }\nprotected:\n    Expr *_key;\n};\n\nclass GetSlotExpr : public SlotAccessExpr {\npublic:\n    GetSlotExpr(Expr *receiver, Expr *key, bool nullable, SourceLoc end)\n        : SlotAccessExpr(TO_GETSLOT, {receiver->sourceSpan().start, end}, receiver, key, nullable) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n};\n\nclass SetSlotExpr : public SlotAccessExpr {\npublic:\n    SetSlotExpr(Expr *receiver, Expr *key, Expr *val, bool nullable)\n        : SlotAccessExpr(TO_SETSLOT, {receiver->sourceSpan().start, val->sourceSpan().end}, receiver, key, nullable)\n        , _val(val) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *value() const { return _val; }\nprivate:\n    Expr *_val;\n};\n\nclass BaseExpr : public Expr {\npublic:\n    BaseExpr(SourceSpan span) : Expr(TO_BASE, span) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n};\n\nclass RootTableAccessExpr : public Expr {\npublic:\n    RootTableAccessExpr(SourceSpan span) : Expr(TO_ROOT_TABLE_ACCESS, span) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n};\n\nenum LiteralKind {\n    LK_STRING,\n    LK_INT,\n    LK_FLOAT,\n    LK_BOOL,\n    LK_NULL\n};\n\nclass LiteralExpr : public Expr {\npublic:\n    LiteralExpr(SourceSpan span) : Expr(TO_LITERAL, span), _kind(LK_NULL) { _v.raw = 0; }\n    LiteralExpr(SourceSpan span, const char *s) : Expr(TO_LITERAL, span), _kind(LK_STRING) { _v.s = s; }\n    LiteralExpr(SourceSpan span, SQFloat f) : Expr(TO_LITERAL, span), _kind(LK_FLOAT) { _v.f = f; }\n    LiteralExpr(SourceSpan span, SQInteger i) : Expr(TO_LITERAL, span), _kind(LK_INT) { _v.i = i; }\n    LiteralExpr(SourceSpan span, bool b) : Expr(TO_LITERAL, span), _kind(LK_BOOL) { _v.b = b; }\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n\n    enum LiteralKind kind() const { return _kind;  }\n\n    SQFloat f() const { assert(_kind == LK_FLOAT); return _v.f; }\n    SQInteger i() const { assert(_kind == LK_INT); return _v.i; }\n    bool b() const { assert(_kind == LK_BOOL); return _v.b; }\n    const char *s() const { assert(_kind == LK_STRING); return _v.s; }\n    void *null() const { assert(_kind == LK_NULL); return nullptr; }\n    SQUnsignedInteger raw() const { return _v.raw; }\n\nprivate:\n    enum LiteralKind _kind;\n    union {\n        const char *s;\n        SQInteger i;\n        SQFloat f;\n        bool b;\n        SQUnsignedInteger raw;\n    } _v;\n\n};\n\n// Used in the analyzer for external bindings\nclass ExternalValueExpr : public Expr {\npublic:\n    ExternalValueExpr(const SQObject &from) : Expr(TO_EXTERNAL_VALUE, SourceSpan::invalid()), _value(from) {}\n    ExternalValueExpr(const SQObject &from, SourceSpan span) : Expr(TO_EXTERNAL_VALUE, span), _value(from) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n\n    SQObjectPtr& value() { return _value; }\n    const SQObjectPtr& value() const { return _value; }\n\nprivate:\n    SQObjectPtr _value; // To release this, ~ExternalValueExpr() dtor is called explicitly\n};\n\nenum IncForm {\n    IF_PREFIX,\n    IF_POSTFIX\n};\n\nclass IncExpr : public Expr {\npublic:\n    // Constructor computes span based on form\n    // For prefix: opLoc is the start of the operator, span is {opLoc, arg->span().end}\n    // For postfix: opLoc is the end of the operator, span is {arg->span().start, opLoc}\n    IncExpr(Expr *arg, int diff, enum IncForm form, SourceLoc opLoc)\n        : Expr(TO_INC, form == IF_PREFIX\n            ? SourceSpan{opLoc, arg->sourceSpan().end}\n            : SourceSpan{arg->sourceSpan().start, opLoc})\n        , _arg(arg), _diff(diff), _form(form) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    enum IncForm form() const { return _form; }\n    int diff() const { return _diff; }\n    Expr *argument() const { return _arg; }\n\nprivate:\n    Expr *_arg;\n    int _diff;\n    enum IncForm _form;\n};\n\nclass CallExpr : public Expr {\npublic:\n    // For incremental building - call setSpanEnd() after adding arguments\n    CallExpr(Arena *arena, Expr *callee, bool nullable)\n        : Expr(TO_CALL, {callee->sourceSpan().start, SourceLoc::invalid()})\n        , _callee(callee), _args(arena), _nullable(nullable) {}\n\n    // For cases where end is known at construction time\n    CallExpr(Arena *arena, Expr *callee, bool nullable, SourceLoc end)\n        : Expr(TO_CALL, {callee->sourceSpan().start, end})\n        , _callee(callee), _args(arena), _nullable(nullable) {}\n\n    void addArgument(Expr *arg) { _args.push_back(arg); }\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    bool isNullable() const { return _nullable; }\n    Expr *callee() const { return _callee; }\n    const ArenaVector<Expr *> &arguments() const { return _args; }\n    ArenaVector<Expr *> &arguments() { return _args; }\n\nprivate:\n    Expr *_callee;\n    ArenaVector<Expr *> _args;\n    bool _nullable;\n};\n\nclass ArrayExpr : public Expr {\npublic:\n    // Incremental building - call setSpanEnd() after adding values\n    ArrayExpr(Arena *arena, SourceLoc start)\n        : Expr(TO_ARRAY, {start, SourceLoc::invalid()}), _inits(arena) {}\n\n    void addValue(Expr *v) { _inits.push_back(v); }\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    const ArenaVector<Expr *> &initializers() const { return _inits; }\n    ArenaVector<Expr *> &initializers() { return _inits; }\n\nprivate:\n    ArenaVector<Expr *> _inits;\n};\n\nclass CommaExpr : public Expr {\npublic:\n    CommaExpr(Arena *arena, ArenaVector<Expr *> exprs)\n        : Expr(TO_COMMA, computeSpan(exprs)), _exprs(std::move(exprs)) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    const ArenaVector<Expr *> &expressions() const { return _exprs; }\n    ArenaVector<Expr *> &expressions() { return _exprs; }\n\nprivate:\n    static SourceSpan computeSpan(const ArenaVector<Expr *> &exprs) {\n        if (exprs.empty()) return SourceSpan::invalid();\n        return SourceSpan::merge(exprs[0]->sourceSpan(), exprs.back()->sourceSpan());\n    }\n\n    ArenaVector<Expr *> _exprs;\n};\n\nclass Block;\n\nclass Statement : public Node {\nprotected:\n    Statement(enum TreeOp op, SourceSpan span) : Node(op, span) {}\n\npublic:\n    inline Block *asBlock() const { assert(op() == TO_BLOCK); return (Block *)(this); }\n};\n\nclass DirectiveStmt : public Statement {\npublic:\n    DirectiveStmt(SourceSpan span) : Statement(TO_DIRECTIVE, span) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n\n    uint32_t setFlags = 0, clearFlags = 0;\n    bool applyToDefault = false;\n};\n\n\nclass ImportStmt : public Statement {\npublic:\n    // Incremental building - call setSpanEnd() after parsing\n    ImportStmt(Arena *arena_, SourceLoc start, const char *module_name, const char *module_alias)\n        : Statement(TO_IMPORT, {start, SourceLoc::invalid()})\n        , arena(arena_), moduleName(module_name), moduleAlias(module_alias), slots(arena_) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n\npublic:\n    Arena *arena;\n    const char *moduleName;\n    const char *moduleAlias;\n    int nameCol = 0;\n    int aliasCol = 0;\n    ArenaVector<SQModuleImportSlot> slots;\n};\n\n\nclass ParamDecl;\nclass VarDecl;\n\nclass Decl : public Statement {\nprotected:\n    Decl(enum TreeOp op, SourceSpan span) : Statement(op, span), typeMask(~0u) {}\n    unsigned typeMask;\npublic:\n\n    ParamDecl *asParam() const { assert(op() == TO_PARAM); return (ParamDecl *)(this); }\n    VarDecl *asVarDecl() const { assert(op() == TO_VAR); return (VarDecl *)(this); }\n    void setTypeMask(unsigned typeMask_) { typeMask = typeMask_; }\n    unsigned getTypeMask() const { return typeMask; }\n};\n\nclass ValueDecl : public Decl {\nprotected:\n    ValueDecl(enum TreeOp op, SourceSpan span, const char *name, Expr *expr)\n        : Decl(op, span), _name(name), _expr(expr) {}\npublic:\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *expression() const { return _expr; }\n    const char *name() const { return _name; }\n\nprivate:\n    const char *_name;\n    Expr *_expr;\n};\n\nclass DestructuringDecl;\n\nclass ParamDecl : public ValueDecl {\n    bool _isVararg;\n    DestructuringDecl *_destructuring;\npublic:\n    ParamDecl(SourceSpan nameSpan, const char *name, Expr *defaultVal)\n        : ValueDecl(TO_PARAM,\n            {nameSpan.start, defaultVal ? defaultVal->sourceSpan().end : nameSpan.end},\n            name, defaultVal)\n        , _isVararg(false)\n        , _destructuring(nullptr) {}\n\n    bool hasDefaultValue() const { return expression() != NULL; }\n    Expr *defaultValue() const { return expression(); }\n\n    void setVararg() { _isVararg = true; };\n    bool isVararg() const { return _isVararg; }\n\n    void setDestructuring(DestructuringDecl *destructuring) { _destructuring = destructuring; }\n    DestructuringDecl *getDestructuring() const { return _destructuring; }\n};\n\nclass VarDecl : public ValueDecl {\n    Id *_nameId;\npublic:\n    VarDecl(SourceLoc start, Id *nameId, Expr *init, bool assignable, bool destructured = false)\n        : ValueDecl(TO_VAR,\n            {start, init ? init->sourceSpan().end : nameId->sourceSpan().end},\n            nameId->name(), init)\n        , _nameId(nameId), _assignable(assignable), _destructured(destructured) {}\n\n    Expr *initializer() const { return expression(); }\n\n    // Get the Id node (for diagnostics - points to identifier)\n    Id *nameId() const { return _nameId; }\n\n    bool isAssignable() const { return _assignable; }\n    bool isDestructured() const { return _destructured; }\n\nprivate:\n    bool _assignable;\n    bool _destructured;\n};\n\nenum TableMemberFlags : unsigned {\n  TMF_STATIC = (1U << 0),\n  TMF_DYNAMIC_KEY = (1U << 1),\n  TMF_JSON = (1U << 2)\n};\n\nstruct TableMember {\n    Expr *key;\n    Expr *value;\n    unsigned flags;\n\n    bool isStatic() const { return (flags & TMF_STATIC) != 0; }\n    bool isDynamicKey() const { return (flags & TMF_DYNAMIC_KEY) != 0; }\n    bool isJson() const { return (flags & TMF_JSON) != 0; }\n};\n\nclass TableExpr : public Expr {\npublic:\n    // Incremental building - call setSpanEnd() after adding members\n    TableExpr(Arena *arena, SourceLoc start)\n        : Expr(TO_TABLE, {start, SourceLoc::invalid()}), _members(arena) {}\n\n    void addMember(Expr *key, Expr *value, unsigned keys = 0) { _members.push_back({ key, value, keys }); }\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    ArenaVector<TableMember> &members() { return _members; }\n    const ArenaVector<TableMember> &members() const { return _members; }\n\n    DocObject docObject;\n\nprotected:\n    TableExpr(Arena *arena, enum TreeOp op, SourceLoc start)\n        : Expr(op, {start, SourceLoc::invalid()}), _members(arena) {}\n\nprivate:\n    ArenaVector<TableMember> _members;\n};\n\nclass ClassExpr : public TableExpr {\npublic:\n    // Incremental building - span starts at class keyword, call setSpanEnd() after body\n    ClassExpr(Arena *arena, SourceLoc classKeywordStart, Expr *key, Expr *base)\n        : TableExpr(arena, TO_CLASS, classKeywordStart), _key(key), _base(base) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *classBase() const { return _base; }\n    Expr* classKey() const { return _key; }\n\n    void setClassBase(Expr *b) { _base = b; }\n    void setClassKey(Expr *k) { _key = k; }\n\n    FunctionExpr *findConstructor() const;\n\nprivate:\n    Expr *_key;\n    Expr *_base;\n\n};\n\nclass Block;\n\nclass FunctionExpr : public Expr {\n    Id *_nameId;       // Name identifier (for diagnostics)\nprotected:\n    // Incremental building - call setSpanEnd() after body is set\n    FunctionExpr(enum TreeOp op, Arena *arena, SourceLoc start, const char *name, Id *nameId = nullptr)\n        : Expr(op, {start, SourceLoc::invalid()}), _arena(arena), _parameters(arena), _name(name), _nameId(nameId),\n        _vararg(false), _body(NULL), _lambda(false), _pure(false), _nodiscard(false), _sourcename(NULL), _hoistingLevel(0), _resultTypeMask(~0u) {}\n\npublic:\n    FunctionExpr(Arena *arena, SourceLoc start, Id *nameId)\n        : Expr(TO_FUNCTION, {start, SourceLoc::invalid()}), _arena(arena), _parameters(arena), _name(nameId->name()), _nameId(nameId),\n        _vararg(false), _body(NULL), _lambda(false), _pure(false), _nodiscard(false), _sourcename(NULL), _hoistingLevel(0), _resultTypeMask(~0u) {}\n\n    FunctionExpr(Arena *arena, SourceLoc start, const char *name)\n        : Expr(TO_FUNCTION, {start, SourceLoc::invalid()}), _arena(arena), _parameters(arena), _name(name), _nameId(nullptr),\n        _vararg(false), _body(NULL), _lambda(false), _pure(false), _nodiscard(false), _sourcename(NULL), _hoistingLevel(0), _resultTypeMask(~0u) {}\n\n    void addParameter(SourceSpan nameSpan, const char *name, Expr *defaultVal = NULL) {\n        _parameters.push_back(new (_arena) ParamDecl(nameSpan, name, defaultVal));\n    }\n\n    ArenaVector<ParamDecl *> &parameters() { return _parameters; }\n    const ArenaVector<ParamDecl *> &parameters() const { return _parameters; }\n\n    void setVararg(bool v) { _vararg = v; }\n    void setBody(Block *body);\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    void setName(const char *newName) { _name = newName; }\n    const char *name() const { return _name; }\n    Id *nameId() const { return _nameId; }\n    bool isVararg() const { return _vararg; }\n    Block *body() const { return _body; }\n\n    void setSourceName(const char *sn) { _sourcename = sn; }\n    const char *sourceName() const { return _sourcename; }\n\n    bool isLambda() const { return _lambda; }\n    void setLambda(bool v) { _lambda = v; }\n\n    void setPure(bool v) { _pure = v; }\n    bool isPure() const { return _pure; }\n\n    void setNodiscard(bool v) { _nodiscard = v; }\n    bool isNodiscard() const { return _nodiscard; }\n\n    int hoistingLevel() const { return _hoistingLevel; }\n    void hoistBy(int level) { _hoistingLevel += level; }\n\n    unsigned getResultTypeMask() const { return _resultTypeMask; }\n    void setResultTypeMask(unsigned resultTypeMask) { _resultTypeMask = resultTypeMask; }\n\n    DocObject docObject;\n\nprivate:\n    Arena *_arena;\n    const char *_name;\n    ArenaVector<ParamDecl *> _parameters;\n    Block * _body;\n    unsigned _resultTypeMask;\n    bool _vararg;\n    bool _lambda;\n    bool _pure;\n    bool _nodiscard;\n\n    const char *_sourcename;\n    int _hoistingLevel;\n};\n\nstruct EnumConst {\n    const char *id;\n    LiteralExpr *val;\n};\n\nclass EnumDecl : public Decl {\npublic:\n    // Incremental building - call setSpanEnd() after constants are added\n    EnumDecl(Arena *arena, SourceLoc start, const char *id, bool global)\n        : Decl(TO_ENUM, {start, SourceLoc::invalid()}), _id(id), _consts(arena), _global(global) {}\n\n    void addConst(const char *id, LiteralExpr *val) { _consts.push_back({ id, val }); }\n\n    ArenaVector<EnumConst> &consts() { return _consts; }\n    const ArenaVector<EnumConst> &consts() const { return _consts; }\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n\n    const char *name() const { return _id; }\n    bool isGlobal() const { return _global; }\n\nprivate:\n    ArenaVector<EnumConst> _consts;\n    const char *_id;\n    bool _global;\n};\n\nclass ConstDecl : public Decl {\npublic:\n    ConstDecl(SourceLoc start, const char *id, Expr *value, bool global)\n        : Decl(TO_CONST, {start, value->sourceSpan().end}), _id(id), _value(value), _global(global) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    const char *name() const { return _id; }\n    Expr *value() const { return _value; }\n    bool isGlobal() const { return _global; }\n\nprivate:\n    const char *_id;\n    Expr *_value;\n    bool _global;\n};\n\nclass DeclGroup : public Decl {\nprotected:\n    // Incremental building - span start is keyword, end is set when last decl is added\n    DeclGroup(Arena *arena, enum TreeOp op, SourceLoc start)\n        : Decl(op, {start, SourceLoc::invalid()}), _decls(arena) {}\npublic:\n    DeclGroup(Arena *arena, SourceLoc start)\n        : Decl(TO_DECL_GROUP, {start, SourceLoc::invalid()}), _decls(arena) {}\n\n    void addDeclaration(VarDecl *d) {\n      _decls.push_back(d);\n      // Update span end to include the new declaration\n      setSpanEnd(d->sourceSpan().end);\n    }\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    ArenaVector<VarDecl *> &declarations() { return _decls; }\n    const ArenaVector<VarDecl *> &declarations() const { return _decls; }\n\nprivate:\n    ArenaVector<VarDecl *> _decls;\n};\n\nenum DestructuringType {\n    DT_TABLE,\n    DT_ARRAY\n};\n\nclass DestructuringDecl : public DeclGroup {\npublic:\n    DestructuringDecl(Arena *arena, SourceLoc start, enum DestructuringType dt)\n        : DeclGroup(arena, TO_DESTRUCTURE, start), _dt_type(dt), _expr(NULL) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    void setExpression(Expr *expr) {\n        _expr = expr;\n        setSpanEnd(_expr->sourceSpan().end);\n    }\n    Expr *initExpression() const { return _expr; }\n\n    void setType(enum DestructuringType t) { _dt_type = t; }\n    enum DestructuringType type() const { return _dt_type; }\n\nprivate:\n    Expr *_expr;\n    enum DestructuringType _dt_type;\n};\n\nclass Block : public Statement {\npublic:\n    // Incremental building - call setSpanEnd() after statements are added\n    Block(Arena *arena, SourceLoc start, bool is_root = false)\n        : Statement(TO_BLOCK, {start, SourceLoc::invalid()})\n        , _statements(arena), _is_root(is_root), _is_body(false), _is_expr_block(false) {}\n\n    void addStatement(Statement *stmt) { assert(stmt); _statements.push_back(stmt); }\n\n    ArenaVector<Statement *> &statements() { return _statements; }\n    const ArenaVector<Statement *> &statements() const { return _statements; }\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    bool isRoot() const { return _is_root; }\n\n    bool isBody() const { return _is_body; }\n    void setIsBody() { _is_body = true; }\n\n    bool isExprBlock() { return _is_expr_block; }\n    void setIsExprBlock() { _is_expr_block = true; }\n\nprivate:\n    ArenaVector<Statement *> _statements;\n    bool _is_root;\n    bool _is_body;\n    bool _is_expr_block;\n};\n\nclass RootBlock : public Block {\npublic:\n    RootBlock(Arena *arena, SourceLoc start) : Block(arena, start, true) {}\n};\n\nclass CodeBlockExpr : public Expr {\npublic:\n    CodeBlockExpr(Block *block): Expr(TO_CODE_BLOCK_EXPR, block->sourceSpan()), _block(block) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Block *block() const { return _block; }\n\nprivate:\n    Block *_block;\n};\n\nclass IfStatement : public Statement {\npublic:\n    IfStatement(SourceLoc start, Expr *cond, Statement *thenB, Statement *elseB)\n        : Statement(TO_IF, {start, (elseB ? elseB : thenB)->sourceSpan().end})\n        , _cond(cond), _thenB(thenB), _elseB(elseB) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *condition() const { return _cond; }\n    Statement *thenBranch() const { return _thenB; }\n    Statement *elseBranch() const { return _elseB; }\n\nprivate:\n    Expr *_cond;\n    Statement *_thenB;\n    Statement *_elseB;\n};\n\nclass LoopStatement : public Statement {\nprotected:\n    // Constructor computes span from keyword start to body end\n    LoopStatement(enum TreeOp op, SourceLoc start, Statement *body)\n        : Statement(op, {start, body->sourceSpan().end}), _body(body) {}\n\n    // For DoWhile which needs a different span\n    LoopStatement(enum TreeOp op, SourceSpan span, Statement *body)\n        : Statement(op, span), _body(body) {}\npublic:\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Statement *body() const { return _body; }\n\nprivate:\n    Statement *_body;\n};\n\nclass WhileStatement : public LoopStatement {\npublic:\n    WhileStatement(SourceLoc start, Expr *cond, Statement *body)\n        : LoopStatement(TO_WHILE, start, body), _cond(cond) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *condition() const { return _cond;  }\n\nprivate:\n    Expr *_cond;\n};\n\nclass DoWhileStatement : public LoopStatement {\npublic:\n    DoWhileStatement(SourceLoc start, Statement *body, Expr *cond, SourceLoc end)\n        : LoopStatement(TO_DOWHILE, {start, end}, body), _cond(cond) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *condition() const { return _cond; }\n\nprivate:\n    Expr *_cond;\n};\n\nclass ForStatement : public LoopStatement {\npublic:\n    ForStatement(SourceLoc start, Node *init, Expr *cond, Expr *mod, Statement *body)\n        : LoopStatement(TO_FOR, start, body), _init(init), _cond(cond), _mod(mod) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Node *initializer() const { return _init; }\n    Expr *condition() const { return _cond; }\n    Expr *modifier() const { return _mod; }\n\n\nprivate:\n    Node *_init;\n    Expr *_cond;\n    Expr *_mod;\n};\n\nclass ForeachStatement : public LoopStatement {\npublic:\n    ForeachStatement(SourceLoc start, VarDecl *idx, VarDecl *val, Expr *container, Statement *body)\n        : LoopStatement(TO_FOREACH, start, body), _idx(idx), _val(val), _container(container) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *container() const { return _container; }\n    VarDecl *idx() const { return _idx; }\n    VarDecl *val() const { return _val; }\n\nprivate:\n    VarDecl *_idx;\n    VarDecl *_val;\n    Expr *_container;\n};\n\nstruct SwitchCase {\n    Expr *val;\n    Statement *stmt;\n};\n\nclass SwitchStatement : public Statement {\npublic:\n    // Incremental building - call setSpanEnd() after cases are added\n    SwitchStatement(SourceLoc start, Arena *arena, Expr *expr)\n        : Statement(TO_SWITCH, {start, SourceLoc::invalid()}), _expr(expr), _cases(arena), _defaultCase() {}\n\n    void addCases(Expr *val, Statement *stmt) { _cases.push_back({ val, stmt }); }\n\n    void addDefault(Statement *stmt) {\n        assert(_defaultCase.stmt == NULL);\n        _defaultCase.stmt = stmt;\n    }\n\n    ArenaVector<SwitchCase> &cases() { return _cases; }\n    const ArenaVector<SwitchCase> &cases() const { return _cases; }\n\n    Expr *expression() const { return _expr; }\n    const SwitchCase &defaultCase() const { return _defaultCase; }\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\nprivate:\n    Expr *_expr;\n    ArenaVector<SwitchCase> _cases;\n    SwitchCase _defaultCase;\n};\n\nclass TryStatement : public Statement {\npublic:\n    TryStatement(SourceLoc start, Statement *t, Id *exc, Statement *c)\n        : Statement(TO_TRY, {start, c->sourceSpan().end}), _tryStmt(t), _exception(exc), _catchStmt(c) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Statement *tryStatement() const { return _tryStmt; }\n    Id *exceptionId() const { return _exception; }\n    Statement *catchStatement() const { return _catchStmt; }\n\nprivate:\n    Statement *_tryStmt;\n    Id *_exception;\n    Statement *_catchStmt;\n};\n\nclass TerminateStatement : public Statement {\nprotected:\n    TerminateStatement(enum TreeOp op, SourceSpan keywordSpan, Expr *arg)\n        : Statement(op, arg ? SourceSpan{keywordSpan.start, arg->sourceSpan().end} : keywordSpan)\n        , _arg(arg) {}\npublic:\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *argument() const { return _arg; }\n\nprivate:\n    Expr *_arg;\n};\n\nclass ReturnStatement : public TerminateStatement {\npublic:\n    ReturnStatement(SourceSpan keywordSpan, Expr *arg)\n        : TerminateStatement(TO_RETURN, keywordSpan, arg), _isLambda(false) {}\n\n\n    void setIsLambda() { _isLambda = true; }\n    bool isLambdaReturn() const { return _isLambda; }\n\nprivate:\n    bool _isLambda;\n};\n\nclass YieldStatement : public TerminateStatement {\npublic:\n    YieldStatement(SourceSpan keywordSpan, Expr *arg) : TerminateStatement(TO_YIELD, keywordSpan, arg) {}\n};\n\nclass ThrowStatement : public TerminateStatement {\npublic:\n    ThrowStatement(SourceSpan keywordSpan, Expr *arg) : TerminateStatement(TO_THROW, keywordSpan, arg) { assert(arg); }\n};\n\nclass JumpStatement : public Statement {\nprotected:\n    JumpStatement(enum TreeOp op, SourceSpan span) : Statement(op, span) {}\npublic:\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n};\n\nclass BreakStatement : public JumpStatement {\npublic:\n    BreakStatement(SourceSpan span, Statement *breakTarget) : JumpStatement(TO_BREAK, span), _target(breakTarget) {}\n\nprivate:\n    Statement *_target; // Currently not used\n};\n\nclass ContinueStatement : public JumpStatement {\npublic:\n    ContinueStatement(SourceSpan span, LoopStatement *target) : JumpStatement(TO_CONTINUE, span), _target(target) {}\n\nprivate:\n    LoopStatement *_target; // Currently not used\n};\n\nclass ExprStatement : public Statement {\npublic:\n    ExprStatement(Expr *expr) : Statement(TO_EXPR_STMT, expr->sourceSpan()), _expr(expr) {}\n\n    void visitChildren(Visitor *visitor);\n    void transformChildren(Transformer *transformer);\n\n    Expr *expression() const { return _expr; }\n\nprivate:\n    Expr *_expr;\n};\n\nclass EmptyStatement : public Statement {\npublic:\n    EmptyStatement(SourceSpan span) : Statement(TO_EMPTY, span) {}\n\n    void visitChildren(Visitor *visitor) {}\n    void transformChildren(Transformer *transformer) {}\n};\n\nconst char* treeopStr(enum TreeOp op);\n\nclass Visitor {\nprotected:\n    Visitor() {}\npublic:\n    virtual ~Visitor() {}\n\n    virtual void visitNode(Node *node) { node->visitChildren(this); }\n\n    virtual void visitExpr(Expr *expr) { visitNode(expr); }\n    virtual void visitUnExpr(UnExpr *expr) { visitExpr(expr); }\n    virtual void visitCodeBlockExpr(CodeBlockExpr *expr) { visitExpr(expr); }\n    virtual void visitBinExpr(BinExpr *expr) { visitExpr(expr); }\n    virtual void visitTerExpr(TerExpr *expr) { visitExpr(expr); }\n    virtual void visitCallExpr(CallExpr *expr) { visitExpr(expr); }\n    virtual void visitId(Id *id) { visitExpr(id); }\n    virtual void visitAccessExpr(AccessExpr *expr) { visitExpr(expr); }\n    virtual void visitGetFieldExpr(GetFieldExpr *expr) { visitAccessExpr(expr); }\n    virtual void visitSetFieldExpr(SetFieldExpr *expr) { visitAccessExpr(expr); }\n    virtual void visitGetSlotExpr(GetSlotExpr *expr) { visitAccessExpr(expr); }\n    virtual void visitSetSlotExpr(SetSlotExpr *expr) { visitAccessExpr(expr); }\n    virtual void visitBaseExpr(BaseExpr *expr) { visitExpr(expr); }\n    virtual void visitRootTableAccessExpr(RootTableAccessExpr *expr) { visitExpr(expr); }\n    virtual void visitLiteralExpr(LiteralExpr *expr) { visitExpr(expr); }\n    virtual void visitIncExpr(IncExpr *expr) { visitExpr(expr); }\n    virtual void visitArrayExpr(ArrayExpr *expr) { visitExpr(expr); }\n    virtual void visitTableExpr(TableExpr *tbl) { visitExpr(tbl); }\n    virtual void visitClassExpr(ClassExpr *cls) { visitTableExpr(cls); }\n    virtual void visitFunctionExpr(FunctionExpr *f) { visitExpr(f); }\n    virtual void visitCommaExpr(CommaExpr *expr) { visitExpr(expr); }\n    virtual void visitExternalValueExpr(ExternalValueExpr *expr) { visitExpr(expr); }\n\n    virtual void visitStmt(Statement *stmt) { visitNode(stmt); }\n    virtual void visitBlock(Block *block) { visitStmt(block); }\n    virtual void visitIfStatement(IfStatement *ifstmt) { visitStmt(ifstmt); }\n    virtual void visitLoopStatement(LoopStatement *loop) { visitStmt(loop); }\n    virtual void visitWhileStatement(WhileStatement *loop) { visitLoopStatement(loop); }\n    virtual void visitDoWhileStatement(DoWhileStatement *loop) { visitLoopStatement(loop); }\n    virtual void visitForStatement(ForStatement *loop) { visitLoopStatement(loop); }\n    virtual void visitForeachStatement(ForeachStatement *loop) { visitLoopStatement(loop); }\n    virtual void visitSwitchStatement(SwitchStatement *swtch) { visitStmt(swtch); }\n    virtual void visitTryStatement(TryStatement *tr) { visitStmt(tr); }\n    virtual void visitTerminateStatement(TerminateStatement *term) { visitStmt(term); }\n    virtual void visitReturnStatement(ReturnStatement *ret) { visitTerminateStatement(ret); }\n    virtual void visitYieldStatement(YieldStatement *yld) { visitTerminateStatement(yld); }\n    virtual void visitThrowStatement(ThrowStatement *thr) { visitTerminateStatement(thr); }\n    virtual void visitJumpStatement(JumpStatement *jmp) { visitStmt(jmp); }\n    virtual void visitBreakStatement(BreakStatement *jmp) { visitJumpStatement(jmp); }\n    virtual void visitContinueStatement(ContinueStatement *jmp) { visitJumpStatement(jmp); }\n    virtual void visitExprStatement(ExprStatement *estmt) { visitStmt(estmt); }\n    virtual void visitEmptyStatement(EmptyStatement *empty) { visitStmt(empty); }\n\n    virtual void visitDecl(Decl *decl) { visitStmt(decl); }\n    virtual void visitValueDecl(ValueDecl *decl) { visitDecl(decl); }\n    virtual void visitVarDecl(VarDecl *decl) { visitValueDecl(decl); }\n    virtual void visitParamDecl(ParamDecl *decl) { visitValueDecl(decl); }\n    virtual void visitConstDecl(ConstDecl *cnst) { visitDecl(cnst); }\n    virtual void visitEnumDecl(EnumDecl *enm) { visitDecl(enm); }\n    virtual void visitDeclGroup(DeclGroup *grp) { visitDecl(grp); }\n    virtual void visitDestructuringDecl(DestructuringDecl  *destruct) { visitDecl(destruct); }\n    virtual void visitDirectiveStatement(DirectiveStmt *dir) { visitStmt(dir); }\n    virtual void visitImportStatement(ImportStmt *import) { visitStmt(import); }\n};\n\nclass Transformer {\nprotected:\n  Transformer() {}\npublic:\n  virtual ~Transformer() {}\n\n  virtual Node* transformNode(Node *node) { node->transformChildren(this); return node; }\n\n  virtual Node *transformExpr(Expr *expr) { return transformNode(expr); }\n  virtual Node *transformUnExpr(UnExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformCodeBlockExpr(CodeBlockExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformBinExpr(BinExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformTerExpr(TerExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformCallExpr(CallExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformId(Id *id) { return transformExpr(id); }\n  virtual Node *transformGetFieldExpr(GetFieldExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformSetFieldExpr(SetFieldExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformGetSlotExpr(GetSlotExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformSetSlotExpr(SetSlotExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformBaseExpr(BaseExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformRootTableAccessExpr(RootTableAccessExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformLiteralExpr(LiteralExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformIncExpr(IncExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformArrayExpr(ArrayExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformTableExpr(TableExpr *tbl) { return transformExpr(tbl); }\n  virtual Node *transformClassExpr(ClassExpr *cls) { return transformTableExpr(cls); }\n  virtual Node *transformFunctionExpr(FunctionExpr *f) { return transformExpr(f); }\n  virtual Node *transformCommaExpr(CommaExpr *expr) { return transformExpr(expr); }\n  virtual Node *transformExternalValueExpr(ExternalValueExpr *expr) { return transformExpr(expr); }\n\n  virtual Node *transformStmt(Statement *stmt) { return transformNode(stmt); }\n  virtual Node *transformBlock(Block *block) { return transformStmt(block); }\n  virtual Node *transformIfStatement(IfStatement *ifstmt) { return transformStmt(ifstmt); }\n  virtual Node *transformLoopStatement(LoopStatement *loop) { return transformStmt(loop); }\n  virtual Node *transformWhileStatement(WhileStatement *loop) { return transformLoopStatement(loop); }\n  virtual Node *transformDoWhileStatement(DoWhileStatement *loop) { return transformLoopStatement(loop); }\n  virtual Node *transformForStatement(ForStatement *loop) { return transformLoopStatement(loop); }\n  virtual Node *transformForeachStatement(ForeachStatement *loop) { return transformLoopStatement(loop); }\n  virtual Node *transformSwitchStatement(SwitchStatement *swtch) { return transformStmt(swtch); }\n  virtual Node *transformTryStatement(TryStatement *tr) { return transformStmt(tr); }\n  virtual Node *transformTerminateStatement(TerminateStatement *term) { return transformStmt(term); }\n  virtual Node *transformReturnStatement(ReturnStatement *ret) { return transformTerminateStatement(ret); }\n  virtual Node *transformYieldStatement(YieldStatement *yld) { return transformTerminateStatement(yld); }\n  virtual Node *transformThrowStatement(ThrowStatement *thr) { return transformTerminateStatement(thr); }\n  virtual Node *transformJumpStatement(JumpStatement *jmp) { return transformStmt(jmp); }\n  virtual Node *transformBreakStatement(BreakStatement *jmp) { return transformJumpStatement(jmp); }\n  virtual Node *transformContinueStatement(ContinueStatement *jmp) { return transformJumpStatement(jmp); }\n  virtual Node *transformExprStatement(ExprStatement *estmt) { return transformStmt(estmt); }\n  virtual Node *transformEmptyStatement(EmptyStatement *empty) { return transformStmt(empty); }\n\n  virtual Node *transformDecl(Decl *decl) { return transformStmt(decl); }\n  virtual Node *transformValueDecl(ValueDecl *decl) { return transformDecl(decl); }\n  virtual Node *transformVarDecl(VarDecl *decl) { return transformValueDecl(decl); }\n  virtual Node *transformParamDecl(ParamDecl *decl) { return transformValueDecl(decl); }\n  virtual Node *transformConstDecl(ConstDecl *cnst) { return transformDecl(cnst); }\n  virtual Node *transformEnumDecl(EnumDecl *enm) { return transformDecl(enm); }\n  virtual Node *transformDeclGroup(DeclGroup *grp) { return transformDecl(grp); }\n  virtual Node *transformDestructuringDecl(DestructuringDecl  *destruct) { return transformDecl(destruct); }\n};\n\ntemplate<typename V>\nvoid Node::visit(V *visitor) {\n    switch (op())\n    {\n    case TO_BLOCK:      visitor->visitBlock(static_cast<Block *>(this)); return;\n    case TO_IF:         visitor->visitIfStatement(static_cast<IfStatement *>(this)); return;\n    case TO_WHILE:      visitor->visitWhileStatement(static_cast<WhileStatement *>(this)); return;\n    case TO_DOWHILE:    visitor->visitDoWhileStatement(static_cast<DoWhileStatement *>(this)); return;\n    case TO_FOR:        visitor->visitForStatement(static_cast<ForStatement *>(this)); return;\n    case TO_FOREACH:    visitor->visitForeachStatement(static_cast<ForeachStatement *>(this)); return;\n    case TO_SWITCH:     visitor->visitSwitchStatement(static_cast<SwitchStatement *>(this)); return;\n    case TO_RETURN:     visitor->visitReturnStatement(static_cast<ReturnStatement *>(this)); return;\n    case TO_YIELD:      visitor->visitYieldStatement(static_cast<YieldStatement *>(this)); return;\n    case TO_THROW:      visitor->visitThrowStatement(static_cast<ThrowStatement *>(this)); return;\n    case TO_TRY:        visitor->visitTryStatement(static_cast<TryStatement *>(this)); return;\n    case TO_BREAK:      visitor->visitBreakStatement(static_cast<BreakStatement *>(this)); return;\n    case TO_CONTINUE:   visitor->visitContinueStatement(static_cast<ContinueStatement *>(this)); return;\n    case TO_EXPR_STMT:  visitor->visitExprStatement(static_cast<ExprStatement *>(this)); return;\n    case TO_EMPTY:      visitor->visitEmptyStatement(static_cast<EmptyStatement *>(this)); return;\n        //case TO_STATEMENT_MARK:\n    case TO_ID:         visitor->visitId(static_cast<Id *>(this)); return;\n    case TO_COMMA:      visitor->visitCommaExpr(static_cast<CommaExpr *>(this)); return;\n    case TO_NULLC:\n    case TO_ASSIGN:\n    case TO_OROR:\n    case TO_ANDAND:\n    case TO_OR:\n    case TO_XOR:\n    case TO_AND:\n    case TO_NE:\n    case TO_EQ:\n    case TO_3CMP:\n    case TO_GE:\n    case TO_GT:\n    case TO_LE:\n    case TO_LT:\n    case TO_IN:\n    case TO_INSTANCEOF:\n    case TO_USHR:\n    case TO_SHR:\n    case TO_SHL:\n    case TO_MUL:\n    case TO_DIV:\n    case TO_MOD:\n    case TO_ADD:\n    case TO_SUB:\n    case TO_NEWSLOT:\n    case TO_PLUSEQ:\n    case TO_MINUSEQ:\n    case TO_MULEQ:\n    case TO_DIVEQ:\n    case TO_MODEQ:\n        visitor->visitBinExpr(static_cast<BinExpr *>(this)); return;\n    case TO_NOT:\n    case TO_BNOT:\n    case TO_NEG:\n    case TO_TYPEOF:\n    case TO_RESUME:\n    case TO_CLONE:\n    case TO_PAREN:\n    case TO_DELETE:\n    case TO_STATIC_MEMO:\n    case TO_INLINE_CONST:\n        visitor->visitUnExpr(static_cast<UnExpr *>(this)); return;\n    case TO_CODE_BLOCK_EXPR:\n        visitor->visitCodeBlockExpr(static_cast<CodeBlockExpr *>(this)); return;\n    case TO_LITERAL:\n        visitor->visitLiteralExpr(static_cast<LiteralExpr *>(this)); return;\n    case TO_BASE:\n        visitor->visitBaseExpr(static_cast<BaseExpr *>(this)); return;\n    case TO_ROOT_TABLE_ACCESS:\n        visitor->visitRootTableAccessExpr(static_cast<RootTableAccessExpr *>(this)); return;\n    case TO_INC:\n        visitor->visitIncExpr(static_cast<IncExpr *>(this)); return;\n    case TO_ARRAY:\n        visitor->visitArrayExpr(static_cast<ArrayExpr *>(this)); return;\n    case TO_TABLE:\n        visitor->visitTableExpr(static_cast<TableExpr *>(this)); return;\n    case TO_CLASS:\n        visitor->visitClassExpr(static_cast<ClassExpr *>(this)); return;\n    case TO_FUNCTION:\n        visitor->visitFunctionExpr(static_cast<FunctionExpr *>(this)); return;\n    case TO_GETFIELD:\n        visitor->visitGetFieldExpr(static_cast<GetFieldExpr *>(this)); return;\n    case TO_SETFIELD:\n        visitor->visitSetFieldExpr(static_cast<SetFieldExpr *>(this)); return;\n    case TO_GETSLOT:\n        visitor->visitGetSlotExpr(static_cast<GetSlotExpr *>(this)); return;\n    case TO_SETSLOT:\n        visitor->visitSetSlotExpr(static_cast<SetSlotExpr *>(this)); return;\n    case TO_CALL:\n        visitor->visitCallExpr(static_cast<CallExpr *>(this)); return;\n    case TO_TERNARY:\n        visitor->visitTerExpr(static_cast<TerExpr *>(this)); return;\n    case TO_EXTERNAL_VALUE:\n        visitor->visitExternalValueExpr(static_cast<ExternalValueExpr *>(this)); return;\n        //case TO_EXPR_MARK:\n    case TO_VAR:\n        visitor->visitVarDecl(static_cast<VarDecl *>(this)); return;\n    case TO_PARAM:\n        visitor->visitParamDecl(static_cast<ParamDecl *>(this)); return;\n    case TO_CONST:\n        visitor->visitConstDecl(static_cast<ConstDecl *>(this)); return;\n    case TO_DECL_GROUP:\n        visitor->visitDeclGroup(static_cast<DeclGroup *>(this)); return;\n    case TO_DESTRUCTURE:\n        visitor->visitDestructuringDecl(static_cast<DestructuringDecl  *>(this)); return;\n    case TO_ENUM:\n        visitor->visitEnumDecl(static_cast<EnumDecl *>(this)); return;\n    case TO_DIRECTIVE:\n        visitor->visitDirectiveStatement(static_cast<DirectiveStmt *>(this)); return;\n    case TO_IMPORT:\n        visitor->visitImportStatement(static_cast<ImportStmt *>(this)); return;\n    default:\n        break;\n    }\n}\n\ntemplate<typename T>\nNode *Node::transform(T *transformer) {\n  switch (op())\n  {\n  case TO_BLOCK:      return transformer->transformBlock(static_cast<Block *>(this));\n  case TO_IF:         return transformer->transformIfStatement(static_cast<IfStatement *>(this));\n  case TO_WHILE:      return transformer->transformWhileStatement(static_cast<WhileStatement *>(this));\n  case TO_DOWHILE:    return transformer->transformDoWhileStatement(static_cast<DoWhileStatement *>(this));\n  case TO_FOR:        return transformer->transformForStatement(static_cast<ForStatement *>(this));\n  case TO_FOREACH:    return transformer->transformForeachStatement(static_cast<ForeachStatement *>(this));\n  case TO_SWITCH:     return transformer->transformSwitchStatement(static_cast<SwitchStatement *>(this));\n  case TO_RETURN:     return transformer->transformReturnStatement(static_cast<ReturnStatement *>(this));\n  case TO_YIELD:      return transformer->transformYieldStatement(static_cast<YieldStatement *>(this));\n  case TO_THROW:      return transformer->transformThrowStatement(static_cast<ThrowStatement *>(this));\n  case TO_TRY:        return transformer->transformTryStatement(static_cast<TryStatement *>(this));\n  case TO_BREAK:      return transformer->transformBreakStatement(static_cast<BreakStatement *>(this));\n  case TO_CONTINUE:   return transformer->transformContinueStatement(static_cast<ContinueStatement *>(this));\n  case TO_EXPR_STMT:  return transformer->transformExprStatement(static_cast<ExprStatement *>(this));\n  case TO_EMPTY:      return transformer->transformEmptyStatement(static_cast<EmptyStatement *>(this));\n    //case TO_STATEMENT_MARK:\n  case TO_ID:         return transformer->transformId(static_cast<Id *>(this));\n  case TO_COMMA:      return transformer->transformCommaExpr(static_cast<CommaExpr *>(this));\n  case TO_NULLC:\n  case TO_ASSIGN:\n  case TO_OROR:\n  case TO_ANDAND:\n  case TO_OR:\n  case TO_XOR:\n  case TO_AND:\n  case TO_NE:\n  case TO_EQ:\n  case TO_3CMP:\n  case TO_GE:\n  case TO_GT:\n  case TO_LE:\n  case TO_LT:\n  case TO_IN:\n  case TO_INSTANCEOF:\n  case TO_USHR:\n  case TO_SHR:\n  case TO_SHL:\n  case TO_MUL:\n  case TO_DIV:\n  case TO_MOD:\n  case TO_ADD:\n  case TO_SUB:\n  case TO_NEWSLOT:\n  case TO_PLUSEQ:\n  case TO_MINUSEQ:\n  case TO_MULEQ:\n  case TO_DIVEQ:\n  case TO_MODEQ:\n    return transformer->transformBinExpr(static_cast<BinExpr *>(this));\n  case TO_NOT:\n  case TO_BNOT:\n  case TO_NEG:\n  case TO_TYPEOF:\n  case TO_RESUME:\n  case TO_CLONE:\n  case TO_PAREN:\n  case TO_DELETE:\n  case TO_STATIC_MEMO:\n  case TO_INLINE_CONST:\n    return transformer->transformUnExpr(static_cast<UnExpr *>(this));\n  case TO_CODE_BLOCK_EXPR:\n    return transformer->transformCodeBlockExpr(static_cast<CodeBlockExpr *>(this));\n  case TO_LITERAL:\n    return transformer->transformLiteralExpr(static_cast<LiteralExpr *>(this));\n  case TO_BASE:\n    return transformer->transformBaseExpr(static_cast<BaseExpr *>(this));\n  case TO_ROOT_TABLE_ACCESS:\n    return transformer->transformRootTableAccessExpr(static_cast<RootTableAccessExpr *>(this));\n  case TO_INC:\n    return transformer->transformIncExpr(static_cast<IncExpr *>(this));\n  case TO_ARRAY:\n    return transformer->transformArrayExpr(static_cast<ArrayExpr *>(this));\n  case TO_TABLE:\n    return transformer->transformTableExpr(static_cast<TableExpr *>(this));\n  case TO_CLASS:\n    return transformer->transformClassExpr(static_cast<ClassExpr *>(this));\n  case TO_FUNCTION:\n    return transformer->transformFunctionExpr(static_cast<FunctionExpr *>(this));\n  case TO_GETFIELD:\n    return transformer->transformGetFieldExpr(static_cast<GetFieldExpr *>(this));\n  case TO_SETFIELD:\n    return transformer->transformSetFieldExpr(static_cast<SetFieldExpr *>(this));\n  case TO_GETSLOT:\n    return transformer->transformGetSlotExpr(static_cast<GetSlotExpr *>(this));\n  case TO_SETSLOT:\n    return transformer->transformSetSlotExpr(static_cast<SetSlotExpr *>(this));\n  case TO_CALL:\n    return transformer->transformCallExpr(static_cast<CallExpr *>(this));\n  case TO_TERNARY:\n    return transformer->transformTerExpr(static_cast<TerExpr *>(this));\n  case TO_EXTERNAL_VALUE:\n    return transformer->transformExternalValueExpr(static_cast<ExternalValueExpr *>(this));\n    //case TO_EXPR_MARK:\n  case TO_VAR:\n    return transformer->transformVarDecl(static_cast<VarDecl *>(this));\n  case TO_PARAM:\n    return transformer->transformParamDecl(static_cast<ParamDecl *>(this));\n  case TO_CONST:\n    return transformer->transformConstDecl(static_cast<ConstDecl *>(this));\n  case TO_DECL_GROUP:\n    return transformer->transformDeclGroup(static_cast<DeclGroup *>(this));\n  case TO_DESTRUCTURE:\n    return transformer->transformDestructuringDecl(static_cast<DestructuringDecl  *>(this));\n  case TO_ENUM:\n    return transformer->transformEnumDecl(static_cast<EnumDecl *>(this));\n  case TO_DIRECTIVE:\n    return this; //-V1037\n  case TO_IMPORT:\n    return this; //-V1037\n  default:\n    assert(0 && \"Unknown tree type\");\n    return this;\n  }\n}\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/codegen.cpp",
    "content": "#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include \"opcodes.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqfuncstate.h\"\n#include \"codegen.h\"\n#include \"constgen.h\"\n#include \"sqvm.h\"\n#include \"optimizer.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqclass.h\"\n#include \"sqclosure.h\"\n\n\n#define GLOBAL_OPTIMIZATION_SWITCH true /* false - turn off broken optimizer */\n\n#define STATIC_MEMO_CONST_SCORE_THRESHOLD 10\n\n#define STATIC_MEMO_ENABLED 1\n\n#ifndef SQ_LINE_INFO_IN_STRUCTURES\n#  define SQ_LINE_INFO_IN_STRUCTURES 1\n#endif\n\n\n#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \\\n                     _scope.outers = _fs->_outers; \\\n                     _scope.stacksize = _fs->GetStackSize(); \\\n                     _scopedconsts.push_back();\n\n#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _fs->_blockstacksizes.top()) { \\\n                            if(_fs->CountOuters(_fs->_blockstacksizes.top())) { \\\n                                _fs->AddInstruction(_OP_CLOSE,0,_fs->_blockstacksizes.top()); \\\n                            } \\\n                        }\n\n#define END_SCOPE_NO_CLOSE() {  if(_fs->GetStackSize() != _scope.stacksize) { \\\n                            _fs->SetStackSize(_scope.stacksize); \\\n                        } \\\n                        _scope = __oldscope__; \\\n                        assert(!_scopedconsts.empty()); \\\n                        _scopedconsts.pop_back(); \\\n                    }\n\n#define END_SCOPE() {   SQInteger oldouters = _fs->_outers;\\\n                        if(_fs->GetStackSize() != _scope.stacksize) { \\\n                            _fs->SetStackSize(_scope.stacksize); \\\n                            if(oldouters != _fs->_outers) { \\\n                                _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \\\n                            } \\\n                        } \\\n                        _scope = __oldscope__; \\\n                        _scopedconsts.pop_back(); \\\n                    }\n\n#define BEGIN_BREAKABLE_BLOCK()  SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \\\n                            SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \\\n                            _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); \\\n                            _fs->_blockstacksizes.push_back(_scope.stacksize);\n\n\n#define END_BREAKABLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \\\n                    __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \\\n                    if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \\\n                    if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \\\n                    _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back(); \\\n                    _fs->_blockstacksizes.pop_back(); }\n\n\nnamespace SQCompilation {\n\n\nCodeGenVisitor::CodeGenVisitor(Arena *arena, const HSQOBJECT *bindings, SQVM *vm, const char *sourceName, SQCompilationContext &ctx)\n    : Visitor(),\n    _fs(NULL),\n    _childFs(NULL),\n    _ctx(ctx),\n    _scopedconsts(_ss(vm)->_alloc_ctx),\n    _sourceName(sourceName),\n    _vm(vm),\n    _resolve_mode(ExprChainResolveMode::Value),\n    _inside_static_memo(false),\n    _visit_arrays_and_tables(false),\n    _variable_node(nullptr),\n    _arena(arena),\n    _scope() {\n\n    _complexity_level = 0;\n\n    if (bindings) {\n        assert(sq_type(*bindings) == OT_TABLE || sq_type(*bindings) == OT_NULL);\n        if (sq_type(*bindings) == OT_TABLE) {\n            _scopedconsts.push_back(SQObjectPtr(*bindings));\n        }\n    }\n}\n\n\nvoid CodeGenVisitor::reportDiagnostic(Node *n, int32_t id, ...) {\n    va_list vargs;\n    va_start(vargs, id);\n\n    _ctx.vreportDiagnostic((enum DiagnosticsId)id, n->lineStart(), n->columnStart(), n->textWidth(), vargs);\n\n    va_end(vargs);\n}\n\nbool CodeGenVisitor::generate(RootBlock *root, SQObjectPtr &out) {\n    SQFuncState funcstate(_ss(_vm), NULL, _ctx);\n\n    try {\n        _fs = &funcstate;\n        _childFs = NULL;\n\n        _fs->_name = SQString::Create(_ss(_vm), \"__main__\");\n        _fs->AddParameter(_fs->CreateString(\"this\"), _RT_NULL);\n        _fs->AddParameter(_fs->CreateString(\"vargv\"), _RT_ARRAY);\n        _fs->_varparams = true;\n        _fs->_sourcename = SQString::Create(_ss(_vm), _sourceName);\n\n        SQInteger stacksize = _fs->GetStackSize();\n\n        root->visit(this);\n\n        _fs->SetStackSize(stacksize);\n        _fs->AddLineInfos(root->lineEnd(), true, true);\n        _fs->AddInstruction(_OP_RETURN, 0xFF);\n\n        if (GLOBAL_OPTIMIZATION_SWITCH && !(_fs->lang_features & LF_DISABLE_OPTIMIZER)) {\n            SQOptimizer opt(funcstate);\n            opt.optimize();\n            _fs->CheckForPurity();\n        }\n\n        _fs->SetStackSize(0);\n\n        out = _fs->BuildProto();\n\n        _fs = NULL;\n        return true;\n    }\n    catch (CompilerError &) {\n        return false;\n    }\n}\n\nvoid CodeGenVisitor::CheckDuplicateLocalIdentifier(Node *n, SQObject name, const char *desc, bool ignore_global_consts) {\n    SQCompiletimeVarInfo varInfo;\n    if (_fs->GetLocalVariable(name, varInfo) >= 0)\n        reportDiagnostic(n, DiagnosticsId::DI_CONFLICTS_WITH, desc, _string(name)->_val, \"existing local variable\");\n    if (_string(name) == _string(_fs->_name))\n        reportDiagnostic(n, DiagnosticsId::DI_CONFLICTS_WITH, desc, _stringval(name), \"function name\");\n\n    SQObjectPtr constant;\n    if (ignore_global_consts ? IsLocalConstant(name, constant) : IsConstant(name, constant))\n        reportDiagnostic(n, DiagnosticsId::DI_CONFLICTS_WITH, desc, _stringval(name), \"existing constant/enum/import\");\n}\n\nstatic bool compareLiterals(LiteralExpr *a, LiteralExpr *b) {\n    if (a->kind() != b->kind()) return false;\n    if (a->kind() == LK_STRING) {\n        return strcmp(a->s(), b->s()) == 0;\n    }\n\n    return a->raw() == b->raw();\n}\n\n#ifdef _SQ64\n# define SQ_UINT_FMT PRIu64\n#else\n# define SQ_UINT_FMT PRIuPTR\n#endif // _SQ64\n\nbool CodeGenVisitor::CheckMemberUniqueness(ArenaVector<Expr *> &vec, Expr *obj) {\n\n    if (obj->op() != TO_LITERAL && obj->op() != TO_ID) return true;\n\n    for (SQUnsignedInteger i = 0, n = vec.size(); i < n; ++i) {\n        Expr *vecobj = vec[i];\n        if (vecobj->op() == TO_ID && obj->op() == TO_ID) {\n            if (strcmp(vecobj->asId()->name(), obj->asId()->name()) == 0) {\n                reportDiagnostic(obj, DiagnosticsId::DI_DUPLICATE_KEY, obj->asId()->name());\n                return false;\n            }\n            continue;\n        }\n        if (vecobj->op() == TO_LITERAL && obj->op() == TO_LITERAL) {\n            LiteralExpr *a = (LiteralExpr*)vecobj;\n            LiteralExpr *b = (LiteralExpr*)obj;\n            if (compareLiterals(a, b)) {\n                if (a->kind() == LK_STRING) {\n                    reportDiagnostic(obj, DiagnosticsId::DI_DUPLICATE_KEY, a->s());\n                }\n                else {\n                    char b[32] = { 0 };\n                    snprintf(b, sizeof b, \"%\" SQ_UINT_FMT, a->raw());\n                    reportDiagnostic(obj, DiagnosticsId::DI_DUPLICATE_KEY, b);\n                }\n                return false;\n            }\n            continue;\n        }\n    }\n\n    vec.push_back(obj);\n    return true;\n}\n\nvoid CodeGenVisitor::EmitLoadConstInt(SQInteger value, SQInteger target)\n{\n    if (target < 0) {\n        target = _fs->PushTarget();\n    }\n    if (value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits?\n        _fs->AddInstruction(_OP_LOADINT, target, value);\n    }\n    else {\n        _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\n    }\n}\n\nvoid CodeGenVisitor::EmitLoadConstFloat(SQFloat value, SQInteger target)\n{\n    if (target < 0) {\n        target = _fs->PushTarget();\n    }\n    if (sizeof(SQFloat) == sizeof(SQInt32)) {\n        _fs->AddInstruction(_OP_LOADFLOAT, target, *((SQInt32 *)&value));\n    }\n    else {\n        _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));\n    }\n}\n\nvoid CodeGenVisitor::ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)\n{\n    while (ntoresolve > 0) {\n        SQInteger pos = funcstate->_unresolvedbreaks.back();\n        funcstate->_unresolvedbreaks.pop_back();\n        //set the jmp instruction\n        funcstate->SetInstructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);\n        ntoresolve--;\n    }\n}\n\n\nvoid CodeGenVisitor::ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)\n{\n    while (ntoresolve > 0) {\n        SQInteger pos = funcstate->_unresolvedcontinues.back();\n        funcstate->_unresolvedcontinues.pop_back();\n        //set the jmp instruction\n        funcstate->SetInstructionParams(pos, 0, targetpos - pos, 0);\n        ntoresolve--;\n    }\n}\n\n\nvoid CodeGenVisitor::EmitDerefOp(SQOpcode op)\n{\n    SQInteger val = _fs->PopTarget();\n    SQInteger key = _fs->PopTarget();\n    SQInteger src = _fs->PopTarget();\n    _fs->AddInstruction(op, _fs->PushTarget(), src, key, val);\n}\n\n\nvoid CodeGenVisitor::EmitCheckType(int target, uint32_t type_mask)\n{\n#if SQ_RUNTIME_TYPE_CHECK\n    if (type_mask != ~0u && target < 256)\n        _fs->AddInstruction(_OP_CHECK_TYPE, target, type_mask);\n#else\n    (void)target;\n    (void)type_mask;\n#endif\n}\n\n\nvoid CodeGenVisitor::visitBlock(Block *block) {\n    addLineNumber(block);\n\n    BEGIN_SCOPE();\n\n    ArenaVector<Statement *> &statements = block->statements();\n\n    for (auto stmt : statements) {\n        stmt->visit(this);\n        _fs->SnoozeOpt();\n    }\n\n    if (block->isBody() || block->isRoot()) {\n        END_SCOPE_NO_CLOSE();\n    }\n    else {\n        END_SCOPE();\n    }\n}\n\n\nvoid CodeGenVisitor::visitIfStatement(IfStatement *ifStmt) {\n    addLineNumber(ifStmt);\n    BEGIN_SCOPE();\n\n    visitForValueMaybeStaticMemo(ifStmt->condition());\n\n    _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n    SQInteger jnepos = _fs->GetCurrentPos();\n\n    ifStmt->thenBranch()->visit(this);\n\n    SQInteger endifblock = _fs->GetCurrentPos();\n\n    if (ifStmt->elseBranch()) {\n        _fs->AddInstruction(_OP_JMP);\n        SQInteger jmppos = _fs->GetCurrentPos();\n        ifStmt->elseBranch()->visit(this);\n        _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\n    }\n\n    _fs->SetInstructionParam(jnepos, 1, endifblock - jnepos + (ifStmt->elseBranch() ? 1 : 0));\n    END_SCOPE();\n}\n\nvoid CodeGenVisitor::visitWhileStatement(WhileStatement *whileLoop) {\n    addLineNumber(whileLoop);\n    _complexity_level++;\n\n    BEGIN_SCOPE();\n    {\n        SQInteger jmppos = _fs->GetCurrentPos();\n\n        visitForValue(whileLoop->condition());\n\n        BEGIN_BREAKABLE_BLOCK();\n\n        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n\n        SQInteger jzpos = _fs->GetCurrentPos();\n\n        BEGIN_SCOPE();\n\n        whileLoop->body()->visit(this);\n\n        END_SCOPE();\n\n        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);\n        _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\n\n        END_BREAKABLE_BLOCK(jmppos);\n    }\n    END_SCOPE();\n\n    _complexity_level--;\n}\n\nvoid CodeGenVisitor::visitDoWhileStatement(DoWhileStatement *doWhileLoop) {\n    addLineNumber(doWhileLoop);\n    _complexity_level++;\n\n    BEGIN_SCOPE();\n    {\n        SQInteger jmptrg = _fs->GetCurrentPos();\n        BEGIN_BREAKABLE_BLOCK();\n\n        BEGIN_SCOPE();\n        doWhileLoop->body()->visit(this);\n        END_SCOPE();\n\n        SQInteger continuetrg = _fs->GetCurrentPos();\n        visitForValue(doWhileLoop->condition());\n\n        _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);\n        _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);\n        END_BREAKABLE_BLOCK(continuetrg);\n\n    }\n    END_SCOPE();\n\n    _complexity_level--;\n}\n\nvoid CodeGenVisitor::visitForStatement(ForStatement *forLoop) {\n    addLineNumber(forLoop);\n\n    _complexity_level++;\n    BEGIN_SCOPE();\n\n    if (forLoop->initializer()) {\n        Node *init = forLoop->initializer();\n        visitForValue(init);\n        if (init->isExpression()) {\n            _fs->PopTarget();\n        }\n    }\n\n    _fs->SnoozeOpt();\n    SQInteger jzpos = -1;\n\n    if (forLoop->condition()) {\n        _fs->SnoozeOpt();\n        visitForValue(forLoop->condition());\n        _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n        jzpos = _fs->GetCurrentPos();\n    }\n    SQInteger jmppos = _fs->GetCurrentPos();\n\n    SQInteger expstart = _fs->GetCurrentPos() + 1;\n\n    if (forLoop->modifier()) {\n        _fs->SnoozeOpt();\n        visitForValue(forLoop->modifier());\n        _fs->PopTarget();\n    }\n\n    SQInteger expend = _fs->GetCurrentPos();\n    SQInteger expsize = (expend - expstart) + 1;\n    ArenaVector<SQInstruction> exp(_arena);\n\n    if (expsize > 0) {\n        for (SQInteger i = 0; i < expsize; i++)\n            exp.push_back(_fs->GetInstruction(expstart + i));\n        _fs->PopInstructions(expsize);\n    }\n\n    _fs->SnoozeOpt();\n\n    BEGIN_BREAKABLE_BLOCK();\n    forLoop->body()->visit(this);\n    SQInteger continuetrg = _fs->GetCurrentPos();\n    if (expsize > 0) {\n        for (SQInteger i = 0; i < expsize; i++)\n            _fs->AddInstruction(exp[i]);\n    }\n\n    if (forLoop->condition()) {\n        _fs->SnoozeOpt();\n        visitForValue(forLoop->condition());\n        const int cmpPos = _fs->GetCurrentPos();\n        _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), jmppos - cmpPos, 1);\n        if (cmpPos != _fs->GetCurrentPos()) // instruction was optimized\n          _fs->SetInstructionParam(_fs->GetCurrentPos(), 1, jmppos - cmpPos - 1);\n    } else\n        _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);\n    if (jzpos > 0) _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);\n    _fs->RestoreOpt();\n\n    END_BREAKABLE_BLOCK(continuetrg);\n\n    END_SCOPE();\n    _complexity_level--;\n}\n\n// Returns true if any Id node behind a function/lambda boundary inside body\n// matches name0 or name1 (either may be null). Over-approximates: an inner\n// same-named local that shadows the outer still counts as a hit. Cost of a\n// false positive is one MOVE per binding + one OP_CLOSE per iteration, so\n// the simpler scan wins.\nclass CaptureScanVisitor : public Visitor {\npublic:\n    bool captured = false;\n    int fnDepth = 0;\n    const char *name0 = nullptr;\n    const char *name1 = nullptr;\n    uint64_t bitFilter = 0; // bit i set if any tracked name starts with char c where c%64 == i\n\n    virtual void visitId(Id *id) override {\n        if (captured || fnDepth == 0)\n            return;\n        const char *nm = id->name();\n        if ((bitFilter & (uint64_t(1) << (uint8_t(nm[0]) & 63))) == 0)\n            return;\n        if ((name0 && strcmp(name0, nm) == 0) || (name1 && strcmp(name1, nm) == 0))\n            captured = true;\n    }\n\n    virtual void visitFunctionExpr(FunctionExpr *f) override {\n        if (captured)\n            return;\n        fnDepth++;\n        f->visitChildren(this);\n        fnDepth--;\n    }\n};\n\nstatic bool scanCaptureForNames(Statement *body, const char *name0, const char *name1) {\n    if (!name0 && !name1)\n        return false;\n    CaptureScanVisitor v;\n    v.name0 = name0;\n    v.name1 = name1;\n    if (name0)\n        v.bitFilter |= uint64_t(1) << (uint8_t(name0[0]) & 63);\n    if (name1)\n        v.bitFilter |= uint64_t(1) << (uint8_t(name1[0]) & 63);\n    body->visit(&v);\n    return v.captured;\n}\n\nvoid CodeGenVisitor::visitForeachStatement(ForeachStatement *foreachLoop) {\n    addLineNumber(foreachLoop);\n    _complexity_level++;\n\n    BEGIN_SCOPE();\n\n    visitForValue(foreachLoop->container());\n\n    SQInteger container = _fs->TopTarget();\n\n    assert(foreachLoop->val()->op() == TO_VAR && ((VarDecl *)foreachLoop->val())->initializer() == nullptr);\n    const char *userValName = ((VarDecl *)foreachLoop->val())->name();\n    const char *userIdxName = foreachLoop->idx() ? ((VarDecl *)foreachLoop->idx())->name() : nullptr;\n\n    // Parser-emitted destructuring surrogate: source code can't reference it\n    // (lexer can't produce '@'), so it never gets captured and never needs\n    // per-iter rebinding.\n    bool valIsSurrogate = userValName && strncmp(userValName, \"@FE_VAL\", 7) == 0;\n\n    // Detect if any user-visible name (idx, val) is captured by an inner\n    // function inside body. When captured, we re-bind those names in a\n    // per-iteration scope inside the body region so END_SCOPE emits _OP_CLOSE\n    // every iter, giving each closure its own frozen copy of the value.\n    bool perIterScope = scanCaptureForNames(foreachLoop->body(),\n        userIdxName,\n        (userValName && !valIsSurrogate) ? userValName : nullptr);\n\n    // Outer-scope names: when a user-visible name will be re-bound per-iter,\n    // hide the outer slot under a surrogate so source references resolve to\n    // the per-iter binding.\n    SQObjectPtr idxName = (userIdxName && !perIterScope)\n        ? _fs->CreateString(userIdxName)\n        : _fs->CreateString(\"@INDEX@\");\n    SQInteger indexpos = _fs->PushLocalVariable(idxName, SQCompiletimeVarInfo{});\n\n    SQObjectPtr valName = (userValName && !valIsSurrogate && perIterScope)\n        ? _fs->CreateString(\"@valouter@\")\n        : _fs->CreateString(userValName);\n    SQInteger valpos = _fs->PushLocalVariable(valName, SQCompiletimeVarInfo{});\n\n    //push reference index\n    _fs->PushLocalVariable(_fs->CreateString(\"@ITERATOR@\"), SQCompiletimeVarInfo{}); //use invalid id to make it inaccessible\n\n    _fs->AddInstruction(_OP_PREFOREACH, container, 0, indexpos);\n    SQInteger preForEachPos = _fs->GetCurrentPos();\n    _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);\n    SQInteger postForEachPos = _fs->GetCurrentPos();\n\n    BEGIN_BREAKABLE_BLOCK();\n\n    if (perIterScope) {\n        BEGIN_SCOPE();\n        if (userIdxName) {\n            SQInteger pos = _fs->PushLocalVariable(_fs->CreateString(userIdxName), SQCompiletimeVarInfo{});\n            _fs->AddInstruction(_OP_MOVE, pos, indexpos);\n        }\n        if (userValName && !valIsSurrogate) {\n            SQInteger pos = _fs->PushLocalVariable(_fs->CreateString(userValName), SQCompiletimeVarInfo{});\n            _fs->AddInstruction(_OP_MOVE, pos, valpos);\n        }\n        foreachLoop->body()->visit(this);\n        END_SCOPE();\n    } else {\n        foreachLoop->body()->visit(this);\n    }\n\n    SQInteger continuePos = _fs->GetCurrentPos();\n    SQInteger forEachLabelPos = _fs->GetCurrentPos() + 1;\n    _fs->AddInstruction(_OP_FOREACH, container, postForEachPos - forEachLabelPos, indexpos); //ip is already + 1 now\n    _fs->SetInstructionParam(preForEachPos, 1, forEachLabelPos - preForEachPos); //ip is already + 1 now\n    _fs->SetInstructionParam(postForEachPos, 1, _fs->GetCurrentPos() - postForEachPos); //ip is already + 1 now\n\n    END_BREAKABLE_BLOCK(continuePos);\n    //restore the local variable stack(remove index,val and ref idx)\n    _fs->PopTarget();\n    END_SCOPE();\n\n    _complexity_level--;\n}\n\nvoid CodeGenVisitor::visitSwitchStatement(SwitchStatement *swtch) {\n    addLineNumber(swtch);\n    BEGIN_SCOPE();\n\n    visitForValue(swtch->expression());\n\n    SQInteger expr = _fs->TopTarget();\n    SQInteger tonextcondjmp = -1;\n    SQInteger skipcondjmp = -1;\n    SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();\n\n    _fs->_breaktargets.push_back(0);\n    _fs->_blockstacksizes.push_back(_scope.stacksize);\n    ArenaVector<SwitchCase> &cases = swtch->cases();\n\n    for (SQUnsignedInteger i = 0; i < cases.size(); ++i) {\n        if (i) {\n            _fs->AddInstruction(_OP_JMP, 0, 0);\n            skipcondjmp = _fs->GetCurrentPos();\n            _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\n        }\n\n        const SwitchCase &c = cases[i];\n\n        visitForValueMaybeStaticMemo(c.val);\n\n        SQInteger trg = _fs->PopTarget();\n        SQInteger eqtarget = trg;\n        bool local = _fs->IsLocal(trg);\n        if (local) {\n            eqtarget = _fs->PushTarget(); //we need to allocate a extra reg\n        }\n\n        _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr);\n        _fs->AddInstruction(_OP_JZ, eqtarget, 0);\n        if (local) {\n            _fs->PopTarget();\n        }\n\n        //end condition\n        if (skipcondjmp != -1) {\n            _fs->SetInstructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));\n        }\n        tonextcondjmp = _fs->GetCurrentPos();\n\n        BEGIN_SCOPE();\n        c.stmt->visit(this);\n        END_SCOPE();\n    }\n\n    if (tonextcondjmp != -1)\n        _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);\n\n    const SwitchCase &d = swtch->defaultCase();\n\n    if (d.stmt) {\n        BEGIN_SCOPE();\n        d.stmt->visit(this);\n        END_SCOPE();\n    }\n\n    _fs->PopTarget();\n    __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;\n    if (__nbreaks__ > 0) ResolveBreaks(_fs, __nbreaks__);\n    _fs->_breaktargets.pop_back();\n    _fs->_blockstacksizes.pop_back();\n    END_SCOPE();\n}\n\nvoid CodeGenVisitor::visitTryStatement(TryStatement *tryStmt) {\n    addLineNumber(tryStmt);\n    _fs->AddInstruction(_OP_PUSHTRAP, 0, 0);\n    _fs->_traps++;\n\n    if (_fs->_breaktargets.size()) _fs->_breaktargets.top()++;\n    if (_fs->_continuetargets.size()) _fs->_continuetargets.top()++;\n\n    SQInteger trappos = _fs->GetCurrentPos();\n    {\n        BEGIN_SCOPE();\n        tryStmt->tryStatement()->visit(this);\n        END_SCOPE();\n    }\n\n    _fs->_traps--;\n    _fs->AddInstruction(_OP_POPTRAP, 1, 0);\n    if (_fs->_breaktargets.size()) _fs->_breaktargets.top()--;\n    if (_fs->_continuetargets.size()) _fs->_continuetargets.top()--;\n    _fs->AddInstruction(_OP_JMP, 0, 0);\n    SQInteger jmppos = _fs->GetCurrentPos();\n    _fs->SetInstructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));\n\n    {\n        BEGIN_SCOPE();\n        SQInteger ex_target = _fs->PushLocalVariable(_fs->CreateString(tryStmt->exceptionId()->name()), SQCompiletimeVarInfo{});\n        _fs->SetInstructionParam(trappos, 0, ex_target);\n        tryStmt->catchStatement()->visit(this);\n        _fs->SetInstructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);\n        END_SCOPE();\n    }\n}\n\nvoid CodeGenVisitor::visitBreakStatement(BreakStatement *breakStmt) {\n    addLineNumber(breakStmt);\n    if (_fs->_breaktargets.size() <= 0)\n        reportDiagnostic(breakStmt, DiagnosticsId::DI_LOOP_CONTROLLER_NOT_IN_LOOP, \"break\");\n    if (_fs->_breaktargets.top() > 0) {\n        _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);\n    }\n    RESOLVE_OUTERS();\n    _fs->AddInstruction(_OP_JMP, 0, -1234);\n    _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());\n}\n\nvoid CodeGenVisitor::visitContinueStatement(ContinueStatement *continueStmt) {\n    addLineNumber(continueStmt);\n    if (_fs->_continuetargets.size() <= 0 || _fs->_continuetargets.top() < 0)\n        reportDiagnostic(continueStmt, DiagnosticsId::DI_LOOP_CONTROLLER_NOT_IN_LOOP, \"continue\");\n    if (_fs->_continuetargets.top() > 0) {\n        _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);\n    }\n    RESOLVE_OUTERS();\n    _fs->AddInstruction(_OP_JMP, 0, -1234);\n    _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());\n}\n\nvoid CodeGenVisitor::visitTerminateStatement(TerminateStatement *terminator) {\n    addLineNumber(terminator);\n\n    if (terminator->argument()) {\n        visitForValueMaybeStaticMemo(terminator->argument());\n    }\n}\n\nvoid CodeGenVisitor::visitReturnStatement(ReturnStatement *retStmt) {\n    SQInteger retexp = _fs->GetCurrentPos() + 1;\n    visitTerminateStatement(retStmt);\n\n    if (!_fs->_expr_block_results.empty()) {\n        // Inside a CodeBlockExpr: return is compiled as a break (MOVE+JMP),\n        // not a real function return. Only pop traps local to this block,\n        // not the entire function's traps.\n        if (_fs->_breaktargets.top() > 0) {\n            _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);\n        }\n        if (retStmt->argument()) {\n            _fs->AddInstruction(_OP_MOVE, _fs->_expr_block_results.back(), _fs->PopTarget());\n        } else {\n            _fs->AddInstruction(_OP_LOADNULLS, _fs->_expr_block_results.back(), 1);\n        }\n        RESOLVE_OUTERS();\n        _fs->AddInstruction(_OP_JMP, 0, -1234);\n        _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());\n    } else {\n        if (_fs->_traps > 0) {\n            _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);\n        }\n        if (retStmt->argument()) {\n            _fs->_returnexp = retexp;\n            int target = _fs->PopTarget();\n            if (!_fs->_bgenerator) {\n                if (!checkInferredType(retStmt, retStmt->argument(), _fs->_result_type_mask))\n                    EmitCheckType(target, _fs->_result_type_mask);\n            }\n            _fs->AddInstruction(_OP_RETURN, 1, target);\n        } else {\n            if ((_fs->_result_type_mask & _RT_NULL) == 0 && !_fs->_bgenerator)\n                reportDiagnostic(retStmt, DiagnosticsId::DI_TYPE_DIFFERS, \"Return\");\n            _fs->_returnexp = -1;\n            _fs->AddInstruction(_OP_RETURN, 0xFF, 0);\n        }\n    }\n}\n\nvoid CodeGenVisitor::visitYieldStatement(YieldStatement *yieldStmt) {\n    SQInteger retexp = _fs->GetCurrentPos() + 1;\n    _fs->_bgenerator = true;\n    visitTerminateStatement(yieldStmt);\n\n    if (yieldStmt->argument()) {\n        _fs->_returnexp = retexp;\n        int target = _fs->PopTarget();\n        if (!checkInferredType(yieldStmt, yieldStmt->argument(), _fs->_result_type_mask))\n            EmitCheckType(target, _fs->_result_type_mask);\n        _fs->AddInstruction(_OP_YIELD, 1, target, _fs->GetStackSize());\n    }\n    else {\n        if ((_fs->_result_type_mask & _RT_NULL) == 0)\n            reportDiagnostic(yieldStmt, DiagnosticsId::DI_TYPE_DIFFERS, \"Yield\");\n        _fs->_returnexp = -1;\n        _fs->AddInstruction(_OP_YIELD, 0xFF, 0, _fs->GetStackSize());\n    }\n}\n\nvoid CodeGenVisitor::visitThrowStatement(ThrowStatement *throwStmt) {\n    visitTerminateStatement(throwStmt);\n    _fs->AddInstruction(_OP_THROW, _fs->PopTarget());\n}\n\nbool CodeGenVisitor::DoesObjectContainOnlySimpleObjects(const SQObject &obj, int depth) {\n    if (sq_isnumeric(obj) || sq_isstring(obj) || sq_isbool(obj) || sq_isnull(obj))\n        return true;\n\n    if (sq_is_pure_function(const_cast<SQObject *>(&obj)))\n        return true;\n\n    if (depth > 80)\n        return false;\n\n    if (sq_istable(obj)) {\n        SQInteger idx = 0;\n        SQObjectPtr key, val;\n        while ((idx = _table(obj)->Next(true, SQObjectPtr(idx), key, val)) != -1) {\n            if (!DoesObjectContainOnlySimpleObjects(key, depth + 1))\n                return false;\n            if (!DoesObjectContainOnlySimpleObjects(val, depth + 1))\n                return false;\n        }\n\n        return true;\n    }\n\n    if (sq_isclass(obj)) {\n        SQInteger idx = 0;\n        SQObjectPtr key, val;\n        while ((idx = _class(obj)->Next(SQObjectPtr(idx), key, val)) != -1) {\n            if (!DoesObjectContainOnlySimpleObjects(key, depth + 1))\n                return false;\n            if (!DoesObjectContainOnlySimpleObjects(val, depth + 1))\n                return false;\n        }\n\n        return true;\n    }\n\n    if (sq_isarray(obj)) {\n        SQInteger idx = 0;\n        SQObjectPtr key, val;\n        while ((idx = _array(obj)->Next(SQObjectPtr(idx), key, val)) != -1) {\n            if (!DoesObjectContainOnlySimpleObjects(val, depth + 1))\n                return false;\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\nbool CodeGenVisitor::IsSimpleConstant(const SQObject &name) {\n    SQObjectPtr c;\n\n    if (!IsConstant(name, c))\n        return false;\n\n    return DoesObjectContainOnlySimpleObjects(c, 0);\n}\n\nExpr *CodeGenVisitor::skipConstFreezePure(Expr *expr) {\n    for (;;) {\n        if (expr->op() == TO_STATIC_MEMO || expr->op() == TO_PAREN)\n            expr = static_cast<UnExpr*>(expr)->argument();\n        else if (isFreezeCall(expr))\n            expr = static_cast<CallExpr *>(expr)->arguments()[0];\n        else\n            break;\n    }\n\n    return expr;\n}\n\n\nclass GuaranteedPurityCheckVisitor : public Visitor {\n    SQVM *_vm;\n    SQFuncState *_fs = nullptr;\npublic:\n    bool pure;\n    GuaranteedPurityCheckVisitor(SQVM *vm, SQFuncState *fs) : pure(true), _vm(vm), _fs(fs) {}\n\n    virtual void visitNode(Node *node) override {\n        if (!pure)\n            return;\n\n        switch (node->op()) {\n            case TO_THROW:\n            case TO_YIELD:\n                pure = false;\n                break;\n\n            case TO_ID: {\n                    SQObjectPtr name(SQString::Create(_ss(_vm), static_cast<Id *>(node)->name()));\n                    SQCompiletimeVarInfo varInfo;\n                    if (_fs->GetLocalVariable(name, varInfo) != -1 || _fs->GetOuterVariable(name, varInfo) != -1) {\n                        pure = false;\n                        break;\n                    }\n                }\n                break;\n\n            default:\n                node->visitChildren(this);\n                break;\n        }\n    }\n};\n\n\nbool CodeGenVisitor::IsGuaranteedPureFunction(Node *expr) {\n    GuaranteedPurityCheckVisitor visitor(_vm, _fs);\n    expr->visit(&visitor);\n    return visitor.pure;\n}\n\nbool CodeGenVisitor::isConstScoredMethodCall(GetFieldExpr *getField) {\n    Expr *receiver = deparen(getField->receiver());\n    if (getSubtreeConstScoreImpl(receiver) == 0) {\n        _variable_node = getField->receiver();\n        return false;\n    }\n    SQInteger type = inferReceiverType(receiver);\n    SQObjectPtr method = GetTypeMethod(type, getField->fieldName());\n    return sq_is_pure_function(&method);\n}\n\nbool CodeGenVisitor::isConstScoredDirectCall(CallExpr *callExpr) {\n    if (isPureFunctionCall(callExpr))\n        return true;\n    Expr *callee = deparen(callExpr->callee());\n    SQObjectPtr calleeName = _fs->CreateString(callee->asId()->name());\n    SQCompiletimeVarInfo varInfo;\n    if (findConstScoredVar(calleeName, varInfo, VF_INIT_WITH_PURE))\n        return true;\n    SQObjectPtr c;\n    return IsConstant(calleeName, c) && sq_is_pure_function(&c);\n}\n\nSQInteger CodeGenVisitor::inferReceiverType(Expr *receiver) {\n    if (receiver->op() == TO_ID) {\n        SQObjectPtr c;\n        SQObjectPtr name = _fs->CreateString(receiver->asId()->name());\n        if (IsConstant(name, c)) {\n            SQInteger type = sq_type(c);\n            if ((type == OT_TABLE || type == OT_CLASS || type == OT_ARRAY) &&\n                (c._flags & SQOBJ_FLAG_IMMUTABLE) == 0)\n                return -1;\n            return type;\n        }\n        SQCompiletimeVarInfo varInfo;\n        if (findConstScoredVar(name, varInfo,\n                VF_INIT_WITH_CONST | VF_INIT_WITH_FREEZE | VF_INIT_WITH_PURE))\n            receiver = skipConstFreezePure(varInfo.initializer);\n    }\n\n    if (receiver->op() == TO_LITERAL) {\n        switch (receiver->asLiteral()->kind()) {\n            case LK_STRING: return OT_STRING;\n            case LK_INT:    return OT_INTEGER;\n            case LK_FLOAT:  return OT_FLOAT;\n            case LK_BOOL:   return OT_BOOL;\n            case LK_NULL:   return OT_NULL;\n            default:        return -1;\n        }\n    }\n    if (receiver->op() == TO_TABLE) return OT_TABLE;\n    if (receiver->op() == TO_CLASS) return OT_CLASS;\n    if (receiver->op() == TO_ARRAY) return OT_ARRAY;\n    return -1;\n}\n\nbool CodeGenVisitor::findConstScoredVar(const SQObjectPtr &name,\n    SQCompiletimeVarInfo &varInfo, unsigned requiredFlags)\n{\n    if (_fs->GetLocalVariable(name, varInfo) == -1 &&\n        _fs->GetOuterVariable(name, varInfo) == -1)\n        return false;\n    return (varInfo.var_flags & requiredFlags) != 0 &&\n           (varInfo.var_flags & (VF_DESTRUCTURED | VF_ASSIGNABLE)) == 0;\n}\n\n// 0 - not const\nint CodeGenVisitor::getSubtreeConstScore(Node *node, bool visit_arrays_and_tables) {\n    _variable_node = nullptr;\n    _visit_arrays_and_tables = visit_arrays_and_tables;\n    return getSubtreeConstScoreImpl(node);\n}\n\nint CodeGenVisitor::getSubtreeConstScoreImpl(Node *node) {\n    switch (node->op()) {\n        case TO_NULLC:\n        case TO_OROR:\n        case TO_ANDAND:\n        case TO_OR:\n        case TO_XOR:\n        case TO_AND:\n        case TO_NE:\n        case TO_EQ:\n        case TO_3CMP:\n        case TO_GE:\n        case TO_GT:\n        case TO_LE:\n        case TO_LT:\n        case TO_IN:\n        case TO_INSTANCEOF:\n        case TO_USHR:\n        case TO_SHR:\n        case TO_SHL:\n        case TO_MUL:\n        case TO_DIV:\n        case TO_MOD:\n        case TO_ADD:\n        case TO_SUB: {\n            BinExpr *binExpr = static_cast<BinExpr *>(node);\n            int s1 = getSubtreeConstScoreImpl(binExpr->lhs());\n            int s2 = getSubtreeConstScoreImpl(binExpr->rhs());\n            if (s1 == 0 || s2 == 0)\n                return 0;\n\n            return s1 + s2 + 1;\n        }\n\n        case TO_NOT:\n        case TO_BNOT:\n        case TO_NEG:\n        case TO_TYPEOF:\n        case TO_PAREN: {\n            UnExpr *unExpr = static_cast<UnExpr *>(node);\n            int s = getSubtreeConstScoreImpl(unExpr->argument());\n            return s > 0 ? s + 1 : 0;\n        }\n\n        case TO_STATIC_MEMO: {\n            return 9999;\n        }\n\n        case TO_INLINE_CONST: {\n            return 1; // the same as const identifier\n        }\n\n        case TO_TERNARY: {\n            TerExpr *terExpr = static_cast<TerExpr *>(node);\n            int s1 = getSubtreeConstScoreImpl(terExpr->a());\n            int s2 = getSubtreeConstScoreImpl(terExpr->b());\n            int s3 = getSubtreeConstScoreImpl(terExpr->c());\n            if (s1 > 0 && s2 > 0 && s3 > 0)\n                return s1 + s2 + s3 + 1;\n\n            return 0;\n        }\n\n        case TO_CALL: {\n            CallExpr *callExpr = static_cast<CallExpr *>(node);\n            Expr *callee = deparen(callExpr->callee());\n\n            if (callee->op() == TO_GETFIELD) {\n                if (!isConstScoredMethodCall(callee->asGetField())) {\n                    if (!_variable_node) _variable_node = node;\n                    return 0;\n                }\n            }\n            else if (callee->op() == TO_ID) {\n                if (!isConstScoredDirectCall(callExpr)) {\n                    _variable_node = node;\n                    return 0;\n                }\n            }\n            else {\n                _variable_node = node;\n                return 0;\n            }\n\n            int res = 20;\n            for (Expr *arg : callExpr->arguments()) {\n                int s = getSubtreeConstScoreImpl(arg);\n                if (s == 0)\n                    return 0;\n                res += s + 1;\n            }\n            return res;\n        }\n\n        case TO_ID: {\n            Id *id = node->asId();\n            SQObjectPtr name = _fs->CreateString(id->name());\n\n            SQObjectPtr c;\n            if (IsConstant(name, c))\n                return 1;\n\n            SQCompiletimeVarInfo varInfo;\n            if (findConstScoredVar(name, varInfo, VF_INIT_WITH_CONST | VF_INIT_WITH_FREEZE))\n                return 1;\n\n            _variable_node = node;\n            return 0;\n        }\n\n        case TO_GETSLOT: {\n            GetSlotExpr *expr = static_cast<GetSlotExpr *>(node);\n\n            Expr *receiver = expr->receiver();\n            int s1 = getSubtreeConstScoreImpl(receiver);\n            if (s1 == 0) {\n                _variable_node = receiver;\n                return 0;\n            }\n\n            if (receiver->op() == TO_ID) {\n                SQObjectPtr name = _fs->CreateString(receiver->asId()->name());\n                SQCompiletimeVarInfo varInfo;\n                if (findConstScoredVar(name, varInfo, VF_INIT_WITH_CONST | VF_INIT_WITH_FREEZE | VF_INIT_WITH_PURE))\n                    receiver = skipConstFreezePure(varInfo.initializer);\n            }\n\n            if (receiver->op() == TO_LITERAL) {\n                if (receiver->asLiteral()->kind() != LK_STRING) {\n                    _variable_node = expr->receiver();\n                    return 0;\n                }\n            }\n            else if (receiver->op() == TO_TABLE || receiver->op() == TO_CLASS) {\n                // Table and class expressions are allowed\n            }\n            else if (receiver->op() == TO_ID) {\n                SQObjectPtr name = _fs->CreateString(receiver->asId()->name());\n                if (!IsSimpleConstant(name)) {\n                    _variable_node = expr->receiver();\n                    return 0;\n                }\n            }\n            else if (receiver->op() != TO_ARRAY) {\n                _variable_node = expr->receiver();\n                return 0;\n            }\n\n            int s2 = getSubtreeConstScoreImpl(expr->key());\n            if (s2 == 0) {\n                _variable_node = expr->key();\n                return 0;\n            }\n\n            return s1 + s2 + 1;\n        }\n\n        case TO_GETFIELD: {\n            GetFieldExpr *expr = static_cast<GetFieldExpr *>(node);\n\n            int s = getSubtreeConstScoreImpl(expr->receiver());\n            if (s == 0) {\n                _variable_node = expr->receiver();\n                return 0;\n            }\n\n            Expr *receiver = deparen(expr->receiver());\n            if (receiver->op() == TO_ID) {\n                SQObjectPtr name = _fs->CreateString(receiver->asId()->name());\n                SQObjectPtr c;\n                if (IsConstant(name, c) || IsSimpleConstant(name))\n                    return s + 2;\n            }\n            else if (receiver->op() == TO_GETFIELD)\n                return s + 2;\n\n            _variable_node = expr->receiver();\n            return 0;\n        }\n\n        case TO_LITERAL:\n            return 1;\n\n        case TO_FUNCTION: {\n            if (IsGuaranteedPureFunction(node))\n                return 10;\n            else {\n                _variable_node = node;\n                return 0;\n            }\n        }\n\n        case TO_TABLE:\n        case TO_CLASS: {\n            if (!_visit_arrays_and_tables) {\n                _variable_node = node;\n                return 0;\n            }\n\n            ArenaVector<TableMember> &members = static_cast<TableExpr *>(node)->members();\n            int res = 50;\n            for (TableMember &m : members) {\n                int s1 = getSubtreeConstScoreImpl(m.key);\n                int s2 = getSubtreeConstScoreImpl(m.value);\n                if (s1 == 0 || s2 == 0)\n                    return 0;\n\n                res += s1 + s2 + 1;\n            }\n\n            return res;\n        }\n\n        case TO_ARRAY: {\n            if (!_visit_arrays_and_tables) {\n                _variable_node = node;\n                return 0;\n            }\n\n            ArenaVector<Expr *> &initializers = static_cast<ArrayExpr *>(node)->initializers();\n            int res = 50;\n            for (Expr *expr : initializers) {\n                int s = getSubtreeConstScoreImpl(expr);\n                if (s == 0)\n                    return 0;\n\n                res += s + 1;\n            }\n\n            return res;\n        }\n\n        default:\n            _variable_node = node;\n            return 0;\n    }\n}\n\nvoid CodeGenVisitor::visitCodeBlockExpr(CodeBlockExpr *expr) {\n    maybeAddInExprLine(expr);\n    SQInteger resultTarget = _fs->PushTarget();\n    BEGIN_SCOPE();\n\n    SQInteger nbreaks = _fs->_unresolvedbreaks.size();\n    _fs->_breaktargets.push_back(0);\n    _fs->_continuetargets.push_back(-1); // sentinel: not a loop, 'continue' is invalid\n    _fs->_blockstacksizes.push_back(_scope.stacksize);\n\n    _fs->_expr_block_results.push_back(resultTarget);\n\n    expr->block()->visit(this);\n\n    //_fs->AddInstruction(_OP_LOADNULLS, resultTarget, 1);\n\n    nbreaks = _fs->_unresolvedbreaks.size() - nbreaks;\n    if (nbreaks > 0)\n        ResolveBreaks(_fs, nbreaks);\n    _fs->_expr_block_results.pop_back();\n    _fs->_breaktargets.pop_back();\n    _fs->_continuetargets.pop_back();\n    _fs->_blockstacksizes.pop_back();\n\n    END_SCOPE();\n}\n\n\nvoid CodeGenVisitor::visitExprStatement(ExprStatement *stmt) {\n    addLineNumber(stmt);\n    visitForValue(stmt->expression());\n    _fs->DiscardTarget();\n}\n\nvoid CodeGenVisitor::generateTableExpr(TableExpr *tableDecl) {\n    bool isKlass = tableDecl->op() == TO_CLASS;\n    const auto &members = tableDecl->members();\n\n    ArenaVector<Expr *> memberConstantKeys(_arena);\n\n    for (SQUnsignedInteger i = 0; i < members.size(); ++i) {\n        const TableMember &m = members[i];\n#if SQ_LINE_INFO_IN_STRUCTURES\n        if (i < 100 && m.key->lineStart() != -1) {\n            _fs->AddLineInfos(m.key->lineStart(), false, false);\n        }\n#endif\n        CheckMemberUniqueness(memberConstantKeys, m.key);\n\n        bool isConstKey = m.key->op() == TO_LITERAL && !isKlass;\n        SQInteger constantI;\n        if (isConstKey)\n        {\n          switch(m.key->asLiteral()->kind())\n          {\n            case LK_STRING: constantI = _fs->GetConstant(_fs->CreateString(m.key->asLiteral()->s())); break;\n            case LK_INT: constantI = _fs->GetNumericConstant(m.key->asLiteral()->i()); break;\n            case LK_FLOAT: constantI = _fs->GetNumericConstant(m.key->asLiteral()->f()); break;\n            case LK_BOOL: constantI = _fs->GetConstant(SQObjectPtr(m.key->asLiteral()->b())); break;\n            case LK_NULL: constantI = _fs->GetConstant(SQObjectPtr()); break;\n            default: assert(0); break;\n          }\n          //isConstKey = constantI < 256; // since currently we store in arg1, it is sufficient\n        }\n\n        if (!isConstKey)\n            visitForValueMaybeStaticMemo(m.key);\n        visitForValueMaybeStaticMemo(m.value);\n\n        SQInteger val = _fs->PopTarget();\n        SQInteger key = isConstKey ? constantI : _fs->PopTarget();\n        SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE\n        assert(table < 256);\n\n        if (isKlass) {\n            _fs->AddInstruction(_OP_NEWSLOTA, m.isStatic() ? NEW_SLOT_STATIC_FLAG : 0, table, key, val);\n        }\n        else {\n            _fs->AddInstruction(isConstKey ? _OP_NEWSLOTK : _OP_NEWSLOT, 0xFF, key, table, val);\n        }\n    }\n}\n\nvoid CodeGenVisitor::addPatchDocObjectInstruction(const DocObject &docObject) {\n    int idx = (_ss(_vm)->doc_object_index += 2);\n    SaveDocstringToVM((void *)size_t(idx), docObject);\n    _fs->AddInstruction(_OP_PATCH_DOCOBJ, _fs->TopTarget(), idx, 0, 0);\n}\n\nvoid CodeGenVisitor::visitTableExpr(TableExpr *tableExpr) {\n    addLineNumber(tableExpr);\n    _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), tableExpr->members().size(), 0, NEWOBJ_TABLE);\n    if (!tableExpr->docObject.isEmpty())\n        addPatchDocObjectInstruction(tableExpr->docObject);\n\n    generateTableExpr(tableExpr);\n}\n\nvoid CodeGenVisitor::visitClassExpr(ClassExpr *klass) {\n    addLineNumber(klass);\n\n    Expr *baseExpr = klass->classBase();\n    SQInteger baseIdx = -1;\n    if (baseExpr) {\n        visitForValue(baseExpr);\n        baseIdx = _fs->PopTarget();\n    }\n\n    _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), baseIdx, 0, NEWOBJ_CLASS);\n    if (!klass->docObject.isEmpty())\n        addPatchDocObjectInstruction(klass->docObject);\n\n    generateTableExpr(klass);\n}\n\nstatic const char *varDeclKindDescription(VarDecl *var) {\n    Expr *init = var->initializer();\n    if (init == NULL) {\n        return var->isAssignable() ? \"Local variable\" : \"Named binding\";\n    }\n    else {\n        switch (init->op())\n        {\n        case TO_FUNCTION:\n            return \"Function\";\n        case TO_CLASS:\n            return \"Class\";\n        case TO_TABLE:\n            return \"Named binding\"; // <== is that correct?\n        default:\n            return var->isAssignable() ? \"Local variable\" : \"Named binding\";\n        }\n    }\n}\n\nbool CodeGenVisitor::isFreezeCall(Expr *node) {\n    node = deparen(node);\n    if (node->op() == TO_CALL) {\n        CallExpr *callExpr = static_cast<CallExpr *>(node);\n        Expr *callee = deparen(callExpr->callee());\n        if (callee->op() == TO_ID && !strcmp(callee->asId()->name(), \"freeze\") && callExpr->arguments().size() == 1)\n            return true;\n    }\n\n    return false;\n}\n\nbool CodeGenVisitor::isPureFunctionCall(Expr *node) {\n    node = deparen(node);\n    if (node->op() == TO_CALL) {\n        CallExpr *callExpr = static_cast<CallExpr *>(node);\n        Expr *callee = deparen(callExpr->callee());\n        if (callee->op() == TO_ID) {\n            SQObjectPtr name(SQString::Create(_ss(_vm), callee->asId()->name()));\n            SQObjectPtr constant;\n            // Find the function in the local scope\n            SQInteger pos = -1;\n            SQCompiletimeVarInfo varInfo;\n            if ((pos = _fs->GetLocalVariable(name, varInfo)) != -1\n             || (pos = _fs->GetOuterVariable(name, varInfo)) != -1) {\n                if (varInfo.initializer && varInfo.initializer->op() == TO_FUNCTION) {\n                    FunctionExpr *funcExpr = varInfo.initializer->asFunctionExpr();\n                    if (funcExpr->isPure()) {\n                        return true;\n                    }\n                }\n            }\n            else if (IsConstant(name, constant)) {\n                if (sq_is_pure_function(&constant)) {\n                    return true;\n                }\n            }\n        }\n    }\n    return false;\n}\n\nvoid CodeGenVisitor::visitVarDecl(VarDecl *var) {\n    addLineNumber(var);\n    const char *name = var->name();\n    char varFlags = var->isAssignable() ? VF_ASSIGNABLE : 0;\n    if (var->isDestructured())\n        varFlags |= VF_DESTRUCTURED;\n    if (_complexity_level == 0)\n        varFlags |= VF_FIRST_LEVEL;\n\n    SQObjectPtr varName = _fs->CreateString(name);\n\n    CheckDuplicateLocalIdentifier(var, varName, varDeclKindDescription(var), false);\n\n    if (var->initializer()) {\n        bool isStaticMemoInitializer = visitForValueMaybeStaticMemo(var->initializer());\n        if (isStaticMemoInitializer)\n            varFlags |= VF_INIT_WITH_CONST;\n        else if (isFreezeCall(var->initializer()))\n            varFlags |= VF_INIT_WITH_FREEZE;\n        else if (isPureFunctionCall(var->initializer()))\n            varFlags |= VF_INIT_WITH_PURE;\n\n        SQInteger src = _fs->PopTarget();\n        SQInteger dest = _fs->PushTarget();\n        if (dest != src) {\n            _fs->AddInstruction(_OP_MOVE, dest, src);\n        }\n\n        if (!checkInferredType(var, var->initializer(), var->getTypeMask()))\n            EmitCheckType(dest, var->getTypeMask());\n    }\n    else {\n        _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(), 1);\n        if ((var->getTypeMask() & _RT_NULL) == 0 && !var->isDestructured())\n            reportDiagnostic(var, DiagnosticsId::DI_TYPE_DIFFERS, \"Assigned null\");\n    }\n\n    _last_declared_var_pos = _fs->PopTarget();\n    _fs->PushLocalVariable(varName, SQCompiletimeVarInfo{varFlags, var->getTypeMask(), var->initializer()});\n}\n\nvoid CodeGenVisitor::visitDeclGroup(DeclGroup *group) {\n    addLineNumber(group);\n    const auto &declarations = group->declarations();\n\n    for (Decl *d : declarations) {\n        d->visit(this);\n    }\n}\n\nvoid CodeGenVisitor::visitDestructuringDecl(DestructuringDecl *destruct) {\n    addLineNumber(destruct);\n    ArenaVector<SQInteger> targets(_arena);\n\n    const auto &declarations = destruct->declarations();\n\n    for (auto d : declarations) {\n        d->visit(this);\n        assert(_last_declared_var_pos != -1);\n        targets.push_back(_last_declared_var_pos);\n        _last_declared_var_pos = -1;\n    }\n\n    visitForValueMaybeStaticMemo(destruct->initExpression());\n\n    SQInteger src = _fs->TopTarget();\n    _fs->PushTarget(); // key\n\n    for (SQUnsignedInteger i = 0; i < declarations.size(); ++i) {\n        VarDecl *d = declarations[i];\n        SQInteger flags = d->initializer() ? OP_GET_FLAG_NO_ERROR | OP_GET_FLAG_KEEP_VAL : 0;\n        _fs->AddInstruction(_OP_GETK, targets[i], destruct->type() == DT_ARRAY ? _fs->GetNumericConstant((SQInteger)i) : _fs->GetConstant(_fs->CreateString(d->name())), src, flags);\n        EmitCheckType(targets[i], d->getTypeMask());\n    }\n\n    _fs->PopTarget();\n    _fs->PopTarget();\n}\n\nvoid CodeGenVisitor::visitParamDecl(ParamDecl *param) {\n    if (param->hasDefaultValue()) {\n        checkInferredType(param, param->defaultValue(), param->getTypeMask());\n        visitForValueMaybeStaticMemo(param->defaultValue());\n    }\n}\n\n\nSQObjectPtr CodeGenVisitor::compileFunc(FunctionExpr *funcDecl, bool is_const, sqvector<SQObjectPtr> *out_defparam_values) {\n    _complexity_level++;\n\n    // For hoisted closures, skip overriding the parent's line number —\n    // the enclosing VarDecl already set the correct line for the _OP_CLOSURE\n    // instruction. Using the original lambda line would corrupt stack traces.\n    if (funcDecl->hoistingLevel() == 0)\n        addLineNumber(funcDecl);\n\n    SQFuncState *savedChildFsAtRoot = _childFs; // may be non-null when processing default argument that is declared as function/lambda\n    _childFs = _fs->PushChildState(_ss(_vm));\n\n    _childFs->_name = _fs->CreateString(funcDecl->name());\n    _childFs->_sourcename = _fs->_sourcename = SQString::Create(_ss(_vm), funcDecl->sourceName());\n    _childFs->_varparams = funcDecl->isVararg();\n    _childFs->_purefunction = funcDecl->isPure();\n    _childFs->_nodiscard = funcDecl->isNodiscard();\n    _childFs->_result_type_mask = funcDecl->getResultTypeMask();\n\n    SQInteger defparams = 0;\n\n    _childFs->AddParameter(_fs->CreateString(\"this\"), _RT_INSTANCE | _RT_TABLE | _RT_CLASS | _RT_USERDATA | _RT_NULL);\n\n    assert(is_const == (out_defparam_values!=nullptr));\n\n    for (auto param : funcDecl->parameters()) {\n        _childFs->AddParameter(_fs->CreateString(param->name()), param->getTypeMask());\n\n        if (is_const) {\n            if (param->hasDefaultValue()) {\n                ConstGenVisitor constVisitor(_vm, _fs, _ctx, *this);\n                SQObjectPtr defValue;\n                constVisitor.process(param->defaultValue(), defValue);\n                out_defparam_values->push_back(defValue);\n\n                const SQInteger dummy = -1; // The actual values is not used.\n                // Adding to internal vector only to provide the correct number of default arguments\n                // for SQFuncState::BuildProto() call.\n                // SQClosure's default argument values will be initialized in compileConstFunc()\n                _childFs->AddDefaultParam(dummy);\n                ++defparams;\n            }\n        }\n        else {\n            // The logic is split over visitParamDecl() and here\n            // TODO: move to the single place\n            param->visit(this);\n\n            if (param->hasDefaultValue()) {\n                _childFs->AddDefaultParam(_fs->TopTarget());\n                ++defparams;\n            }\n        }\n    }\n\n    if (!is_const) {\n        for (SQInteger n = 0; n < defparams; n++) {\n            _fs->PopTarget();\n        }\n    }\n\n    Block *body = funcDecl->body();\n\n    {\n        assert(_childFs->_parent == _fs);\n        SQFuncState *savedChildFsAtBody = _childFs;\n        _fs = _childFs;\n        _childFs = NULL;\n\n        for (auto param : funcDecl->parameters()) {\n            if (param->getDestructuring())\n                param->getDestructuring()->visit(this);\n        }\n\n        SQInteger startLine = body->lineStart();\n        if (startLine != -1)\n          savedChildFsAtBody->AddLineInfos(startLine, true, false);\n\n        funcDecl->body()->visit(this);\n\n        _childFs = savedChildFsAtBody;\n        _fs = _childFs->_parent;\n    }\n\n    _childFs->AddLineInfos(body->lineEnd(), true, true);\n    _childFs->AddInstruction(_OP_RETURN, -1);\n\n    if (GLOBAL_OPTIMIZATION_SWITCH && !(_childFs->lang_features & LF_DISABLE_OPTIMIZER)) {\n        SQOptimizer opt(*_childFs);\n        opt.optimize();\n        _childFs->CheckForPurity();\n    }\n\n    _childFs->SetStackSize(0);\n    _childFs->_hoistLevel = funcDecl->hoistingLevel();\n    SQFunctionProto *funcProto = _childFs->BuildProto();\n    SQObjectPtr result(funcProto);\n\n    _fs->PopChildState();\n    _childFs = savedChildFsAtRoot;\n\n    SaveDocstringToVM((void *)funcProto, funcDecl->docObject);\n    _complexity_level--;\n\n    return result;\n}\n\n\nvoid CodeGenVisitor::visitFunctionExpr(FunctionExpr *funcDecl) {\n    bool old_inside_static_memo = _inside_static_memo;\n    _inside_static_memo = false;\n\n    SQObjectPtr objFuncProto = compileFunc(funcDecl, false, nullptr);\n\n    _fs->_functions.push_back(objFuncProto);\n    _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, funcDecl->isLambda() ? 1 : 0);\n\n    _inside_static_memo = old_inside_static_memo;\n}\n\n\nSQObjectPtr CodeGenVisitor::compileConstFunc(FunctionExpr *funcDecl)\n{\n    sqvector<SQObjectPtr> defParamValues(nullptr);\n    SQObjectPtr objFuncProto = compileFunc(funcDecl, true, &defParamValues);\n\n    if (_funcproto(objFuncProto)->_noutervalues)\n        reportDiagnostic(funcDecl, DiagnosticsId::DI_GENERAL_COMPILE_ERROR, \"const function cannot have outer variables\");\n\n    SQClosure *closure = SQClosure::Create(_ss(_vm), _funcproto(objFuncProto));\n\n    SQInteger ndefparams = _funcproto(objFuncProto)->_ndefaultparams;\n    assert((SQInteger)defParamValues.size() == ndefparams);\n    for (SQInteger i = 0; i < ndefparams; i++) {\n        closure->_defaultparams[i] = defParamValues[i];\n    }\n\n    return SQObjectPtr(closure);\n}\n\n\nvoid CodeGenVisitor::SaveDocstringToVM(void *key, const DocObject &docObject) {\n    if (docObject.getDocString()) {\n        SQObjectPtr docValue(SQString::Create(_ss(_vm), docObject.getDocString()));\n        SQObjectPtr docKey;\n        docKey._type = OT_USERPOINTER;\n        docKey._unVal.pUserPointer = key;\n        _table(_ss(_vm)->doc_objects)->NewSlot(docKey, docValue);\n    }\n}\n\nSQTable* CodeGenVisitor::GetScopedConstsTable()\n{\n    assert(!_scopedconsts.empty());\n    SQObjectPtr &consts = _scopedconsts.top();\n    if (sq_type(consts) != OT_TABLE)\n        consts = SQTable::Create(_ss(_vm), 0);\n    return _table(consts);\n}\n\nSQObjectPtr CodeGenVisitor::convertLiteral(LiteralExpr *lit) {\n    SQObjectPtr ret{};\n    switch (lit->kind()) {\n    case LK_STRING: return SQObjectPtr(SQString::Create(_fs->_sharedstate, lit->s(), -1));\n    case LK_FLOAT: ret._type = OT_FLOAT; ret._unVal.fFloat = lit->f(); break;\n    case LK_INT:  ret._type = OT_INTEGER; ret._unVal.nInteger = lit->i(); break;\n    case LK_BOOL: ret._type = OT_BOOL; ret._unVal.nInteger = lit->b() ? 1 : 0; break;\n    case LK_NULL: ret._type = OT_NULL; ret._unVal.raw = 0; break;\n    }\n    return ret;\n}\n\nvoid CodeGenVisitor::visitConstDecl(ConstDecl *decl) {\n    addLineNumber(decl);\n\n    SQObjectPtr id = _fs->CreateString(decl->name());\n\n    CheckDuplicateLocalIdentifier(decl, id, \"Constant\", decl->isGlobal() && !(_fs->lang_features & LF_FORBID_GLOBAL_CONST_REWRITE));\n\n    SQTable *constantsTbl = decl->isGlobal() ? _table(_ss(_vm)->_consts) : GetScopedConstsTable();\n\n    ConstGenVisitor constVisitor(_vm, _fs, _ctx, *this);\n\n    SQObjectPtr value;\n    constVisitor.process(decl->value(), value);\n\n    constantsTbl->NewSlot(id, value);\n}\n\nvoid CodeGenVisitor::visitEnumDecl(EnumDecl *enums) {\n    addLineNumber(enums);\n    SQObjectPtr table(SQTable::Create(_fs->_sharedstate,0));\n\n    table._flags = SQOBJ_FLAG_IMMUTABLE;\n\n    SQObjectPtr id = _fs->CreateString(enums->name());\n\n    CheckDuplicateLocalIdentifier(enums, id, \"Enum\", enums->isGlobal() && !(_fs->lang_features & LF_FORBID_GLOBAL_CONST_REWRITE));\n\n    for (auto &c : enums->consts()) {\n        SQObjectPtr key = _fs->CreateString(c.id);\n        _table(table)->NewSlot(key, convertLiteral(c.val));\n    }\n\n    SQTable *enumsTable = enums->isGlobal() ? _table(_ss(_vm)->_consts) : GetScopedConstsTable();\n    enumsTable->NewSlot(id, SQObjectPtr(table));\n}\n\nvoid CodeGenVisitor::MoveIfCurrentTargetIsLocal() {\n    SQInteger trg = _fs->TopTarget();\n    if (_fs->IsLocal(trg)) {\n        trg = _fs->PopTarget(); //pops the target and moves it\n        _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);\n    }\n}\n\nvoid CodeGenVisitor::maybeAddInExprLine(Expr *expr) {\n    if (!_ss(_vm)->_lineInfoInExpressions) return;\n\n    if (expr->lineStart() != -1) {\n        _fs->AddLineInfos(expr->lineStart(), true, false);\n    }\n}\n\nvoid CodeGenVisitor::addLineNumber(Node *node) {\n    SQInteger line = node->lineStart();\n    if (line != -1) {\n        _fs->AddLineInfos(line, true, false);\n    }\n}\n\nstatic bool isCalleeAnObject(const Expr *expr) {\n    if (expr->isAccessExpr())\n        return expr->asAccessExpr()->receiver()->op() != TO_BASE;\n    if (expr->op() == TO_ROOT_TABLE_ACCESS)\n        return true;\n    return false;\n}\n\nstatic bool isCalleeAnOuter(SQFuncState *_fs, const Expr *expr, SQInteger &outer_pos) {\n    if (expr->op() != TO_ID)\n        return false;\n\n    SQObjectPtr nameObj(_fs->CreateString(expr->asId()->name()));\n    SQCompiletimeVarInfo varInfo;\n\n    if (_fs->GetLocalVariable(nameObj, varInfo) != -1)\n        return false;\n\n    outer_pos = _fs->GetOuterVariable(nameObj, varInfo);\n\n    return outer_pos != -1;\n}\n\nvoid CodeGenVisitor::visitCallExpr(CallExpr *call) {\n    maybeAddInExprLine(call);\n\n    Expr *callee = deparen(call->callee());\n    bool isNullCall = call->isNullable();\n    bool isTypeMethod = false;\n    if (callee->op() == TO_GETFIELD) {\n        isTypeMethod = callee->asGetField()->isTypeMethod();\n    }\n\n    visitForTarget(callee);\n\n    SQInteger outerPos = -1;\n\n    if (isCalleeAnObject(callee)) {\n        if (!isNullCall && !isTypeMethod && ((_fs->lang_features & LF_FORBID_IMPLICIT_TYPE_METHODS) == 0)) {\n            SQInteger key = _fs->PopTarget();  /* location of the key */\n            SQInteger table = _fs->PopTarget();  /* location of the object */\n            SQInteger closure = _fs->PushTarget(); /* location for the closure */\n            SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */\n            _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);\n        }\n        else {\n            SQInteger self = _fs->GetUpTarget(1);  /* location of the object */\n            SQInteger storedSelf = _fs->PushTarget();\n            _fs->_optimization = false;\n            _fs->AddInstruction(_OP_MOVE, storedSelf, self);\n            _fs->PopTarget();\n            SQInteger flags = 0;\n            if (isTypeMethod) {\n                flags |= OP_GET_FLAG_TYPE_METHODS_ONLY;\n            } else if ((_fs->lang_features & LF_FORBID_IMPLICIT_TYPE_METHODS) == 0) {\n                flags |= OP_GET_FLAG_ALLOW_TYPE_METHODS;\n            }\n            if (isNullCall)\n              flags |= OP_GET_FLAG_NO_ERROR;\n\n            SQInteger key = _fs->PopTarget();\n            SQInteger src = _fs->PopTarget();\n            _fs->AddInstruction(_OP_GET, _fs->PushTarget(), key, src, flags);\n            SQInteger ttarget = _fs->PushTarget();\n            _fs->_optimization = false;\n            _fs->AddInstruction(_OP_MOVE, ttarget, storedSelf);\n        }\n    }\n    else if (isCalleeAnOuter(_fs, callee, outerPos)) {\n        _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), outerPos);\n        _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\n    }\n    else {\n        _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);\n    }\n\n    const ArenaVector<Expr *> &args = call->arguments();\n\n    for (Expr *arg : args) {\n        visitMaybeStaticMemo(arg);\n        MoveIfCurrentTargetIsLocal();\n    }\n\n    for (SQUnsignedInteger i = 0; i < args.size(); ++i) {\n        _fs->PopTarget();\n    }\n\n    SQInteger stackbase = _fs->PopTarget();\n    SQInteger closure = _fs->PopTarget();\n    SQInteger target = _fs->PushTarget();\n    assert(target >= -1);\n    assert(target < 255);\n    _fs->AddInstruction(isNullCall ? _OP_NULLCALL : _OP_CALL, target, closure, stackbase, args.size() + 1);\n}\n\nvoid CodeGenVisitor::visitBaseExpr(BaseExpr *base) {\n    maybeAddInExprLine(base);\n    _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());\n}\n\nvoid CodeGenVisitor::visitRootTableAccessExpr(RootTableAccessExpr *expr) {\n    maybeAddInExprLine(expr);\n    _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());\n}\n\nvoid CodeGenVisitor::visitLiteralExpr(LiteralExpr *lit) {\n    maybeAddInExprLine(lit);\n    switch (lit->kind()) {\n    case LK_STRING:\n        _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(lit->s())));\n        break;\n    case LK_FLOAT:EmitLoadConstFloat(lit->f(), -1); break;\n    case LK_INT:  EmitLoadConstInt(lit->i(), -1); break;\n    case LK_BOOL: _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(), lit->b()); break;\n    case LK_NULL: _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(), 1); break;\n    }\n}\n\nvoid CodeGenVisitor::visitArrayExpr(ArrayExpr *expr) {\n    maybeAddInExprLine(expr);\n    const auto &inits = expr->initializers();\n\n    _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), inits.size(), 0, NEWOBJ_ARRAY);\n\n    for (SQUnsignedInteger i = 0; i < inits.size(); ++i) {\n        Expr *valExpr = inits[i];\n#if SQ_LINE_INFO_IN_STRUCTURES\n        if (i < 100 && valExpr->lineStart() != -1)\n            _fs->AddLineInfos(valExpr->lineStart(), false, false);\n#endif\n        visitForValueMaybeStaticMemo(valExpr);\n        SQInteger val = _fs->PopTarget();\n        SQInteger array = _fs->TopTarget();\n        _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);\n    }\n}\n\nvoid CodeGenVisitor::emitUnaryOp(SQOpcode op, UnExpr *u) {\n    Expr *arg = u->argument();\n    visitForValueMaybeStaticMemo(arg);\n\n    if (_fs->_targetstack.size() == 0)\n        reportDiagnostic(u, DiagnosticsId::DI_CANNOT_EVAL_UNARY);\n\n    SQInteger src = _fs->PopTarget();\n    _fs->AddInstruction(op, _fs->PushTarget(), src);\n}\n\n\nvoid CodeGenVisitor::emitStaticMemo(Expr *static_memo_arg, bool is_auto_memo) {\n    if (static_memo_arg->op() == TO_STATIC_MEMO) {\n        emitStaticMemo(static_cast<UnExpr*>(static_memo_arg)->argument());\n        return;\n    }\n\n    bool old_inside_static_memo = _inside_static_memo;\n    _inside_static_memo = true;\n\n    SQInteger staticIdx = _fs->_staticmemos_count++;\n    if (staticIdx > STATIC_MEMO_IDX_MASK)\n        reportDiagnostic(static_memo_arg, DiagnosticsId::DI_GENERAL_COMPILE_ERROR, \"too many static memos in function\");\n\n    _fs->AddInstruction(_OP_DATA_NOP); // will be replaced by _OP_LOAD_STATIC_MEMO\n    SQInteger loadInstrPos = _fs->GetCurrentPos();\n\n    visitForValue(static_memo_arg);\n\n    if (_fs->_targetstack.size() == 0)\n        reportDiagnostic(static_memo_arg, DiagnosticsId::DI_CANNOT_EVAL_UNARY);\n\n    SQInteger src = _fs->PopTarget();\n    SQInteger dst = _fs->PushTarget();\n\n    SQInteger storeInstrPos = _fs->GetCurrentPos() + 1;\n    SQInteger offset = storeInstrPos - loadInstrPos;\n    if (offset >= 0xFFFF)\n        reportDiagnostic(static_memo_arg, DiagnosticsId::DI_TOO_BIG_STATIC_MEMO);\n\n    SQInteger encodedIdx = is_auto_memo ? (staticIdx | STATIC_MEMO_AUTO_FLAG) : staticIdx;\n    _fs->SetInstructionParams(loadInstrPos, dst, encodedIdx, (offset) >> 8, (offset) & 0xFF);\n    _fs->AddInstruction(_OP_SAVE_STATIC_MEMO, src, encodedIdx, (offset + 1) >> 8, (offset + 1) & 0xFF);\n\n    _inside_static_memo = old_inside_static_memo;\n}\n\n\nvoid CodeGenVisitor::emitInlineConst(Expr *const_initializer) {\n    ConstGenVisitor constVisitor(_vm, _fs, _ctx, *this);\n    SQObjectPtr value;\n    constVisitor.process(const_initializer, value);\n    selectConstant(_fs->PushTarget(), value);\n}\n\n\nvoid CodeGenVisitor::emitDelete(UnExpr *ud) {\n    Expr *argument = ud->argument();\n    visitForTarget(argument);\n\n    switch (argument->op())\n    {\n    case TO_GETFIELD:\n    case TO_GETSLOT: break;\n    case TO_BASE:\n        reportDiagnostic(ud, DiagnosticsId::DI_CANNOT_DELETE, \"'base'\");\n        break;\n    case TO_ID:\n        reportDiagnostic(ud, DiagnosticsId::DI_CANNOT_DELETE, \"an (outer) local\");\n        break;\n    default:\n        reportDiagnostic(ud, DiagnosticsId::DI_CANNOT_DELETE, \"an expression\");\n        break;\n    }\n\n    SQInteger table = _fs->PopTarget(); //src in OP_GET\n    SQInteger key = _fs->PopTarget(); //key in OP_GET\n    _fs->AddInstruction(_OP_DELETE, _fs->PushTarget(), key, table);\n}\n\nvoid CodeGenVisitor::visitUnExpr(UnExpr *unary) {\n    maybeAddInExprLine(unary);\n\n    switch (unary->op())\n    {\n    case TO_NEG: emitUnaryOp(_OP_NEG, unary); break;\n    case TO_NOT: emitUnaryOp(_OP_NOT, unary); break;\n    case TO_BNOT:emitUnaryOp(_OP_BWNOT, unary); break;\n    case TO_TYPEOF: emitUnaryOp(_OP_TYPEOF, unary); break;\n    case TO_RESUME: emitUnaryOp(_OP_RESUME, unary); break;\n    case TO_CLONE: emitUnaryOp(_OP_CLONE, unary); break;\n    case TO_PAREN: unary->argument()->visit(this); break;\n    case TO_DELETE: emitDelete(unary); break;\n    case TO_STATIC_MEMO: {\n#if STATIC_MEMO_ENABLED\n        int score = getSubtreeConstScore(unary->argument(), true);\n        if (score == 0)\n            reportDiagnostic(_variable_node ? _variable_node : unary, DiagnosticsId::DI_NOT_A_CONST);\n        if (score > 0 && score < 3)\n            reportDiagnostic(_variable_node ? _variable_node : unary, DiagnosticsId::DI_STATIC_MEMO_TOO_SIMPLE);\n        emitStaticMemo(unary->argument());\n#else\n        unary->argument()->visit(this);\n#endif\n        break;\n    }\n    case TO_INLINE_CONST:\n        emitInlineConst(unary->argument());\n        break;\n    default:\n        assert(!\"Invalid unary op\");\n        break;\n    }\n}\n\nvoid CodeGenVisitor::emitSimpleBinaryOp(SQOpcode op, Expr *lhs, Expr *rhs, SQInteger op3) {\n    visitForValueMaybeStaticMemo(lhs);\n    visitForValueMaybeStaticMemo(rhs);\n    SQInteger op1 = _fs->PopTarget();\n    SQInteger op2 = _fs->PopTarget();\n    _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);\n}\n\nvoid CodeGenVisitor::emitShortCircuitLogicalOp(SQOpcode op, Expr *lhs, Expr *rhs) {\n    visitForValue(lhs);\n\n    SQInteger first_exp = _fs->PopTarget();\n    SQInteger trg = _fs->PushTarget();\n    _fs->AddInstruction(op, trg, 0, first_exp, 0);\n    SQInteger jpos = _fs->GetCurrentPos();\n    if (trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\n    visitForValue(rhs);\n    _fs->SnoozeOpt();\n    SQInteger second_exp = _fs->PopTarget();\n    if (trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\n    _fs->SnoozeOpt();\n    _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));\n}\n\nvoid CodeGenVisitor::emitCompoundArith(SQOpcode op, SQInteger opcode, Expr *lvalue, Expr *rvalue) {\n\n    if (lvalue->isAccessExpr() && lvalue->asAccessExpr()->isFieldAccessExpr()) {\n        FieldAccessExpr *fieldAccess = lvalue->asAccessExpr()->asFieldAccessExpr();\n        SQObjectPtr nameObj = _fs->CreateString(fieldAccess->fieldName());\n        SQInteger constantI = _fs->GetConstant(nameObj);\n        if (constantI < 256u)\n        {\n          visitForValue(fieldAccess->receiver());\n          _fs->PushTarget();\n          visitForValueMaybeStaticMemo(rvalue);\n          SQInteger val = _fs->PopTarget();\n          _fs->PopTarget();\n          SQInteger src = _fs->PopTarget();\n          /* _OP_COMPARITH mixes dest obj and source val in the arg1 */\n          _fs->AddInstruction(_OP_COMPARITH_K, _fs->PushTarget(), (src << 16) | val, constantI, opcode);\n          return;\n        }\n    }\n\n    visitForTarget(lvalue);\n\n    visitForValueMaybeStaticMemo(rvalue);\n\n    if (lvalue->op() == TO_ID) {\n        Id *id = lvalue->asId();\n\n        SQObjectPtr nameObj(_fs->CreateString(id->name()));\n        SQCompiletimeVarInfo varInfo;\n        SQInteger pos = -1;\n\n        if ((pos = _fs->GetLocalVariable(nameObj, varInfo)) != -1) {\n            if ((varInfo.var_flags & VF_ASSIGNABLE) == 0)\n                reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_BINDING, id->name());\n\n            SQInteger p2 = _fs->PopTarget(); //src in OP_GET\n            SQInteger p1 = _fs->PopTarget(); //key in OP_GET\n            _fs->PushTarget(p1);\n            //EmitCompArithLocal(tok, p1, p1, p2);\n            _fs->AddInstruction(op, p1, p2, p1, 0);\n            EmitCheckType(p1, varInfo.type_mask);\n            _fs->SnoozeOpt();\n        }\n        else if ((pos = _fs->GetOuterVariable(nameObj, varInfo)) != -1) {\n            if ((varInfo.var_flags & VF_ASSIGNABLE) == 0)\n                reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_BINDING, id->name());\n\n            SQInteger val = _fs->TopTarget();\n            SQInteger tmp = _fs->PushTarget();\n            _fs->AddInstruction(_OP_GETOUTER, tmp, pos);\n            _fs->AddInstruction(op, tmp, val, tmp, 0);\n            EmitCheckType(tmp, varInfo.type_mask);\n            _fs->PopTarget();\n            _fs->PopTarget();\n            _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);\n        }\n        else {\n            reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_EXPR);\n        }\n    }\n    else if (lvalue->isAccessExpr()) {\n        SQInteger val = _fs->PopTarget();\n        SQInteger key = _fs->PopTarget();\n        SQInteger src = _fs->PopTarget();\n        /* _OP_COMPARITH mixes dest obj and source val in the arg1 */\n        _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src << 16) | val, key, opcode);\n    }\n    else {\n        reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_EXPR);\n    }\n}\n\nvoid CodeGenVisitor::emitNewSlot(Expr *lvalue, Expr *rvalue) {\n\n    if (lvalue->isAccessExpr() && lvalue->asAccessExpr()->receiver()->op() != TO_BASE && canBeLiteral(lvalue->asAccessExpr())) {\n        FieldAccessExpr *fieldAccess = lvalue->asAccessExpr()->asFieldAccessExpr();\n        SQObjectPtr nameObj = _fs->CreateString(fieldAccess->fieldName());\n        SQInteger constantI = _fs->GetConstant(nameObj);\n        //if (constantI < 256) // currently stored in arg1, unlimited\n        {\n            visitForValue(fieldAccess->receiver());\n            visitForValueMaybeStaticMemo(rvalue);\n            SQInteger val = _fs->PopTarget();\n            SQInteger src = _fs->PopTarget();\n            _fs->AddInstruction(_OP_NEWSLOTK, _fs->PushTarget(), constantI, src, val);\n            return;\n       }\n    }\n\n    visitForTarget(lvalue);\n\n    visitForValueMaybeStaticMemo(rvalue);\n\n    if (lvalue->isAccessExpr()) { // d.f || d[\"f\"]\n        SQInteger val = _fs->PopTarget();\n        SQInteger key = _fs->PopTarget();\n        SQInteger src = _fs->PopTarget();\n        _fs->AddInstruction(_OP_NEWSLOT, _fs->PushTarget(), key, src, val);\n    }\n    else {\n        reportDiagnostic(lvalue, DiagnosticsId::DI_LOCAL_SLOT_CREATE);\n    }\n}\n\nvoid CodeGenVisitor::emitFieldAssign(int isLiteralIndex) {\n    const bool isLiteral = isLiteralIndex >= 0;\n    SQInteger val = _fs->PopTarget();\n    SQInteger key = isLiteralIndex >= 0 ? isLiteralIndex : _fs->PopTarget();\n    SQInteger src = _fs->PopTarget();\n    assert(src < 256);\n\n    _fs->AddInstruction(isLiteral ? _OP_SET_LITERAL : _OP_SET, _fs->PushTarget(), key, src, val);\n    static_assert(_OP_DATA_NOP == 0);\n    if (isLiteral)\n        _fs->AddInstruction(SQOpcode(0), 0, 0, 0, 0);//hint\n}\n\nvoid CodeGenVisitor::emitAssign(Expr *lvalue, Expr * rvalue) {\n\n    if (lvalue->isAccessExpr() && lvalue->asAccessExpr()->receiver()->op() != TO_BASE && canBeLiteral(lvalue->asAccessExpr())) {\n        FieldAccessExpr *fieldAccess = lvalue->asAccessExpr()->asFieldAccessExpr();\n        SQObjectPtr nameObj = _fs->CreateString(fieldAccess->fieldName());\n        SQInteger constantI = _fs->GetConstant(nameObj);\n        // arg1 is of int size, enough\n        visitForValue(fieldAccess->receiver());\n\n        visitForValueMaybeStaticMemo(rvalue);\n\n        emitFieldAssign(constantI);\n        return;\n    }\n\n    visitForTarget(lvalue);\n\n    visitForValueMaybeStaticMemo(rvalue);\n\n    if (lvalue->op() == TO_ID) {\n        Id *id = lvalue->asId();\n\n        SQObjectPtr nameObj(_fs->CreateString(id->name()));\n        SQCompiletimeVarInfo varInfo;\n        SQInteger pos = -1;\n\n        if ((pos = _fs->GetLocalVariable(nameObj, varInfo)) != -1) {\n            if ((varInfo.var_flags & VF_ASSIGNABLE) == 0)\n                reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_BINDING, id->name());\n\n            SQInteger src = _fs->PopTarget();\n            SQInteger dst = _fs->TopTarget();\n            _fs->AddInstruction(_OP_MOVE, dst, src);\n            if (!checkInferredType(lvalue, rvalue, varInfo.type_mask))\n                EmitCheckType(dst, varInfo.type_mask);\n        }\n        else if ((pos = _fs->GetOuterVariable(nameObj, varInfo)) != -1) {\n            if ((varInfo.var_flags & VF_ASSIGNABLE) == 0)\n                reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_BINDING, id->name());\n\n            SQInteger src = _fs->PopTarget();\n            _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, src);\n            if (!checkInferredType(lvalue, rvalue, varInfo.type_mask))\n                EmitCheckType(src, varInfo.type_mask);\n        }\n        else {\n            reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_EXPR);\n        }\n    }\n    else if (lvalue->isAccessExpr()) {\n        if (lvalue->asAccessExpr()->receiver()->op() != TO_BASE) {\n            emitFieldAssign(-1);\n        }\n        else {\n            reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_EXPR);\n        }\n    }\n    else {\n        reportDiagnostic(lvalue, DiagnosticsId::DI_ASSIGN_TO_EXPR);\n    }\n}\n\nbool CodeGenVisitor::canBeLiteral(AccessExpr *expr) {\n    if (!expr->isFieldAccessExpr()) return false;\n\n    FieldAccessExpr *field = expr->asFieldAccessExpr();\n\n    return field->canBeLiteral(CanBeTypeMethod(field->fieldName()));\n}\n\n\nbool CodeGenVisitor::CanBeTypeMethod(const char *key)\n{\n    if (_fs->lang_features & LF_FORBID_IMPLICIT_TYPE_METHODS)\n      return false;\n\n    // Check if key exists in any built-in type class\n    // This can be optimized by keeping joined list/table of used keys\n    SQClass *builtinClasses[] = {\n        _class(_fs->_sharedstate->_null_class),\n        _class(_fs->_sharedstate->_integer_class),\n        _class(_fs->_sharedstate->_float_class),\n        _class(_fs->_sharedstate->_bool_class),\n        _class(_fs->_sharedstate->_table_class),\n        _class(_fs->_sharedstate->_array_class),\n        _class(_fs->_sharedstate->_string_class),\n        _class(_fs->_sharedstate->_generator_class),\n        _class(_fs->_sharedstate->_function_class),\n        _class(_fs->_sharedstate->_thread_class),\n        _class(_fs->_sharedstate->_class_class),\n        _class(_fs->_sharedstate->_instance_class),\n        _class(_fs->_sharedstate->_weakref_class),\n        _class(_fs->_sharedstate->_userdata_class)\n    };\n    SQObjectPtr tmp;\n    int keyLen = strlen(key);\n    for (SQInteger i = 0; i < sizeof(builtinClasses) / sizeof(builtinClasses[0]); ++i) {\n        if (builtinClasses[i]->GetStr(key, keyLen, tmp))\n            return true;\n    }\n    return false;\n}\n\nSQObjectPtr CodeGenVisitor::GetTypeMethod(SQInteger sq_type, const char* key) {\n    SQObjectPtr res;\n    SQClass *builtinClass = nullptr;\n    switch (sq_type) {\n        case OT_NULL: builtinClass = _class(_fs->_sharedstate->_null_class); break;\n\n        case OT_INTEGER: builtinClass = _class(_fs->_sharedstate->_integer_class); break;\n        case OT_FLOAT: builtinClass = _class(_fs->_sharedstate->_float_class); break;\n        case OT_BOOL: builtinClass = _class(_fs->_sharedstate->_bool_class); break;\n\n        case OT_TABLE: builtinClass = _class(_fs->_sharedstate->_table_class); break;\n        case OT_ARRAY: builtinClass = _class(_fs->_sharedstate->_array_class); break;\n        case OT_STRING: builtinClass = _class(_fs->_sharedstate->_string_class); break;\n\n        case OT_GENERATOR: builtinClass = _class(_fs->_sharedstate->_generator_class); break;\n        case OT_CLOSURE:\n        case OT_NATIVECLOSURE: builtinClass = _class(_fs->_sharedstate->_function_class); break;\n        case OT_THREAD: builtinClass = _class(_fs->_sharedstate->_thread_class); break;\n        case OT_CLASS: builtinClass = _class(_fs->_sharedstate->_class_class); break;\n        case OT_INSTANCE: builtinClass = _class(_fs->_sharedstate->_instance_class); break;\n        case OT_WEAKREF: builtinClass = _class(_fs->_sharedstate->_weakref_class); break;\n        case OT_USERDATA: builtinClass = _class(_fs->_sharedstate->_userdata_class); break;\n        case OT_USERPOINTER: // no type methods for user pointers\n        case OT_FUNCPROTO: // no type methods for function prototypes\n            return res;\n\n        default:\n            return res;\n    }\n\n    if (!builtinClass)\n        return res;\n\n    builtinClass->GetStr(key, strlen(key), res);\n    return res;\n}\n\nbool CodeGenVisitor::CanBeTableTypeMethod(const char *key)\n{\n    if (_fs->lang_features & LF_FORBID_IMPLICIT_TYPE_METHODS)\n      return false;\n\n    SQObjectPtr tmp;\n    return _class(_fs->_sharedstate->_table_class)->GetStr(key, strlen(key), tmp);\n}\n\n\nvoid CodeGenVisitor::selectConstant(SQInteger target, const SQObjectPtr &constant) {\n    SQObjectType ctype = sq_type(constant);\n    switch (ctype) {\n    case OT_INTEGER: EmitLoadConstInt(_integer(constant), target); break;\n    case OT_FLOAT: EmitLoadConstFloat(_float(constant), target); break;\n    case OT_BOOL: _fs->AddInstruction(_OP_LOADBOOL, target, _integer(constant)); break;\n    case OT_NULL: _fs->AddInstruction(_OP_LOADNULLS, target, 1); break;\n    default: _fs->AddInstruction(_OP_LOAD, target, _fs->GetConstant(constant)); break;\n    }\n}\n\nvoid CodeGenVisitor::visitGetFieldExpr(GetFieldExpr *expr) {\n    maybeAddInExprLine(expr);\n\n    Expr *receiver = expr->receiver();\n\n    // Handle enums\n    if (receiver->op() == TO_ID) {\n        SQObjectPtr constant;\n        SQObjectPtr id = _fs->CreateString(receiver->asId()->name());\n        if (IsConstant(id, constant)) {\n            if (sq_type(constant) == OT_TABLE && (sq_objflags(constant) & SQOBJ_FLAG_IMMUTABLE) && !expr->isNullable()) {\n                SQObjectPtr next;\n                if (_table(constant)->GetStr(expr->fieldName(), strlen(expr->fieldName()), next)) {\n                    SQObjectType fieldType = sq_type(next);\n                    bool needsCallContext = fieldType == OT_CLOSURE || fieldType == OT_NATIVECLOSURE\n                        || fieldType == OT_GENERATOR || fieldType == OT_CLASS || fieldType == OT_INSTANCE;\n                    if (!needsCallContext) {\n                        selectConstant(_fs->PushTarget(), next);\n                        return; // Done with enum\n                    }\n                    // else fall through to normal get\n                }\n                else {\n                    if (!CanBeTableTypeMethod(expr->fieldName())) {\n                        reportDiagnostic(expr, DiagnosticsId::DI_INVALID_ENUM, expr->fieldName(), \"enum\");\n                        return;\n                    }\n                    // else fall through to normal get\n                }\n            }\n        }\n    }\n\n    visitForValue(receiver);\n\n    SQObjectPtr nameObj = _fs->CreateString(expr->fieldName());\n    SQInteger constantI = _fs->GetConstant(nameObj);\n    SQInteger constTarget = _fs->PushTarget();\n\n    SQInteger flags = expr->isNullable() ? OP_GET_FLAG_NO_ERROR : 0;\n\n    bool typeMethod = CanBeTypeMethod(expr->fieldName());\n\n    if (typeMethod) {\n        flags |= OP_GET_FLAG_ALLOW_TYPE_METHODS;\n    }\n\n    if (expr->isTypeMethod()) {\n        flags |= OP_GET_FLAG_TYPE_METHODS_ONLY;\n    }\n\n    if (expr->receiver()->op() == TO_BASE) {\n        _fs->PopTarget(); // key\n        SQInteger src = _fs->PopTarget();\n        _fs->AddInstruction(_OP_GETK, _fs->PushTarget(), constantI, src, flags);\n    } else if (_resolve_mode == ExprChainResolveMode::Value) {\n        _fs->PopTarget(); // key\n        SQInteger src = _fs->PopTarget();\n        if (expr->canBeLiteral(typeMethod)) {\n            _fs->AddInstruction(_OP_GET_LITERAL, _fs->PushTarget(), constantI, src, flags);\n            static_assert(_OP_DATA_NOP == 0);\n            _fs->AddInstruction(SQOpcode(0), 0, 0, 0, 0); //hint\n        }\n        else {\n            _fs->AddInstruction(_OP_GETK, _fs->PushTarget(), constantI, src, flags);\n        }\n    } else\n    {\n        _fs->AddInstruction(_OP_LOAD, constTarget, constantI);\n    }\n}\n\nvoid CodeGenVisitor::visitGetSlotExpr(GetSlotExpr *expr) {\n    // TODO: support similar optimization with contant table as in GetFieldExpr here too\n\n    maybeAddInExprLine(expr);\n\n    visitForValue(expr->receiver());\n    visitForValueMaybeStaticMemo(expr->key());\n\n    if (expr->receiver()->op() == TO_BASE || _resolve_mode == ExprChainResolveMode::Value) {\n        SQInteger key = _fs->PopTarget(); //key in OP_GET\n        SQInteger src = _fs->PopTarget(); //src in OP_GET\n        _fs->AddInstruction(_OP_GET, _fs->PushTarget(), key, src, expr->isNullable() ? OP_GET_FLAG_NO_ERROR : 0);\n    }\n}\n\nstatic inline bool is_literal_in_int_range(const Expr *expr)\n{\n    if ( expr->op() != TO_LITERAL)\n        return false;\n    LiteralExpr * le = expr->asLiteral();\n    if (le->kind() != LK_INT)\n      return false;\n    SQInteger i = le->i();\n    return i >= SQInteger(INT_MIN) && i <= SQInteger(INT_MAX);\n}\n\nvoid CodeGenVisitor::visitBinExpr(BinExpr *expr) {\n    maybeAddInExprLine(expr);\n    switch (expr->op()) {\n    case TO_NEWSLOT: emitNewSlot(expr->lhs(), expr->rhs());  break;\n    case TO_NULLC: emitShortCircuitLogicalOp(_OP_NULLCOALESCE, expr->lhs(), expr->rhs()); break;\n    case TO_OROR: emitShortCircuitLogicalOp(_OP_OR, expr->lhs(), expr->rhs()); break;\n    case TO_ANDAND: emitShortCircuitLogicalOp(_OP_AND, expr->lhs(), expr->rhs()); break;\n    case TO_ASSIGN:  emitAssign(expr->lhs(), expr->rhs()); break;\n    case TO_PLUSEQ:  emitCompoundArith(_OP_ADD, '+', expr->lhs(), expr->rhs()); break;\n    case TO_MINUSEQ: emitCompoundArith(_OP_SUB, '-', expr->lhs(), expr->rhs()); break;\n    case TO_MULEQ:   emitCompoundArith(_OP_MUL, '*', expr->lhs(), expr->rhs()); break;\n    case TO_DIVEQ:   emitCompoundArith(_OP_DIV, '/', expr->lhs(), expr->rhs()); break;\n    case TO_MODEQ:   emitCompoundArith(_OP_MOD, '%', expr->lhs(), expr->rhs()); break;\n    case TO_ADD:\n      if ( is_literal_in_int_range(expr->lhs()) )\n      {\n          visitForValue(expr->rhs());\n          SQInteger op2 = _fs->PopTarget();\n          _fs->AddInstruction(_OP_ADDI, _fs->PushTarget(), expr->lhs()->asLiteral()->i(), op2, 0);\n      } else if ( is_literal_in_int_range(expr->rhs()) )\n      {\n          visitForValue(expr->lhs());\n          SQInteger op2 = _fs->PopTarget();\n          _fs->AddInstruction(_OP_ADDI, _fs->PushTarget(), expr->rhs()->asLiteral()->i(), op2, 0);\n      } else\n          emitSimpleBinaryOp(_OP_ADD, expr->lhs(), expr->rhs());\n    break;\n    case TO_SUB:\n        if ( is_literal_in_int_range(expr->rhs()) && expr->rhs()->asLiteral()->i() != SQInteger(INT_MIN) )\n        {\n            visitForValue(expr->lhs());\n            SQInteger op2 = _fs->PopTarget();\n            _fs->AddInstruction(_OP_ADDI, _fs->PushTarget(), -expr->rhs()->asLiteral()->i(), op2, 0);\n        } else\n            emitSimpleBinaryOp(_OP_SUB, expr->lhs(), expr->rhs());\n    break;\n    case TO_MUL: emitSimpleBinaryOp(_OP_MUL, expr->lhs(), expr->rhs()); break;\n    case TO_DIV: emitSimpleBinaryOp(_OP_DIV, expr->lhs(), expr->rhs()); break;\n    case TO_MOD: emitSimpleBinaryOp(_OP_MOD, expr->lhs(), expr->rhs()); break;\n    case TO_OR:  emitSimpleBinaryOp(_OP_BITW, expr->lhs(), expr->rhs(), BW_OR); break;\n    case TO_AND: emitSimpleBinaryOp(_OP_BITW, expr->lhs(), expr->rhs(), BW_AND); break;\n    case TO_XOR: emitSimpleBinaryOp(_OP_BITW, expr->lhs(), expr->rhs(), BW_XOR); break;\n    case TO_USHR:emitSimpleBinaryOp(_OP_BITW, expr->lhs(), expr->rhs(), BW_USHIFTR); break;\n    case TO_SHR: emitSimpleBinaryOp(_OP_BITW, expr->lhs(), expr->rhs(), BW_SHIFTR); break;\n    case TO_SHL: emitSimpleBinaryOp(_OP_BITW, expr->lhs(), expr->rhs(), BW_SHIFTL); break;\n    case TO_EQ:  emitSimpleBinaryOp(_OP_EQ, expr->lhs(), expr->rhs()); break;\n    case TO_NE:  emitSimpleBinaryOp(_OP_NE, expr->lhs(), expr->rhs()); break;\n    case TO_GE:  emitSimpleBinaryOp(_OP_CMP, expr->lhs(), expr->rhs(), CMP_GE); break;\n    case TO_GT:  emitSimpleBinaryOp(_OP_CMP, expr->lhs(), expr->rhs(), CMP_G); break;\n    case TO_LE:  emitSimpleBinaryOp(_OP_CMP, expr->lhs(), expr->rhs(), CMP_LE); break;\n    case TO_LT:  emitSimpleBinaryOp(_OP_CMP, expr->lhs(), expr->rhs(), CMP_L); break;\n    case TO_3CMP: emitSimpleBinaryOp(_OP_CMP, expr->lhs(), expr->rhs(), CMP_3W); break;\n    case TO_IN:  emitSimpleBinaryOp(_OP_EXISTS, expr->lhs(), expr->rhs()); break;\n    case TO_INSTANCEOF: emitSimpleBinaryOp(_OP_INSTANCEOF, expr->lhs(), expr->rhs()); break;\n    default:\n        assert(!\"Unknown binary expression\");\n        break;\n    }\n}\n\nvoid CodeGenVisitor::visitTerExpr(TerExpr *expr) {\n    maybeAddInExprLine(expr);\n    assert(expr->op() == TO_TERNARY);\n\n    visitForValue(expr->a());\n    _fs->AddInstruction(_OP_JZ, _fs->PopTarget());\n    SQInteger jzpos = _fs->GetCurrentPos();\n\n    SQInteger trg = _fs->PushTarget();\n    visitForValueMaybeStaticMemo(expr->b());\n    SQInteger first_exp = _fs->PopTarget();\n    if (trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);\n    SQInteger endfirstexp = _fs->GetCurrentPos();\n    _fs->AddInstruction(_OP_JMP, 0, 0);\n    SQInteger jmppos = _fs->GetCurrentPos();\n\n    visitForValueMaybeStaticMemo(expr->c());\n    SQInteger second_exp = _fs->PopTarget();\n    if (trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);\n\n    _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);\n    _fs->SetInstructionParam(jzpos, 1, endfirstexp - jzpos + 1);\n    _fs->SnoozeOpt();\n}\n\nvoid CodeGenVisitor::visitIncExpr(IncExpr *expr) {\n    maybeAddInExprLine(expr);\n    Expr *arg = expr->argument();\n\n    visitForTarget(arg);\n\n    if ((arg->op() == TO_GETFIELD || arg->op() == TO_GETSLOT) && arg->asAccessExpr()->receiver()->op() == TO_BASE) {\n        reportDiagnostic(arg, DiagnosticsId::DI_INC_DEC_NOT_ASSIGNABLE);\n    }\n\n    bool isPostfix = expr->form() == IF_POSTFIX;\n\n    if (arg->isAccessExpr()) {\n        SQInteger p2 = _fs->PopTarget();\n        SQInteger p1 = _fs->PopTarget();\n        _fs->AddInstruction(isPostfix ? _OP_PINC : _OP_INC, _fs->PushTarget(), p1, p2, expr->diff());\n    }\n    else if (arg->op() == TO_ID) {\n        Id *id = arg->asId();\n\n        SQObjectPtr nameObj(_fs->CreateString(id->name()));\n        SQInteger pos = -1;\n        SQCompiletimeVarInfo varInfo;\n\n        if ((pos = _fs->GetLocalVariable(nameObj, varInfo)) != -1) {\n            if ((varInfo.var_flags & VF_ASSIGNABLE) == 0)\n                reportDiagnostic(arg, DiagnosticsId::DI_INC_DEC_NOT_ASSIGNABLE);\n\n            SQInteger src = isPostfix ? _fs->PopTarget() : _fs->TopTarget();\n            SQInteger dst = isPostfix ? _fs->PushTarget() : src;\n            _fs->AddInstruction(isPostfix ? _OP_PINCL : _OP_INCL, dst, src, 0, expr->diff());\n        }\n        else if ((pos = _fs->GetOuterVariable(nameObj, varInfo)) != -1) {\n            if ((varInfo.var_flags & VF_ASSIGNABLE) == 0)\n                reportDiagnostic(arg, DiagnosticsId::DI_INC_DEC_NOT_ASSIGNABLE);\n\n            SQInteger tmp1 = _fs->PushTarget();\n            SQInteger tmp2 = isPostfix ? _fs->PushTarget() : tmp1;\n            _fs->AddInstruction(_OP_GETOUTER, tmp2, pos);\n            _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, expr->diff());\n            _fs->AddInstruction(_OP_SETOUTER, tmp2, pos, tmp2);\n            if (isPostfix) {\n                _fs->PopTarget();\n            }\n        }\n        else {\n            reportDiagnostic(arg, DiagnosticsId::DI_INC_DEC_NOT_ASSIGNABLE);\n        }\n    }\n    else {\n        reportDiagnostic(arg, DiagnosticsId::DI_INC_DEC_NOT_ASSIGNABLE);\n    }\n}\n\nvoid CodeGenVisitor::visitDirectiveStatement(DirectiveStmt *directive)\n{\n    _fs->lang_features = (_fs->lang_features | directive->setFlags) & ~directive->clearFlags;\n    if (directive->applyToDefault)\n        _ss(_vm)->defaultLangFeatures = (_ss(_vm)->defaultLangFeatures | directive->setFlags) & ~directive->clearFlags;\n}\n\n\nbool CodeGenVisitor::IsConstant(const SQObject &name, SQObjectPtr &e)\n{\n    if (IsLocalConstant(name, e))\n        return true;\n    if (IsGlobalConstant(name, e))\n        return true;\n    return false;\n}\n\nbool CodeGenVisitor::IsLocalConstant(const SQObject &name, SQObjectPtr &e)\n{\n    SQObjectPtr val;\n    for (SQInteger i = SQInteger(_scopedconsts.size()) - 1; i >= 0; --i) {\n        SQObjectPtr &tbl = _scopedconsts[i];\n        if (!sq_isnull(tbl) && _table(tbl)->Get(SQObjectPtr(name), val)) {\n            e = val;\n            if (tbl._flags & SQOBJ_FLAG_IMMUTABLE)\n                e._flags |= SQOBJ_FLAG_IMMUTABLE;\n            return true;\n        }\n    }\n    return false;\n}\n\nbool CodeGenVisitor::IsGlobalConstant(const SQObject &name, SQObjectPtr &e)\n{\n    SQObjectPtr val;\n    if (_table(_ss(_vm)->_consts)->Get(SQObjectPtr(name), val)) {\n        e = val;\n        return true;\n    }\n    return false;\n}\n\nbool CodeGenVisitor::isConstEvaluable(Expr *expr) {\n    switch (expr->op()) {\n    case TO_PAREN:\n    case TO_INLINE_CONST:\n        return isConstEvaluable(static_cast<UnExpr *>(expr)->argument()); //-V1037\n\n    case TO_LITERAL:\n        return true;\n\n    case TO_ID: {\n        SQObjectPtr name = _fs->CreateString(expr->asId()->name());\n        SQCompiletimeVarInfo varInfo;\n        if (_fs->GetLocalVariable(name, varInfo) != -1 ||\n            _fs->GetOuterVariable(name, varInfo) != -1)\n            return false;  // local/outer shadows any constant\n        SQObjectPtr c;\n        return IsConstant(name, c);\n    }\n\n    case TO_NEG:\n    case TO_NOT:\n    case TO_BNOT:\n    case TO_TYPEOF:\n        return isConstEvaluable(static_cast<UnExpr *>(expr)->argument()); //-V1037\n\n    case TO_ADD: case TO_SUB: case TO_MUL: case TO_DIV: case TO_MOD:\n    case TO_OR: case TO_AND: case TO_XOR:\n    case TO_SHL: case TO_SHR: case TO_USHR:\n    case TO_EQ: case TO_NE: case TO_LT: case TO_LE: case TO_GT: case TO_GE: case TO_3CMP:\n    case TO_OROR: case TO_ANDAND: case TO_NULLC:\n    case TO_IN: case TO_INSTANCEOF: {\n        BinExpr *bin = static_cast<BinExpr *>(expr);\n        return isConstEvaluable(bin->lhs()) && isConstEvaluable(bin->rhs());\n    }\n\n    case TO_TERNARY: {\n        TerExpr *ter = static_cast<TerExpr *>(expr);\n        return isConstEvaluable(ter->a()) && isConstEvaluable(ter->b()) && isConstEvaluable(ter->c());\n    }\n\n    case TO_GETFIELD:\n        return isConstEvaluable(expr->asGetField()->receiver());\n\n    case TO_GETSLOT: {\n        GetSlotExpr *gs = expr->asGetSlot();\n        return isConstEvaluable(gs->receiver()) && isConstEvaluable(gs->key());\n    }\n\n    default:\n        return false;\n    }\n}\n\nvoid CodeGenVisitor::visitCommaExpr(CommaExpr *expr) {\n    for (auto e : expr->expressions()) {\n        visitForValue(e);\n    }\n}\n\nvoid CodeGenVisitor::visitId(Id *id) {\n    maybeAddInExprLine(id);\n    SQInteger pos = -1;\n    SQObjectPtr constant;\n    SQObjectPtr idObj = _fs->CreateString(id->name());\n    SQCompiletimeVarInfo varInfo;\n\n    if (sq_isstring(_fs->_name)\n        && strcmp(_stringval(_fs->_name), id->name()) == 0\n        && _fs->GetLocalVariable(_fs->_name, varInfo) == -1) {\n        _fs->AddInstruction(_OP_LOADCALLEE, _fs->PushTarget());\n        return;\n    }\n\n    if (_string(idObj) == _string(_fs->_name)) {\n        reportDiagnostic(id, DiagnosticsId::DI_CONFLICTS_WITH, \"variable\", id->name(), \"function name\");\n    }\n\n    if ((pos = _fs->GetLocalVariable(idObj, varInfo)) != -1) {\n        _fs->PushTarget(pos);\n    }\n    else if ((pos = _fs->GetOuterVariable(idObj, varInfo)) != -1) {\n        if (_resolve_mode == ExprChainResolveMode::Value) {\n            SQInteger stkPos = _fs->PushTarget();\n            _fs->AddInstruction(_OP_GETOUTER, stkPos, pos);\n        }\n    }\n    else if (IsConstant(idObj, constant)) {\n        /* Handle named constant */\n        SQObjectPtr constval(constant);\n\n        SQInteger stkPos = _fs->PushTarget();\n\n        /* generate direct or literal function depending on size */\n        SQObjectType ctype = sq_type(constval);\n        switch (ctype) {\n        case OT_INTEGER:\n            EmitLoadConstInt(_integer(constval), stkPos);\n            break;\n        case OT_FLOAT:\n            EmitLoadConstFloat(_float(constval), stkPos);\n            break;\n        case OT_BOOL:\n            _fs->AddInstruction(_OP_LOADBOOL, stkPos, _integer(constval));\n            break;\n        case OT_NULL:\n            _fs->AddInstruction(_OP_LOADNULLS, stkPos, 1);\n            break;\n        default:\n            _fs->AddInstruction(_OP_LOAD, stkPos, _fs->GetConstant(constval));\n            break;\n        }\n    }\n    else {\n        reportDiagnostic(id, DiagnosticsId::DI_UNKNOWN_SYMBOL, id->name());\n    }\n}\n\n\nvoid CodeGenVisitor::visitForTarget(Node *n) {\n    ExprChainResolveMode old_mode = _resolve_mode;\n    _resolve_mode = ExprChainResolveMode::Target;\n    n->visit(this);\n    _resolve_mode = old_mode;\n}\n\nvoid CodeGenVisitor::visitForValue(Node *n) {\n    ExprChainResolveMode old_mode = _resolve_mode;\n    _resolve_mode = ExprChainResolveMode::Value;\n    n->visit(this);\n    _resolve_mode = old_mode;\n}\n\nbool CodeGenVisitor::visitMaybeStaticMemo(Node *n) {\n    // AST-level constant folding: fold compound const expressions to a single LOAD\n    if (GLOBAL_OPTIMIZATION_SWITCH && n->isExpression()) {\n        Expr *expr = n->asExpression();\n        TreeOp exprOp = expr->op();\n        // Skip leaves -- already handled optimally by their own visitors\n        if (exprOp != TO_LITERAL && exprOp != TO_ID && isConstEvaluable(expr)) {\n            emitInlineConst(expr);\n            return true;\n        }\n    }\n\n    bool arraysAndTablesFreezed = (_fs->lang_features & LF_ALLOW_AUTO_FREEZE) != 0;\n    int score = (n->isExpression() && !_inside_static_memo) ? getSubtreeConstScore(n->asExpression(), arraysAndTablesFreezed) : 0;\n    if (STATIC_MEMO_ENABLED && GLOBAL_OPTIMIZATION_SWITCH && score > STATIC_MEMO_CONST_SCORE_THRESHOLD && n->op() != TO_STATIC_MEMO &&\n        !(_fs->lang_features & LF_DISABLE_OPTIMIZER) && _complexity_level > 0) {\n        //reportDiagnostic(n, DiagnosticsId::DI_FORGOT_SUBST);\n        //printf(\"static memo applied const score=%d pos:%d:%d\\n\", getSubtreeConstScore(n->asExpression(), false), n->lineStart(), n->columnStart());\n        emitStaticMemo(n->asExpression(), /*is_auto_memo=*/true);\n    }\n    else {\n        if ((_fs->lang_features & LF_ALLOW_AUTO_FREEZE) != 0 &&\n            (n->op() == TO_ARRAY || n->op() == TO_TABLE || n->op() == TO_CLASS)) {\n\n            visitForValue(n);\n            SQInteger src = _fs->PopTarget();\n            _fs->AddInstruction(_OP_FREEZE, _fs->PushTarget(), src);\n        }\n        else\n            visitForValue(n);\n    }\n    return score > 0;\n}\n\nbool CodeGenVisitor::visitForValueMaybeStaticMemo(Node *n) {\n    ExprChainResolveMode old_mode = _resolve_mode;\n    _resolve_mode = ExprChainResolveMode::Value;\n    bool res = visitMaybeStaticMemo(n);\n    _resolve_mode = old_mode;\n    return res;\n}\n\n} // namespace SQCompilation\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/codegen.h",
    "content": "#pragma once\n\n#include \"ast.h\"\n#include \"opcodes.h\"\n#include \"compilationcontext.h\"\n\nstruct SQFuncState;\n\nnamespace SQCompilation {\n\nstruct SQScope {\n    SQInteger outers;\n    SQInteger stacksize;\n};\n\nclass CodeGenVisitor : public Visitor {\n\n    SQFuncState *_fs;\n    SQFuncState *_childFs;\n    SQVM *_vm;\n\n    SQScope _scope;\n    SQObjectPtrVec _scopedconsts;\n\n    // Handling of chain slot reference expressions such as `a.b.c` or `a[b][c]`.\n    enum class ExprChainResolveMode {\n        Value, // Fully resolve and fetch the value now (emit GET/GETOUTER opcodes, push constants, etc.).\n        Target // Do not fetch; leave the chain in a writable/callable form (e.g., receiver+key or outer ref)\n    };\n    ExprChainResolveMode _resolve_mode;\n\n    bool _inside_static_memo;\n    int _complexity_level;\n\n    const char *_sourceName;\n\n    Arena *_arena;\n\n    // This is used to pass variable stack positions from visitVarDecl() to visitDestructuringDecl()\n    // This is somewhat implicit and should be redone.\n    SQInteger _last_declared_var_pos = -1;\n\n    SQCompilationContext &_ctx;\n\npublic:\n    CodeGenVisitor(Arena *arena, const HSQOBJECT *bindings, SQVM *vm, const char *sourceName, SQCompilationContext &ctx);\n\n    bool generate(RootBlock *root, SQObjectPtr &out);\n\n    // API for const building\n    bool IsConstant(const SQObject &name, SQObjectPtr &e);\n    bool IsLocalConstant(const SQObject &name, SQObjectPtr &e);\n    bool IsGlobalConstant(const SQObject &name, SQObjectPtr &e);\n\n    SQObjectPtr compileConstFunc(FunctionExpr *funcExpr);\n\nprivate:\n\n    void reportDiagnostic(Node *n, int32_t id, ...);\n\n    void CheckDuplicateLocalIdentifier(Node *n, SQObject name, const char *desc, bool ignore_global_consts);\n    bool CheckMemberUniqueness(ArenaVector<Expr *> &vec, Expr *obj);\n\n    void EmitLoadConstInt(SQInteger value, SQInteger target);\n    void EmitLoadConstFloat(SQFloat value, SQInteger target);\n\n    void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve);\n    void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos);\n\n    void EmitDerefOp(SQOpcode op);\n    void EmitCheckType(int target, uint32_t type_mask);\n\n    void generateTableExpr(TableExpr *tableExpr);\n\n    SQTable* GetScopedConstsTable();\n    void SaveDocstringToVM(void *key, const DocObject &docObject);\n\n    void emitUnaryOp(SQOpcode op, UnExpr *arg);\n    void emitDelete(UnExpr *argument);\n    void emitSimpleBinaryOp(SQOpcode op, Expr *lhs, Expr *rhs, SQInteger op3 = 0);\n    void emitShortCircuitLogicalOp(SQOpcode op, Expr *lhs, Expr *rhs);\n    void emitCompoundArith(SQOpcode op, SQInteger opcode, Expr *lvalue, Expr *rvalue);\n    void emitStaticMemo(Expr *static_memo_arg, bool is_auto_memo = false);\n    void emitInlineConst(Expr *const_initializer);\n\n    bool _visit_arrays_and_tables;\n    Node *_variable_node;\n    int getSubtreeConstScore(Node *node, bool visit_arrays_and_tables);\n    int getSubtreeConstScoreImpl(Node *node);\n    bool findConstScoredVar(const SQObjectPtr &name, SQCompiletimeVarInfo &varInfo,\n                            unsigned requiredFlags);\n    SQInteger inferReceiverType(Expr *receiver);\n    bool isConstScoredMethodCall(GetFieldExpr *getField);\n    bool isConstScoredDirectCall(CallExpr *callExpr);\n    bool isConstEvaluable(Expr *expr);\n\n    void emitNewSlot(Expr *lvalue, Expr *rvalue);\n    void emitAssign(Expr *lvalue, Expr * rvalue);\n    void emitFieldAssign(int isLiteralIndex);\n\n    bool CanBeTypeMethod(const char *key);\n    bool CanBeTableTypeMethod(const char *key);\n    bool canBeLiteral(AccessExpr *expr);\n    SQObjectPtr GetTypeMethod(SQInteger sq_type, const char* key);\n\n    void MoveIfCurrentTargetIsLocal();\n\n    bool IsSimpleConstant(const SQObject &name);\n    bool DoesObjectContainOnlySimpleObjects(const SQObject &obj, int depth);\n    bool IsGuaranteedPureFunction(Node *expr);\n\n    SQObjectPtr convertLiteral(LiteralExpr *lit);\n\n    void maybeAddInExprLine(Expr *expr);\n\n    void addLineNumber(Node *node);\n\n    void visitForTarget(Node *n);\n    void visitForValue(Node *n);\n    bool visitMaybeStaticMemo(Node *n);\n    bool visitForValueMaybeStaticMemo(Node *n);\n\n    void selectConstant(SQInteger target, const SQObjectPtr &constant);\n    void addPatchDocObjectInstruction(const DocObject &docObject);\n\n    unsigned inferExprTypeMask(Expr *expr);\n    unsigned inferExprTypeMaskImpl(Expr *expr);\n    bool checkInferredType(Node *reportNode, Expr *expr, unsigned declaredMask);\n\n    Expr *deparen(Expr *e) const;\n    bool isFreezeCall(Expr *node);\n    Expr *skipConstFreezePure(Expr *expr);\n    bool isPureFunctionCall(Expr *node);\n\n    SQObjectPtr compileFunc(FunctionExpr *funcExpr, bool is_const, sqvector<SQObjectPtr> *out_defparam_values);\n\npublic:\n\n    void visitBlock(Block *block) override;\n    void visitCodeBlockExpr(CodeBlockExpr *expr) override;\n    void visitIfStatement(IfStatement *ifStmt) override;\n    void visitWhileStatement(WhileStatement *whileLoop) override;\n    void visitDoWhileStatement(DoWhileStatement *doWhileLoop) override;\n    void visitForStatement(ForStatement *forLoop) override;\n    void visitForeachStatement(ForeachStatement *foreachLoop) override;\n    void visitSwitchStatement(SwitchStatement *swtch) override;\n    void visitTryStatement(TryStatement *tryStmt) override;\n    void visitBreakStatement(BreakStatement *breakStmt) override;\n    void visitContinueStatement(ContinueStatement *continueStmt) override;\n    void visitTerminateStatement(TerminateStatement *terminator) override;\n    void visitReturnStatement(ReturnStatement *retStmt) override;\n    void visitYieldStatement(YieldStatement *yieldStmt) override;\n    void visitThrowStatement(ThrowStatement *throwStmt) override;\n    void visitExprStatement(ExprStatement *stmt) override;\n    void visitTableExpr(TableExpr *tableExpr) override;\n    void visitClassExpr(ClassExpr *klass) override;\n    void visitParamDecl(ParamDecl *param) override;\n    void visitVarDecl(VarDecl *var) override;\n    void visitDeclGroup(DeclGroup *group) override;\n    void visitDestructuringDecl(DestructuringDecl *destruct) override;\n    void visitFunctionExpr(FunctionExpr *func) override;\n    void visitConstDecl(ConstDecl *decl) override;\n    void visitEnumDecl(EnumDecl *enums) override;\n    void visitCallExpr(CallExpr *call) override;\n    void visitBaseExpr(BaseExpr *base) override;\n    void visitRootTableAccessExpr(RootTableAccessExpr *expr) override;\n    void visitLiteralExpr(LiteralExpr *lit) override;\n    void visitArrayExpr(ArrayExpr *expr) override;\n    void visitUnExpr(UnExpr *unary) override;\n    void visitGetFieldExpr(GetFieldExpr *expr) override;\n    void visitGetSlotExpr(GetSlotExpr *expr) override;\n    void visitBinExpr(BinExpr *expr) override;\n    void visitTerExpr(TerExpr *expr) override;\n    void visitIncExpr(IncExpr *expr) override;\n    void visitId(Id *id) override;\n    void visitCommaExpr(CommaExpr *expr) override;\n    void visitDirectiveStatement(DirectiveStmt *dir) override;\n};\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/compilationcontext.cpp",
    "content": "\n#include <assert.h>\n#include <memory.h>\n#include <sqconfig.h>\n#include \"compilationcontext.h\"\n#include \"sqstring.h\"\n#include \"keyValueFile.h\"\n#include <sq_char_class.h>\n\nnamespace SQCompilation {\n\n\nenum DiagnosticSubsystem {\n  DSS_LEX,\n  DSS_SYNTAX,\n  DSS_SEMA,\n  DSS_COMPILETIME,\n};\n\nstruct DiagnosticDescriptor {\n  const char *format;\n  const enum DiagnosticSeverity severity;\n  const enum DiagnosticSubsystem subsystem;\n  const int32_t id;\n  const char *textId;\n  bool disabled;\n};\n\nstatic const char severityPrefixes[] = \"hwe\";\nstatic const char *severityNames[] = {\n  \"HINT\", \"WARNING\", \"ERROR\", nullptr\n};\n\nstatic DiagnosticDescriptor diagnosticDescriptors[] = {\n#define DEF_DIAGNOSTIC(_, severity, subsytem, num_id, text_id, fmt) { fmt, DS_##severity, DSS_##subsytem, num_id, text_id, false }\n  DIAGNOSTICS\n#undef DEF_DIAGNOSTIC\n};\n\nSQCompilationContext::SQCompilationContext(SQVM *vm, Arena *arena, const char *sn, const char *code, size_t csize, const Comments *comments, bool raiseError)\n  : _vm(vm)\n  , _arena(arena)\n  , _sourceName(sn)\n  , _linemap(_ss(vm)->_alloc_ctx)\n  , _comments(comments)\n  , _code(code)\n  , _codeSize(csize)\n  , _raiseError(raiseError)\n{\n}\n\nSQCompilationContext::~SQCompilationContext()\n{\n}\n\nComments::~Comments() {\n  SQAllocContext ctx = _commentsList._alloc_ctx;\n\n  for (auto &lc : _commentsList) {\n    for (auto &c : lc) {\n      sq_vm_free(ctx, (void *)c.text, c.size + 1);\n    }\n  }\n}\n\nconst Comments::LineCommentsList &Comments::lineComment(int line) const {\n  if (_commentsList.empty())\n    return emptyComments;\n\n  line -= 1;\n  assert(0 <= line && line < _commentsList.size());\n  return _commentsList[line];\n}\n\n\nvoid SQCompilationContext::buildLineMap() {\n  assert(_code != NULL);\n\n  int prev = '\\n';\n\n  for (size_t i = 0; i < _codeSize; ++i) {\n    if (prev == '\\n') {\n      _linemap.push_back(i);\n    }\n\n    prev = _code[i];\n  }\n}\n\nconst char *SQCompilationContext::findLine(int lineNo) {\n  if (_linemap.empty())\n    buildLineMap();\n\n  lineNo -= 1;\n  if (lineNo < 0 || lineNo >= _linemap.size())\n    return nullptr;\n\n  return _code + _linemap[lineNo];\n}\n\n\nvoid SQCompilationContext::printAllWarnings(FILE *ostream) {\n  for (auto &diag : diagnosticDescriptors) {\n    if (diag.severity == DS_ERROR)\n      continue;\n    fprintf(ostream, \"w%d (%s)\\n\", diag.id, diag.textId);\n    fprintf(ostream, diag.format, \"***\", \"***\", \"***\", \"***\", \"***\", \"***\", \"***\", \"***\");\n    fprintf(ostream, \"\\n\\n\");\n  }\n}\n\nbool SQCompilationContext::enableWarning(const char *diagName, bool state) {\n  for (auto &diag : diagnosticDescriptors) {\n    if (strcmp(diagName, diag.textId) == 0) {\n      if (diag.severity != DS_ERROR) {\n        diag.disabled = !state;\n      }\n      return true;\n    }\n  }\n  return false;\n}\n\nbool SQCompilationContext::enableWarning(int32_t id, bool state) {\n  for (auto &diag : diagnosticDescriptors) {\n    if (id == diag.id) {\n      if (diag.severity != DS_ERROR) {\n        diag.disabled = !state;\n      }\n      return true;\n    }\n  }\n  return false;\n}\n\nvoid SQCompilationContext::switchSyntaxWarningsState(bool state) {\n  for (auto &diag : diagnosticDescriptors) {\n    if (diag.severity == DS_WARNING && (diag.subsystem == DSS_SYNTAX || diag.subsystem == DSS_LEX || diag.subsystem == DSS_COMPILETIME)) {\n      diag.disabled = !state;\n    }\n  }\n}\n\nbool SQCompilationContext::isRequireDisabled(int line, int col) {\n  if (!_comments)\n    return false;\n\n  auto &lineCmts = _comments->lineComment(line);\n  for (auto &comment : lineCmts) {\n    if (strstr(comment.text, \"-skip-require\"))\n      return true;\n  }\n\n  return false;\n}\n\nbool SQCompilationContext::isDisabled(enum DiagnosticsId id, int line, int pos) {\n  DiagnosticDescriptor &descriptor = diagnosticDescriptors[id];\n  if (descriptor.severity >= DS_ERROR) return false;\n\n  if (descriptor.disabled) return true;\n\n  if (!_comments)\n    return false;\n\n  const Comments::LineCommentsList &lineCmts = _comments->lineComment(line);\n\n  char suppressLineIntBuf[64] = { 0 };\n  char suppressLineTextBuf[128] = { 0 };\n  snprintf(suppressLineIntBuf, sizeof(suppressLineIntBuf), \"-%c%d\", severityPrefixes[descriptor.severity], descriptor.id);\n  snprintf(suppressLineTextBuf, sizeof(suppressLineTextBuf), \"-%s\", descriptor.textId);\n\n  for (auto &comment : lineCmts) {\n    if (strstr(comment.text, suppressLineIntBuf))\n      return true;\n\n    if (strstr(comment.text, suppressLineTextBuf))\n      return true;\n  }\n\n  char suppressFileIntBuf[64] = { 0 };\n  char suppressFileTextBuf[128] = { 0 };\n  snprintf(suppressFileIntBuf, sizeof(suppressFileIntBuf), \"-file:%c%d\", severityPrefixes[descriptor.severity], descriptor.id);\n  snprintf(suppressFileTextBuf, sizeof(suppressFileTextBuf), \"-file:%s\", descriptor.textId);\n\n  for (auto &lineComments : _comments->commentsList()) {\n    for (auto &comment : lineComments) {\n      if (strstr(comment.text, suppressFileIntBuf))\n        return true;\n\n      if (strstr(comment.text, suppressFileTextBuf))\n        return true;\n    }\n  }\n\n  return false;\n}\n\nstatic void drawUnderliner(int32_t column, int32_t width, std::string &msg)\n{\n  int32_t i = 0;\n  while (i < column) {\n    msg.push_back(' ');\n    ++i;\n  }\n\n  ++i;\n  msg.push_back('^');\n\n  while ((i - column) < width) {\n    msg.push_back('-');\n    ++i;\n  }\n}\n\n\nbool SQCompilationContext::isBlankLine(const char *l) {\n  if (!l) return true;\n  while ((l < _code + _codeSize) && *l && *l != '\\n') {\n    if (!sq_isspace(*l)) return false;\n    ++l;\n  }\n  return true;\n}\n\nvoid SQCompilationContext::renderDiagnosticHeader(enum DiagnosticsId diag, std::string *msg, ...) {\n  va_list vargs;\n  va_start(vargs, msg);\n  vrenderDiagnosticHeader(diag, *msg, vargs);\n  va_end(vargs);\n}\n\nvoid SQCompilationContext::vrenderDiagnosticHeader(enum DiagnosticsId diag, std::string &message, va_list vargs) {\n  auto &desc = diagnosticDescriptors[diag];\n  char tempBuffer[2048] = { 0 };\n\n  snprintf(tempBuffer, sizeof tempBuffer, \"%s: \", severityNames[desc.severity]);\n\n  message.append(tempBuffer);\n\n  if (desc.id > 0) {\n    snprintf(tempBuffer, sizeof tempBuffer, \"%c%d (%s) \", severityPrefixes[desc.severity], desc.id, desc.textId);\n    message.append(tempBuffer);\n  }\n\n  vsnprintf(tempBuffer, sizeof tempBuffer, desc.format, vargs);\n\n  message.append(tempBuffer);\n}\n\nvoid SQCompilationContext::vreportDiagnostic(enum DiagnosticsId diagId, int32_t line, int32_t pos, int32_t width, va_list vargs) {\n  assert(diagId < DI_NUM_OF_DIAGNOSTICS);\n\n  bool terminate = false;\n\n  if (!isDisabled(diagId, line, pos)) {\n\n    auto &desc = diagnosticDescriptors[diagId];\n    bool isError = desc.severity >= DS_ERROR;\n    std::string message;\n\n    vrenderDiagnosticHeader(diagId, message, vargs);\n\n    std::string extraInfo;\n\n    const char *l1 = findLine(line - 1);\n    const char *l2 = findLine(line);\n    const char *l3 = findLine(line + 1);\n    const char *lastSourceCodeChar = _code + _codeSize - 1;\n\n    if (l1 != nullptr && !isBlankLine(l1)) {\n      extraInfo.push_back('\\n');\n      int32_t j = 0;\n      while ((l1 + j <= lastSourceCodeChar) && l1[j] && l1[j] != '\\n' && l1[j] != '\\r') { //-V522\n        extraInfo.push_back(l1[j++]); //-V595\n      }\n    }\n\n    if (l2 != nullptr) {\n      extraInfo.push_back('\\n');\n      int32_t j = 0;\n      while ((l2 + j <= lastSourceCodeChar) && l2[j] && l2[j] != '\\n' && l2[j] != '\\r') { //-V522\n        extraInfo.push_back(l2[j++]); //-V595\n      }\n\n      extraInfo.push_back('\\n');\n      j = 0;\n\n      drawUnderliner(pos, width, extraInfo);\n    }\n\n    if (l3 != nullptr && !isBlankLine(l3)) {\n      extraInfo.push_back('\\n');\n      int32_t j = 0;\n      while ((l3 + j <= lastSourceCodeChar) && l3[j] && l3[j] != '\\n' && l3[j] != '\\r') { //-V522\n        extraInfo.push_back(l3[j++]); //-V595\n      }\n    }\n\n    const char *extra = nullptr;\n    if (l1 || l2 || l3) {\n      extraInfo.push_back('\\n');\n      extraInfo.push_back('\\n'); // separate with extra line\n      extra = extraInfo.c_str();\n    }\n\n    auto messageFunc = _ss(_vm)->_compilererrorhandler;\n\n    const char *msg = message.c_str();\n\n    auto diagMsgFunc = _ss(_vm)->_compilerdiaghandler;\n    if (diagMsgFunc) {\n      SQCompilerMessage cm;\n      cm.intId = desc.id;\n      cm.textId = desc.textId;\n      cm.line = line;\n      cm.column = pos;\n      cm.columnsWidth = width;\n      cm.message = msg;\n      cm.fileName = _sourceName;\n      cm.isError = isError;\n      diagMsgFunc(_vm, &cm);\n    }\n\n    if (_raiseError && messageFunc) {\n      SQMessageSeverity sev = SEV_ERROR;\n      if (desc.severity == DS_HINT) sev = SEV_HINT;\n      else if (desc.severity == DS_WARNING) sev = SEV_WARNING;\n      messageFunc(_vm, sev, msg, _sourceName, line, pos, extra);\n    }\n    if (isError) {\n      _vm->_lasterror = SQString::Create(_ss(_vm), msg, message.length());\n      terminate = true;\n    }\n  }\n\n  if (terminate)\n    throw CompilerError();\n}\n\nvoid SQCompilationContext::reportDiagnostic(enum DiagnosticsId diagId, int32_t line, int32_t pos, int32_t width, ...) {\n  va_list vargs;\n  va_start(vargs, width);\n  vreportDiagnostic(diagId, line, pos, width, vargs);\n  va_end(vargs);\n}\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/compilationcontext.h",
    "content": "#pragma once\n\n#include <string>\n#include <stdint.h>\n#include <stdarg.h>\n#include <vector>\n#include \"squirrel.h\"\n#include \"sqvm.h\"\n#include \"sqstate.h\"\n#include \"squtils.h\"\n#include \"arena.h\"\n\nclass KeyValueFile;\n\n/*\n  Do we need identifiers for errors?\n  Unlike warninggs, errors have no id (numeric or symbolic), cannot be turned on and off,\n  cannot be of type other than ERROR.\n  So instead of reportDiagnostic(), we may just have throwError() function with printf-like args\n  and this would break the compilation process immediately.\n  And reportDiagnostic() would do just like it does now - only report warnings.\n  For convenience, adding GENERAL_COMPILE_ERROR for now - no need to add new identifiers\n  to use it in a single place.\n  Note how there are not benefits in separate ids for errors over GENERAL_COMPILE_ERROR -\n  it already does all what is needed.\n*/\n\n#define DIAGNOSTICS \\\n  DEF_DIAGNOSTIC(GENERAL_COMPILE_ERROR, ERROR, LEX, -1, \"\", \"%s\"), \\\n  DEF_DIAGNOSTIC(LITERAL_OVERFLOW, ERROR, LEX, -1, \"\", \"%s constant overflow\"), \\\n  DEF_DIAGNOSTIC(LITERAL_UNDERFLOW, ERROR, LEX, -1, \"\", \"%s constant underflow\"), \\\n  DEF_DIAGNOSTIC(FP_EXP_EXPECTED, ERROR, LEX, -1, \"\", \"exponent expected\"), \\\n  DEF_DIAGNOSTIC(MALFORMED_NUMBER, ERROR, LEX, -1, \"\", \"malformed number\"), \\\n  DEF_DIAGNOSTIC(HEX_DIGITS_EXPECTED, ERROR, LEX, -1, \"\", \"expected hex digits after '0x'\"), \\\n  DEF_DIAGNOSTIC(HEX_TOO_MANY_DIGITS, ERROR, LEX, -1, \"\", \"too many digits for a hex number\"), \\\n  DEF_DIAGNOSTIC(OCTAL_NOT_SUPPORTED, ERROR, LEX, -1, \"\", \"leading 0 is not allowed, octal numbers are not supported\"), \\\n  DEF_DIAGNOSTIC(TOO_LONG_LITERAL, ERROR, LEX, -1, \"\", \"constant too long\"), \\\n  DEF_DIAGNOSTIC(EMPTY_LITERAL, ERROR, LEX, -1, \"\", \"empty constant\"), \\\n  DEF_DIAGNOSTIC(UNRECOGNISED_ESCAPER, ERROR, LEX, -1, \"\", \"unrecognised escape char\"), \\\n  DEF_DIAGNOSTIC(NEWLINE_IN_CONST, ERROR, LEX, -1, \"\", \"newline in a constant\"), \\\n  DEF_DIAGNOSTIC(UNFINISHED_STRING, ERROR, LEX, -1, \"\", \"unfinished string\"), \\\n  DEF_DIAGNOSTIC(HEX_NUMBERS_EXPECTED, ERROR, LEX, -1, \"\", \"hexadecimal number expected\"), \\\n  DEF_DIAGNOSTIC(UNEXPECTED_CHAR, ERROR, LEX, -1, \"\", \"unexpected character '%s'\"), \\\n  DEF_DIAGNOSTIC(INVALID_TOKEN, ERROR, LEX, -1, \"\", \"invalid token '%s'\"), \\\n  DEF_DIAGNOSTIC(LEX_ERROR_PARSE, ERROR, LEX, -1, \"\", \"error parsing %s\"), \\\n  DEF_DIAGNOSTIC(BRACE_ORDER, ERROR, LEX, -1, \"\", \"in brace order\"), \\\n  DEF_DIAGNOSTIC(NO_PARAMS_IN_STRING_TEMPLATE, ERROR, LEX, -1, \"\", \"no params collected for string interpolation\"), \\\n  DEF_DIAGNOSTIC(COMMENT_IN_STRING_TEMPLATE, ERROR, LEX, -1, \"\", \"comments inside interpolated string are not supported\"), \\\n  DEF_DIAGNOSTIC(EXPECTED_LEX, ERROR, LEX, -1, \"\", \"expected %s\"), \\\n  DEF_DIAGNOSTIC(MACRO_RECURSION, ERROR, LEX, -1, \"\", \"recursion in reader macro\"), \\\n  DEF_DIAGNOSTIC(INVALID_CHAR, ERROR, LEX, -1, \"\", \"Invalid character\"), \\\n  DEF_DIAGNOSTIC(TRAILING_BLOCK_COMMENT, ERROR, LEX, -1, \"\", \"missing \\\"*/\\\" in comment\"), \\\n  DEF_DIAGNOSTIC(GLOBAL_CONSTS_ONLY, ERROR, SYNTAX, -1, \"\", \"global can be applied to const and enum only\"), \\\n  DEF_DIAGNOSTIC(END_OF_STMT_EXPECTED, ERROR, SYNTAX, -1, \"\", \"end of statement expected (; or lf)\"), \\\n  DEF_DIAGNOSTIC(EXPECTED_TOKEN, ERROR, SYNTAX, -1, \"\", \"expected '%s'\"), \\\n  DEF_DIAGNOSTIC(INVALID_TYPE_NAME_SUGGESTION, ERROR, SYNTAX, -1, \"\", \"Invalid type name '%s', did you mean '%s'?\"), \\\n  DEF_DIAGNOSTIC(INVALID_TYPE_NAME, ERROR, SYNTAX, -1, \"\", \"Invalid type name '%s'\"), \\\n  DEF_DIAGNOSTIC(UNSUPPORTED_DIRECTIVE, ERROR, SYNTAX, -1, \"\", \"unsupported directive '%s'\"), \\\n  DEF_DIAGNOSTIC(EXPECTED_LINENUM, ERROR, SYNTAX, -1, \"\", \"expected line number after #pos:\"), \\\n  DEF_DIAGNOSTIC(EXPECTED_COLNUM, ERROR, SYNTAX, -1, \"\", \"expected column number after #pos:<line>:\"), \\\n  DEF_DIAGNOSTIC(TOO_BIG_AST, ERROR, SYNTAX, -1, \"\", \"AST too big. Consider simplifying it\"), \\\n  DEF_DIAGNOSTIC(TOO_BIG_STATIC_MEMO, ERROR, SYNTAX, -1, \"\", \"static expression is too big\"), \\\n  DEF_DIAGNOSTIC(MULTIPLE_DOCSTRINGS, ERROR, SYNTAX, -1, \"\", \"multiple docstrings in a single block\"), \\\n  DEF_DIAGNOSTIC(ASSIGN_INSIDE_FORBIDDEN, ERROR, SYNTAX, -1, \"\", \"'=' inside '%s' is forbidden\"), \\\n  DEF_DIAGNOSTIC(BROKEN_SLOT_DECLARATION, ERROR, SYNTAX, -1, \"\", \"cannot break deref/or comma needed after [exp]=exp slot declaration\"), \\\n  DEF_DIAGNOSTIC(ROOT_TABLE_FORBIDDEN, ERROR, SYNTAX, -1, \"\", \"Access to root table is forbidden\"), \\\n  DEF_DIAGNOSTIC(DELETE_OP_FORBIDDEN, ERROR, SYNTAX, -1, \"\", \"Usage of 'delete' operator is forbidden. Use 'o.rawdelete(\\\"key\\\")' instead\"), \\\n  DEF_DIAGNOSTIC(COMPILER_INTERNALS_FORBIDDEN, ERROR, SYNTAX, -1, \"\", \"Access to compiler internals is forbidden\"), \\\n  DEF_DIAGNOSTIC(UNINITIALIZED_BINDING, ERROR, SEMA, -1, \"\", \"Binding '%s' must be initialized\"), \\\n  DEF_DIAGNOSTIC(SAME_FOREACH_KV_NAMES, ERROR, SEMA, -1, \"\", \"foreach() key and value names are the same: '%s'\"), \\\n  DEF_DIAGNOSTIC(SCALAR_EXPECTED, ERROR, SYNTAX, -1, \"\", \"scalar expected : %s\"), \\\n  DEF_DIAGNOSTIC(VARARG_WITH_DEFAULT_ARG, ERROR, SYNTAX, -1, \"\", \"function with default parameters cannot have variable number of parameters\"), \\\n  DEF_DIAGNOSTIC(LOOP_CONTROLLER_NOT_IN_LOOP, ERROR, SEMA, -1, \"\", \"'%s' has to be in a loop block\"), \\\n  DEF_DIAGNOSTIC(ASSIGN_TO_EXPR, ERROR, SEMA, -1, \"\", \"can't assign to expression\"), \\\n  DEF_DIAGNOSTIC(BASE_NOT_MODIFIABLE, ERROR, SEMA, -1, \"\", \"'base' cannot be modified\"), \\\n  DEF_DIAGNOSTIC(ASSIGN_TO_BINDING, ERROR, SEMA, -1, \"\", \"can't assign to binding '%s' (probably declaring using 'local' was intended, but 'let' was used)\"), \\\n  DEF_DIAGNOSTIC(LOCAL_SLOT_CREATE, ERROR, SEMA, -1, \"\", \"can't 'create' a local slot\"), \\\n  DEF_DIAGNOSTIC(CANNOT_INC_DEC, ERROR, SEMA, -1, \"\", \"can't '++' or '--' %s\"), \\\n  DEF_DIAGNOSTIC(VARNAME_CONFLICTS, ERROR, SEMA, -1, \"\", \"Variable name %s conflicts with function name\"), \\\n  DEF_DIAGNOSTIC(ONLY_SINGLE_VARIABLE_DECLARATION, ERROR, SEMA, -1, \"\", \"Only single variable declaration is allowed here\"), \\\n  DEF_DIAGNOSTIC(INITIALIZATION_REQUIRED, ERROR, SEMA, -1, \"\", \"Initialization required\"), \\\n  DEF_DIAGNOSTIC(INVALID_ENUM, ERROR, SEMA, -1, \"\", \"invalid enum [no '%s' field in '%s']\"), \\\n  DEF_DIAGNOSTIC(UNKNOWN_SYMBOL, ERROR, SEMA, -1, \"\", \"Unknown variable [%s]\"), \\\n  DEF_DIAGNOSTIC(CANNOT_EVAL_UNARY, ERROR, SEMA, -1, \"\", \"cannot evaluate unary-op\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_KEY, ERROR, SEMA, -1, \"\", \"duplicate key '%s'\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_FUNC_ATTR, ERROR, SEMA, -1, \"\", \"duplicate attribute '%s'\"), \\\n  DEF_DIAGNOSTIC(INVALID_SLOT_INIT, ERROR, SEMA, -1, \"\", \"Invalid slot initializer '%s' - no such variable/constant or incorrect expression\"), \\\n  DEF_DIAGNOSTIC(CANNOT_DELETE, ERROR, SEMA, -1, \"\", \"can't delete %s\"), \\\n  DEF_DIAGNOSTIC(CONFLICTS_WITH, ERROR, SEMA, -1, \"\", \"%s name '%s' conflicts with %s\"), \\\n  DEF_DIAGNOSTIC(INC_DEC_NOT_ASSIGNABLE, ERROR, SEMA, -1, \"\", \"argument of inc/dec operation is not assignable\"), \\\n  DEF_DIAGNOSTIC(TYPE_DIFFERS, ERROR, SEMA, -1, \"\", \"%s type differs from the declared type\"), \\\n  DEF_DIAGNOSTIC(INFERRED_TYPE_MISMATCH, ERROR, SEMA, -1, \"\", \"expression of type '%s' cannot be assigned to type '%s'\"), \\\n  DEF_DIAGNOSTIC(SPACE_SEP_FIELD_NAME, ERROR, SEMA, -1, \"\", \"Separate access operator '%s' with its following name is forbidden\"), \\\n  DEF_DIAGNOSTIC(TOO_MANY_SYMBOLS, ERROR, SEMA, -1, \"\", \"internal compiler error: too many %s\"), \\\n  DEF_DIAGNOSTIC(NOT_ALLOWED_IN_CONST, ERROR, SEMA, -1, \"\", \"%s is not allowed in constant\"), \\\n  DEF_DIAGNOSTIC(ID_IS_NOT_CONST, ERROR, SEMA, -1, \"\", \"Identifier '%s' is not a compile-time constant\"), \\\n  DEF_DIAGNOSTIC(CONSTANT_SLOT_NOT_FOUND, ERROR, SEMA, -1, \"\", \"%s slot %s not found in constant object\"), \\\n  DEF_DIAGNOSTIC(CONSTANT_FIELD_NOT_FOUND, ERROR, SEMA, -1, \"\", \"Field '%s' not found in constant object\"), \\\n  DEF_DIAGNOSTIC(PAREN_IS_FUNC_CALL, WARNING, SYNTAX, 190, \"paren-is-function-call\", \"'(' on a new line parsed as function call.\"), \\\n  DEF_DIAGNOSTIC(STMT_SAME_LINE, WARNING, SYNTAX, 192, \"statement-on-same-line\", \"Next statement on the same line after '%s' statement.\"), \\\n  DEF_DIAGNOSTIC(NULLABLE_OPERANDS, WARNING, SEMA, 200, \"potentially-nulled-ops\", \"%s with potentially nullable expression.\"), \\\n  DEF_DIAGNOSTIC(AND_OR_PAREN, WARNING, SEMA, 202, \"and-or-paren\", \"Priority of the '&&' operator is higher than that of the '||' operator. Perhaps parentheses are missing?\"), \\\n  DEF_DIAGNOSTIC(BITWISE_BOOL_PAREN, WARNING, SEMA, 203, \"bitwise-bool-paren\", \"Result of bitwise operation used in boolean expression. Perhaps parentheses are missing?\"), \\\n  DEF_DIAGNOSTIC(BITWISE_OP_TO_BOOL, WARNING, SEMA, 204, \"bitwise-apply-to-bool\", \"The '&' or '|' operator is applied to boolean type. You've probably forgotten to include parentheses or intended to use the '&&' or '||' operator.\"), \\\n  DEF_DIAGNOSTIC(UNREACHABLE_CODE, WARNING, SEMA, 205, \"unreachable-code\", \"Unreachable code after '%s'.\"), \\\n  DEF_DIAGNOSTIC(ASSIGNED_TWICE, WARNING, SEMA, 206, \"assigned-twice\", \"Variable is assigned twice successively.\"), \\\n  DEF_DIAGNOSTIC(NULLABLE_ASSIGNMENT, WARNING, SEMA, 208, \"potentially-nulled-assign\", \"Assignment to potentially nullable expression.\"), \\\n  DEF_DIAGNOSTIC(ASG_TO_ITSELF, WARNING, SEMA, 209, \"assigned-to-itself\", \"The variable is assigned to itself.\"), \\\n  DEF_DIAGNOSTIC(POTENTIALLY_NULLABLE_INDEX, WARNING, SEMA, 210, \"potentially-nulled-index\", \"Potentially nullable expression used as array index.\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_CASE, WARNING, SEMA, 211, \"duplicate-case\", \"Duplicate case value.\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_IF_EXPR, WARNING, SEMA, 212, \"duplicate-if-expression\", \"Detected pattern 'if (A) {...} else if (A) {...}'. Branch unreachable.\"), \\\n  DEF_DIAGNOSTIC(THEN_ELSE_EQUAL, WARNING, SEMA, 213, \"then-and-else-equals\", \"'then' statement is equivalent to 'else' statement.\"), \\\n  DEF_DIAGNOSTIC(TERNARY_SAME_VALUES, WARNING, SEMA, 214, \"operator-returns-same-val\", \"Both branches of operator '<> ? <> : <>' are equivalent.\"), \\\n  DEF_DIAGNOSTIC(TERNARY_PRIOR, WARNING, SEMA, 215, \"ternary-priority\", \"The '?:' operator has lower priority than the '%s' operator. Perhaps the '?:' operator works in a different way than it was expected.\"), \\\n  DEF_DIAGNOSTIC(SAME_OPERANDS, WARNING, SEMA, 216, \"same-operands\", \"Left and right operands of '%s' operator are the same.\"), \\\n  DEF_DIAGNOSTIC(UNCOND_TERMINATED_LOOP, WARNING, SEMA, 217, \"unconditional-terminated-loop\", \"Unconditional '%s' inside a loop.\"), \\\n  DEF_DIAGNOSTIC(POTENTIALLY_NULLABLE_CONTAINER, WARNING, SEMA, 220, \"potentially-nulled-container\", \"'foreach' on potentially nullable expression.\"), \\\n  DEF_DIAGNOSTIC(UNUTILIZED_EXPRESSION, WARNING, SEMA, 221, \"result-not-utilized\", \"Result of operation is not used.\"), \\\n  DEF_DIAGNOSTIC(BOOL_AS_INDEX, WARNING, SEMA, 222, \"bool-as-index\", \"Boolean used as array index.\"), \\\n  DEF_DIAGNOSTIC(COMPARE_WITH_BOOL, WARNING, SEMA, 223, \"compared-with-bool\", \"Comparison with boolean.\"), \\\n  DEF_DIAGNOSTIC(EMPTY_BODY, WARNING, SEMA, 224, \"empty-body\", \"%s has an empty body.\"), \\\n  DEF_DIAGNOSTIC(NOT_ALL_PATH_RETURN_VALUE, WARNING, SEMA, 225, \"all-paths-return-value\", \"Not all control paths return a value.\"), \\\n  DEF_DIAGNOSTIC(RETURNS_DIFFERENT_TYPES, WARNING, SEMA, 226, \"return-different-types\", \"Function can return different types.\"), \\\n  DEF_DIAGNOSTIC(ID_HIDES_ID, WARNING, SEMA, 227, \"ident-hides-ident\", \"%s '%s' hides %s with the same name.\"), \\\n  DEF_DIAGNOSTIC(DECLARED_NEVER_USED, WARNING, SEMA, 228, \"declared-never-used\", \"%s '%s' was declared but never used.\"), \\\n  DEF_DIAGNOSTIC(COPY_OF_EXPR, WARNING, SEMA, 229, \"copy-of-expression\", \"Duplicate expression found inside the sequence of operations.\"), \\\n  DEF_DIAGNOSTIC(IMPORTED_NEVER_USED, WARNING, SEMA, 230, \"imported-never-used\", \"Imported field '%s' was never used.\"), \\\n  DEF_DIAGNOSTIC(FORMAT_ARGUMENTS_COUNT, WARNING, SEMA, 231, \"format-arguments-count\", \"Format string: arguments count mismatch.\"), \\\n  DEF_DIAGNOSTIC(ALWAYS_T_OR_F, WARNING, SEMA, 232, \"always-true-or-false\", \"Expression is always '%s'.\"), \\\n  DEF_DIAGNOSTIC(CONST_IN_BOOL_EXPR, WARNING, SEMA, 233, \"const-in-bool-expr\", \"Constant in a boolean expression.\"), \\\n  DEF_DIAGNOSTIC(DIV_BY_ZERO, WARNING, SEMA, 234, \"div-by-zero\", \"Integer division by zero.\"), \\\n  DEF_DIAGNOSTIC(ROUND_TO_INT, WARNING, SEMA, 235, \"round-to-int\", \"Result of division will be integer.\"), \\\n  DEF_DIAGNOSTIC(SHIFT_PRIORITY, WARNING, SEMA, 236, \"shift-priority\", \"Shift operator has lower priority. Perhaps parentheses are missing?\"), \\\n  DEF_DIAGNOSTIC(NAME_LIKE_SHOULD_RETURN, WARNING, SEMA, 238, \"named-like-should-return\", \"Function name '%s' implies a return value, but its result is never used.\"), \\\n  DEF_DIAGNOSTIC(NAME_RET_BOOL, WARNING, SEMA, 239, \"named-like-return-bool\", \"Function name '%s' implies a return boolean type but not all control paths return boolean.\"), \\\n  DEF_DIAGNOSTIC(NULL_COALESCING_PRIORITY, WARNING, SEMA, 240, \"null-coalescing-priority\", \"The '??\"\"' operator has a lower priority than the '%s' operator (a??b > c == a??\"\"(b > c)). Perhaps the '??\"\"' operator works in a different way than it was expected.\"), \\\n  DEF_DIAGNOSTIC(ALREADY_REQUIRED, WARNING, SEMA, 241, \"already-required\", \"Module '%s' has been required already.\"), \\\n  DEF_DIAGNOSTIC(USED_FROM_STATIC, WARNING, SEMA, 244, \"used-from-static\", \"Access 'this.%s' from %s function.\"), \\\n  DEF_DIAGNOSTIC(ACCESS_POT_NULLABLE, WARNING, SEMA, 248, \"access-potentially-nulled\", \"'%s' can be null, but is used as a %s without checking.\"), \\\n  DEF_DIAGNOSTIC(CMP_WITH_CONTAINER, WARNING, SEMA, 250, \"cmp-with-container\", \"Comparison with a %s.\"), \\\n  DEF_DIAGNOSTIC(BOOL_PASSED_TO_STRANGE, WARNING, SEMA, 254, \"bool-passed-to-strange\", \"Boolean passed to '%s' operator.\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_FUNC, WARNING, SEMA, 255, \"duplicate-function\", \"Duplicate function body. Consider functions '%s' and '%s'.\"), \\\n  DEF_DIAGNOSTIC(KEY_NAME_MISMATCH, WARNING, SEMA, 256, \"key-and-function-name\", \"Key and function name are not the same ('%s' and '%s').\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_ASSIGN_EXPR, WARNING, SEMA, 257, \"duplicate-assigned-expr\", \"Duplicate of the assigned expression.\"), \\\n  DEF_DIAGNOSTIC(SIMILAR_FUNC, WARNING, SEMA, 258, \"similar-function\", \"Function bodies are very similar. Consider functions '%s' and '%s'.\"), \\\n  DEF_DIAGNOSTIC(SIMILAR_ASSIGN_EXPR, WARNING, SEMA, 259, \"similar-assigned-expr\", \"Assigned expression is very similar to one of the previous ones.\"), \\\n  DEF_DIAGNOSTIC(NAME_EXPECTS_RETURN, WARNING, SEMA, 260, \"named-like-must-return-result\", \"Function '%s' has name like it should return a value, but not all control paths return a value.\"), \\\n  DEF_DIAGNOSTIC(SUSPICIOUS_FMT, WARNING, SYNTAX, 262, \"suspicious-formatting\", \"Suspicious code formatting.\"), \\\n  DEF_DIAGNOSTIC(EGYPT_BRACES, WARNING, SYNTAX, 263, \"egyptian-braces\", \"Indentation style: 'egyptian braces' required.\"), \\\n  DEF_DIAGNOSTIC(PLUS_STRING, WARNING, SEMA, 264, \"plus-string\", \"Usage of '+' for string concatenation.\"), \\\n  DEF_DIAGNOSTIC(FORGOTTEN_DO, WARNING, SEMA, 266, \"forgotten-do\", \"'while' after the statement list (forgot 'do' ?)\"), \\\n  DEF_DIAGNOSTIC(SUSPICIOUS_BRACKET, WARNING, SYNTAX, 267, \"suspicious-bracket\", \"'%s' will be parsed as '%s' (forgot ',' ?)\"), \\\n  DEF_DIAGNOSTIC(MIXED_SEPARATORS, WARNING, SYNTAX, 269, \"mixed-separators\", \"Mixed spaces and commas to separate %s.\"), \\\n  DEF_DIAGNOSTIC(EXTEND_TO_APPEND, HINT, SEMA, 270, \"extent-to-append\", \"It is better to use 'append(A, B, ...)' instead of 'extend([A, B, ...])'.\"), \\\n  DEF_DIAGNOSTIC(FORGOT_SUBST, WARNING, SEMA, 271, \"forgot-subst\", \"'{}' found inside string (forgot 'subst' or '$' ?).\"), \\\n  DEF_DIAGNOSTIC(NOT_UNARY_OP, WARNING, SYNTAX, 272, \"not-unary-op\", \"This '%s' is not a unary operator. Please use ' ' after it or ',' before it for better understandability.\"), \\\n  DEF_DIAGNOSTIC(MISSED_BREAK, WARNING, SEMA, 275, \"missed-break\", \"A 'break' statement is probably missing in a 'switch' statement.\"), \\\n  DEF_DIAGNOSTIC(SPACE_AT_EOL, WARNING, LEX, 277, \"space-at-eol\", \"Whitespace at the end of line.\"), \\\n  DEF_DIAGNOSTIC(FORBIDDEN_FUNC, WARNING, SEMA, 278, \"forbidden-function\", \"It is forbidden to call '%s' function.\"), \\\n  DEF_DIAGNOSTIC(MISMATCH_LOOP_VAR, WARNING, SEMA, 279, \"mismatch-loop-variable\", \"The variable used in for-loop does not match the initialized one.\"), \\\n  DEF_DIAGNOSTIC(FORBIDDEN_PARENT_DIR, WARNING, SEMA, 280, \"forbidden-parent-dir\", \"Access to the parent directory is forbidden in this function.\"), \\\n  DEF_DIAGNOSTIC(UNWANTED_MODIFICATION, WARNING, SEMA, 281, \"unwanted-modification\", \"Function '%s' modifies the object. You probably didn't want to modify the object here.\"), \\\n  DEF_DIAGNOSTIC(USELESS_NULLC, WARNING, SEMA, 283, \"useless-null-coalescing\", \"The expression to the right of the '??\"\"' is null.\"), \\\n  DEF_DIAGNOSTIC(CAN_BE_SIMPLIFIED, WARNING, SEMA, 284, \"can-be-simplified\", \"Expression can be simplified.\"), \\\n  DEF_DIAGNOSTIC(EXPR_NOT_NULL, WARNING, SEMA, 285, \"expr-cannot-be-null\", \"The expression to the left of the '%s' cannot be null.\"), \\\n  DEF_DIAGNOSTIC(DECL_IN_EXPR, WARNING, SEMA, 286, \"decl-in-expression\", \"Declaration used in arith expression as operand.\"), \\\n  DEF_DIAGNOSTIC(RANGE_CHECK, WARNING, SEMA, 287, \"range-check\", \"It looks like the range boundaries are not checked correctly. Pay attention to checking with minimum and maximum index.\"), \\\n  DEF_DIAGNOSTIC(PARAM_COUNT_MISMATCH, WARNING, SEMA, 288, \"param-count\", \"Function '%s' (%d..%d parameters) is called with the wrong number of arguments (%d).\"),\\\n  DEF_DIAGNOSTIC(PARAM_POSITION_MISMATCH, WARNING, SEMA, 289, \"param-pos\", \"The function parameter '%s' seems to be in the wrong position.\"), \\\n  DEF_DIAGNOSTIC(INVALID_UNDERSCORE, WARNING, SEMA, 291, \"invalid-underscore\", \"The name of %s '%s' is invalid. The identifier is marked as unused with a prefix underscore, but it is used.\"), \\\n  DEF_DIAGNOSTIC(MODIFIED_CONTAINER, WARNING, SEMA, 292, \"modified-container\", \"The container was modified within the loop.\"), \\\n  DEF_DIAGNOSTIC(DUPLICATE_PERSIST_ID, WARNING, SEMA, 293, \"duplicate-persist-id\", \"Duplicate id '%s' passed to 'persist'.\"), \\\n  DEF_DIAGNOSTIC(UNDEFINED_GLOBAL, WARNING, SEMA, 295, \"undefined-global\", \"Undefined global identifier '%s'.\"), \\\n  DEF_DIAGNOSTIC(CALL_FROM_ROOT, WARNING, SEMA, 297, \"call-from-root\", \"Function '%s' must be called from the root scope.\"), \\\n  DEF_DIAGNOSTIC(INTEGER_OVERFLOW, WARNING, SEMA, 304, \"integer-overflow\", \"Integer Overflow.\"), \\\n  DEF_DIAGNOSTIC(RELATIVE_CMP_BOOL, WARNING, SEMA, 305, \"relative-bool-cmp\", \"Relative comparison of non-boolean with boolean. It is a potential runtime error.\"), \\\n  DEF_DIAGNOSTIC(EQ_PAREN_MISSED, WARNING, SEMA, 306, \"eq-paren-miss\", \"Suspicious expression, probably parens are missing.\"), \\\n  DEF_DIAGNOSTIC(GLOBAL_NAME_REDEF, WARNING, SEMA, 307, \"global-id-redef\", \"Redefinition of existing global name '%s'.\"), \\\n  DEF_DIAGNOSTIC(BOOL_LAMBDA_REQUIRED, WARNING, SEMA, 308, \"bool-lambda-required\", \"Function '%s' requires lambda which returns boolean.\"), \\\n  DEF_DIAGNOSTIC(MISSING_DESTRUCTURED_VALUE, WARNING, SEMA, 309, \"missing-destructured-value\", \"No value for '%s' in destructured declaration.\"), \\\n  DEF_DIAGNOSTIC(DESTRUCTURED_TYPE_MISMATCH, WARNING, SEMA, 310, \"destructured-type\", \"Destructured type mismatch, right side is %s.\"), \\\n  DEF_DIAGNOSTIC(WRONG_TYPE, WARNING, SEMA, 311, \"wrong-type\", \"Wrong type: expected %s, got %s.\"), \\\n  DEF_DIAGNOSTIC(MISSING_FIELD, WARNING, SEMA, 312, \"missing-field\", \"No field '%s' in %s.\"), \\\n  DEF_DIAGNOSTIC(MISSING_MODULE, HINT, SEMA, 313, \"missing-module\", \"Module '%s' not found, or it returns null.\"), \\\n  DEF_DIAGNOSTIC(SEE_OTHER, HINT, SEMA, 314, \"see-other\", \"You can find %s here.\"), \\\n  DEF_DIAGNOSTIC(INVALID_INDENTATION, WARNING, SYNTAX, 315, \"invalid-indentation\", \"Invalid indentation. Pay attention to lines %s and %s.\"), \\\n  DEF_DIAGNOSTIC(NOT_A_CONST, WARNING, COMPILETIME, 316, \"not-a-const\", \"Expression in 'static' context must be a constant expression.\"), \\\n  DEF_DIAGNOSTIC(STATIC_MEMO_TOO_SIMPLE, WARNING, COMPILETIME, 317, \"static-too-simple\", \"'static' is too simple.\"), \\\n  DEF_DIAGNOSTIC(MERGE_EMPTY_TABLE, WARNING, SEMA, 318, \"merge-empty-table\", \"'__merge({})' with an empty table is equivalent to 'clone'. Use 'clone' instead.\"), \\\n  DEF_DIAGNOSTIC(EMPTY_ARRAY_RESIZE, WARNING, SEMA, 319, \"empty-array-resize\", \"'[].resize(...)' is slower than 'array(...)'. Use 'array(...)' instead.\"), \\\n  DEF_DIAGNOSTIC(CALLBACK_SHOULD_RETURN_VALUE, WARNING, SEMA, 320, \"callback-should-return-value\", \"Callback passed to '%s' must return a value.\"), \\\n  DEF_DIAGNOSTIC(PARAM_ASSIGNMENT_IN_LAMBDA, WARNING, SEMA, 321, \"param-assign-in-lambda\", \"Assignment to parameter '%s' in lambda has no effect. Return the expression instead.\"), \\\n  DEF_DIAGNOSTIC(CALLBACK_SHOULD_NOT_RETURN, WARNING, SEMA, 322, \"callback-should-not-return\", \"Callback passed to '%s' should not return a value.\") \\\n\n\nnamespace SQCompilation {\n\nstruct CompilerError {}; // Exception to throw\n\nenum DiagnosticsId {\n#define DEF_DIAGNOSTIC(id, _, __, ___, _____, ______) DI_##id\n  DIAGNOSTICS,\n#undef DEF_DIAGNOSTIC\n  DI_NUM_OF_DIAGNOSTICS\n};\n\nenum DiagnosticSeverity {\n  DS_HINT,\n  DS_WARNING,\n  DS_ERROR\n};\n\nenum CommentKind {\n  CK_NONE,\n  CK_LINE,    // | // foo bar\n  CK_BLOCK,   // | /* foo bar */\n  CK_ML_BLOCK // | /* foo \\n bar */\n};\n\nstruct CommentData {\n\n  CommentData() : kind(CK_NONE), size(0), text(nullptr), commentLine(-1), begin(-1), end(-1) {}\n  CommentData(enum CommentKind k, size_t s, const char *t, SQInteger n, SQInteger b, SQInteger e) : kind(k), size(s), text(t), commentLine(n), begin(b), end(e) {}\n\n  const enum CommentKind kind;\n  const size_t size;\n  const char *text;\n\n  const SQInteger commentLine; // stand for line number in multiline block comment, or 0 otherwise\n  const SQInteger begin, end;\n\n  bool isLineComment() const { return kind == CK_LINE; }\n  bool isBlockComment() const { return kind == CK_BLOCK; }\n  bool isMultiLineComment() const { return kind == CK_ML_BLOCK; }\n};\n\nclass Comments {\npublic:\n  using LineCommentsList = sqvector<CommentData>;\n\n  Comments(SQAllocContext ctx) : _commentsList(ctx), emptyComments(ctx) {}\n  ~Comments();\n\n  const LineCommentsList &lineComment(int line) const;\n\n  sqvector<LineCommentsList> &commentsList() { return _commentsList; }\n  const sqvector<LineCommentsList> &commentsList() const { return _commentsList; }\n\n  void pushNewLine() { _commentsList.push_back(LineCommentsList(_commentsList._alloc_ctx)); }\n\nprivate:\n  sqvector<LineCommentsList> _commentsList;\n  LineCommentsList emptyComments;\n};\n\nclass SQCompilationContext\n{\npublic:\n  SQCompilationContext(SQVM *vm, Arena *a, const char *sn, const char *code, size_t csize, const Comments *comments, bool raiseError);\n  ~SQCompilationContext();\n\n  const char *sourceName() const { return _sourceName; }\n\n  SQAllocContext allocContext() const { return _ss(_vm)->_alloc_ctx; }\n  SQVM *getVm() const { return _vm; }\n\n  static void vrenderDiagnosticHeader(enum DiagnosticsId diag, std::string &msg, va_list args);\n  static void renderDiagnosticHeader(enum DiagnosticsId diag, std::string *msg, ...);\n  void vreportDiagnostic(enum DiagnosticsId diag, int32_t line, int32_t pos, int32_t width, va_list args);\n  void reportDiagnostic(enum DiagnosticsId diag, int32_t line, int32_t pos, int32_t width, ...);\n  bool isDisabled(enum DiagnosticsId id, int line, int pos);\n  bool isRequireDisabled(int line, int col);\n\n  static void printAllWarnings(FILE *ostream);\n  static bool enableWarning(const char *diagName, bool state);\n  static bool enableWarning(int32_t id, bool state);\n  static void switchSyntaxWarningsState(bool state);\n\n  Arena *arena() const { return _arena; }\n\nprivate:\n\n\n  void buildLineMap();\n\n  const char *findLine(int lineNo);\n  bool isBlankLine(const char *l);\n\n  const char *_sourceName;\n\n  SQVM *_vm;\n\n  const char *_code;\n  size_t _codeSize;\n\n  Arena *_arena;\n\n  bool _raiseError;\n\n  sqvector<int> _linemap;\n  const Comments *_comments;\n};\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/compiler.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include <stdarg.h>\n#include <algorithm>\n#include \"opcodes.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"compiler.h\"\n#include \"sqfuncstate.h\"\n#include \"optimizer.h\"\n#include \"lexer.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"ast.h\"\n#include \"parser.h\"\n#include \"codegen.h\"\n#include \"sqtypeparser.h\"\n#include \"optimizations/closureHoisting.h\"\n#include \"compilationcontext.h\"\n#include \"static_analyzer/analyzer.h\"\n\n\nnamespace SQCompilation {\n\nstatic RootBlock *parseASTImpl(Arena *astArena, SQVM *vm, const char *sourceText, size_t sourceTextSize, const char *sourcename, Comments *comments, bool raiseerror) {\n  Arena parseArena(_ss(vm)->_alloc_ctx, \"Parser\");\n  SQCompilationContext ctx(vm, &parseArena, sourcename, sourceText, sourceTextSize, comments, raiseerror);\n  SQParser p(vm, sourceText, sourceTextSize, sourcename, astArena, ctx, comments);\n\n  RootBlock *r = p.parse();\n\n  if (r) {\n    ClosureHoistingOpt opt(_ss(vm), astArena);\n    opt.run(r);\n  }\n\n  return r;\n}\n\nSqASTData *ParseToAST(SQVM *vm, const char *sourceText, size_t sourceTextSize, const char *sourcename, bool preserveComments, bool raiseerror) {\n\n    SqASTData *astData = sq_allocateASTData(vm);\n\n    if (sourcename) {\n        strncpy(astData->sourceName, sourcename, sizeof(astData->sourceName));\n        astData->sourceName[sizeof(astData->sourceName) / sizeof(astData->sourceName[0]) - 1] = 0;\n    }\n\n    astData->root = parseASTImpl(astData->astArena, vm, sourceText, sourceTextSize, astData->sourceName, preserveComments ? astData->comments : nullptr, raiseerror);\n    if (astData->root)\n        return astData;\n\n    sq_releaseASTData(vm, astData);\n    return nullptr;\n}\n\nbool Compile(SQVM *vm, const char *sourceText, size_t sourceTextSize, const HSQOBJECT *bindings, const char *sourcename, SQObjectPtr &out, bool raiseerror)\n{\n    Arena astArena(_ss(vm)->_alloc_ctx, \"AST\");\n\n    RootBlock *r = parseASTImpl(&astArena, vm, sourceText, sourceTextSize, sourcename, nullptr, raiseerror);\n\n    if (!r)\n      return false;\n\n    Arena cgArena(_ss(vm)->_alloc_ctx, \"Codegen\");\n    SQCompilationContext ctx(vm, &cgArena, sourcename, sourceText, sourceTextSize, nullptr, raiseerror);\n    CodeGenVisitor codegen(&cgArena, bindings, vm, sourcename, ctx);\n\n    return codegen.generate(r, out);\n}\n\nstatic bool TranslateASTToBytecodeImpl(SQVM *vm, RootBlock *ast, const HSQOBJECT *bindings, const char *sourcename, const char *sourceText, size_t sourceTextSize, SQObjectPtr &out, const Comments *comments, bool raiseerror)\n{\n    Arena cgArena(_ss(vm)->_alloc_ctx, \"Codegen\");\n    SQCompilationContext ctx(vm, &cgArena, sourcename, sourceText, sourceTextSize, comments, raiseerror);\n    CodeGenVisitor codegen(&cgArena, bindings, vm, sourcename, ctx);\n\n    return codegen.generate(ast, out);\n}\n\nbool TranslateASTToBytecode(SQVM *vm, SqASTData *astData, const HSQOBJECT *bindings, const char *sourceText, size_t sourceTextSize, SQObjectPtr &out, bool raiseerror)\n{\n    return TranslateASTToBytecodeImpl(vm, astData->root, bindings, astData->sourceName, sourceText, sourceTextSize, out, astData->comments, raiseerror);\n}\n\nvoid AnalyzeCode(SQVM *vm, SqASTData *astData, const HSQOBJECT *bindings, const char *sourceText, size_t sourceTextSize)\n{\n    Arena saArena(_ss(vm)->_alloc_ctx, \"Analyzer\");\n    SQCompilationContext ctx(vm, &saArena, astData->sourceName, sourceText, sourceTextSize, astData->comments, true);\n\n    RootBlock *ast = astData->root;\n    StaticAnalyzer sa(ctx);\n\n    sa.runAnalysis(ast, bindings);\n}\n\nbool AstGetImports(HSQUIRRELVM v, SQCompilation::SqASTData *astData, SQInteger *num, SQModuleImport **imports)\n{\n    if (!astData || !astData->root || !num || !imports)\n        return false;\n\n    const ArenaVector<Statement *> &stmts = astData->root->statements();\n    size_t importCount = 0;\n    for (size_t i = 0; i < stmts.size(); i++) {\n        TreeOp op = stmts[i]->op();\n        if (op == TO_IMPORT)\n            importCount++;\n          else if (op != TO_DIRECTIVE)\n            break;\n    }\n\n    if (importCount == 0) {\n        *num = 0;\n        *imports = nullptr;\n        return true;\n    }\n\n    SQModuleImport *importArrayOut = (SQModuleImport *)sq_vm_malloc(_ss(v)->_alloc_ctx, sizeof(SQModuleImport) * importCount);\n    memset(importArrayOut, 0, sizeof(SQModuleImport) * importCount);\n\n    size_t importIdx = 0;\n    for (size_t i = 0; i < stmts.size(); i++) {\n        if (stmts[i]->op() == TO_DIRECTIVE)\n            continue;\n        if (stmts[i]->op() != TO_IMPORT)\n            break;\n\n        ImportStmt *importStmt = static_cast<ImportStmt *>(stmts[i]);\n        size_t numSlots = importStmt->slots.size();\n\n        SQModuleImport &imp =  importArrayOut[importIdx];\n        imp.name = importStmt->moduleName;\n        imp.alias = importStmt->moduleAlias;\n        imp.numSlots = (int)numSlots;\n        imp.slots = numSlots ? importStmt->slots.begin() : nullptr;\n        imp.line = importStmt->lineStart();\n        imp.nameColumn = importStmt->nameCol;\n        imp.aliasColumn = importStmt->aliasCol;\n\n        importIdx++;\n    }\n\n    *num = (SQInteger)importCount;\n    *imports = importArrayOut;\n\n    return true;\n}\n\nvoid AstFreeImports(HSQUIRRELVM v, SQInteger num, SQModuleImport *imports)\n{\n    if (!imports || num <= 0)\n        return;\n\n    sq_vm_free(_ss(v)->_alloc_ctx, imports, sizeof(SQModuleImport) * num);\n}\n\n}; // SQCompilation\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/compiler.h",
    "content": "/*  see copyright notice in squirrel.h */\n#pragma once\n\nstruct SQVM;\nclass OutputStream;\nclass Arena;\n\nnamespace SQCompilation\n{\n\nclass RootBlock;\nclass Comments;\n\nstruct SqASTData {\n  Arena *astArena;\n  RootBlock *root;\n  char sourceName[256];\n  Comments *comments;\n};\n\n\ntypedef void(*CompilerErrorFunc)(void *ud, const char *s);\nbool Compile(SQVM *vm, const char *sourceText, size_t sourceTextSize, const HSQOBJECT *bindings, const char *sourcename, SQObjectPtr &out, bool raiseerror);\n\nSqASTData *ParseToAST(SQVM *vm, const char *sourceText, size_t sourceTextSize, const char *sourcename, bool preserveComments, bool raiseerror);\nbool TranslateASTToBytecode(SQVM *vm, SqASTData *astData, const HSQOBJECT *bindings, const char *sourceText, size_t sourceTextSize, SQObjectPtr &out, bool raiseerror);\nvoid AnalyzeCode(SQVM *vm, SqASTData *astData, const HSQOBJECT *bindings, const char *sourceText, size_t sourceTextSize);\nbool AstGetImports(HSQUIRRELVM v, SQCompilation::SqASTData *astData, SQInteger *num, SQModuleImport **imports);\nvoid AstFreeImports(HSQUIRRELVM v, SQInteger num, SQModuleImport *imports);\n\n}; // SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/constgen.cpp",
    "content": "#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include <stdarg.h>\n#include \"opcodes.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqfuncstate.h\"\n#include \"codegen.h\"\n#include \"constgen.h\"\n#include \"sqvm.h\"\n#include \"optimizer.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqclass.h\"\n\nnamespace SQCompilation {\n\nvoid ConstGenVisitor::throwUnsupported(Node *n, const char *type)\n{\n    _ctx.reportDiagnostic(DiagnosticsId::DI_NOT_ALLOWED_IN_CONST, n->lineStart(), n->columnStart(), n->textWidth(), type);\n}\n\nvoid ConstGenVisitor::throwGeneralError(Node *n, const char *msg)\n{\n    _ctx.reportDiagnostic(DiagnosticsId::DI_GENERAL_COMPILE_ERROR, n->lineStart(), n->columnStart(), n->textWidth(), msg);\n}\n\nvoid ConstGenVisitor::throwGeneralErrorFmt(Node *n, const char *fmt, ...)\n{\n    char buf[256];\n    va_list args;\n    va_start(args, fmt);\n    vsnprintf(buf, sizeof(buf), fmt, args);\n    va_end(args);\n    _ctx.reportDiagnostic(DiagnosticsId::DI_GENERAL_COMPILE_ERROR, n->lineStart(), n->columnStart(), n->textWidth(), buf);\n}\n\nvoid ConstGenVisitor::process(Expr *expr, SQObjectPtr &out)\n{\n    assert(sq_type(_result) == OT_NULL);\n    expr->visit(this);\n    out = _result;\n}\n\nSQObjectPtr ConstGenVisitor::convertLiteral(LiteralExpr *lit)\n{\n    SQObjectPtr ret{};\n    switch (lit->kind()) {\n    case LK_STRING: return _fs->CreateString(lit->s());\n    case LK_FLOAT: ret._type = OT_FLOAT; ret._unVal.fFloat = lit->f(); break;\n    case LK_INT:  ret._type = OT_INTEGER; ret._unVal.nInteger = lit->i(); break;\n    case LK_BOOL: ret._type = OT_BOOL; ret._unVal.nInteger = lit->b() ? 1 : 0; break;\n    case LK_NULL: ret._type = OT_NULL; ret._unVal.raw = 0; break;\n    }\n    return ret;\n}\n\nvoid ConstGenVisitor::visitLiteralExpr(LiteralExpr *expr)\n{\n    _result = convertLiteral(expr);\n    _call_target.Null();\n}\n\nvoid ConstGenVisitor::visitArrayExpr(ArrayExpr *expr)\n{\n    SQArray *arr = SQArray::Create(_ss(_vm), expr->initializers().size());\n\n    for (SQUnsignedInteger i = 0; i < expr->initializers().size(); ++i) {\n        Expr *valExpr = expr->initializers()[i];\n        valExpr->visit(this);\n        arr->Set(i, _result);\n    }\n\n    _result = SQObjectPtr(arr);\n    _result._flags = SQOBJ_FLAG_IMMUTABLE;\n\n    _call_target.Null();\n}\n\nvoid ConstGenVisitor::visitTableExpr(TableExpr *tblExpr)\n{\n    SQTable *table = SQTable::Create(_ss(_vm), tblExpr->members().size());\n\n    const auto &members = tblExpr->members();\n    for (SQUnsignedInteger i = 0; i < members.size(); ++i) {\n        const TableMember &m = members[i];\n\n        m.key->visit(this);\n        SQObjectPtr key(_result);\n\n        m.value->visit(this);\n        SQObjectPtr value(_result);\n\n        table->NewSlot(key, value);\n    }\n\n    _result = SQObjectPtr(table);\n    _result._flags = SQOBJ_FLAG_IMMUTABLE;\n\n    _call_target.Null();\n}\n\n\nvoid ConstGenVisitor::visitId(Id *id)\n{\n    SQObjectPtr idObj = _fs->CreateString(id->name());\n    SQObjectPtr constant;\n    if (_codegen.IsConstant(idObj, constant)) {\n        _result = constant;\n    } else {\n        _ctx.reportDiagnostic(DiagnosticsId::DI_ID_IS_NOT_CONST,\n            id->lineStart(), id->columnStart(), id->textWidth(),\n            _stringval(idObj));\n    }\n\n    _call_target.Null();\n}\n\n\nvoid ConstGenVisitor::visitCallExpr(CallExpr *expr)\n{\n    if (expr->isNullable()) {\n        throwGeneralError(expr, \"Nullable calls are not supported in constant expressions\");\n        return;\n    }\n\n    ConstGenVisitor funcEval(_vm, _fs, _ctx, _codegen);\n\n    expr->callee()->visit(&funcEval);\n    SQObjectPtr func = funcEval._result;\n\n    if (!sq_is_pure_function(&func))\n        throwGeneralError(expr, \"Only calls to pure functions are allowed in constant expressions\");\n\n    sqvector<SQObjectPtr> argValues(nullptr);\n    argValues.reserve(expr->arguments().size());\n\n    auto &argExprs = expr->arguments();\n\n    for (SQUnsignedInteger i = 0; i < argExprs.size(); ++i) {\n        ConstGenVisitor argEval(_vm, _fs, _ctx, _codegen);\n        argExprs[i]->visit(&argEval);\n        argValues.push_back(argEval._result);\n    }\n\n    SQInteger prevTop = sq_gettop(_vm);\n\n    sq_pushobject(_vm, func);\n    sq_pushobject(_vm, funcEval._call_target);\n    for (SQUnsignedInteger i = 0; i < argValues.size(); ++i) {\n        sq_pushobject(_vm, argValues[i]);\n    }\n    if (SQ_FAILED(sq_call(_vm, 1 + argValues.size(), SQTrue, SQTrue))) {\n        sq_settop(_vm, prevTop);\n        throwGeneralError(expr, \"Failed to evaluate constant initializer call\");\n    }\n\n    HSQOBJECT callRes;\n    sq_getstackobj(_vm, -1, &callRes);\n    callRes._flags = SQOBJ_FLAG_IMMUTABLE;\n    _result = SQObjectPtr(callRes);\n\n    _call_target.Null();\n\n    sq_settop(_vm, prevTop);\n}\n\n\nvoid ConstGenVisitor::visitGetFieldExpr(GetFieldExpr *expr)\n{\n    expr->visitChildren(this);\n    SQObjectPtr container(_result);\n    _call_target = container;\n\n    SQObjectPtr slotName = _fs->CreateString(expr->fieldName());\n\n    SQInteger prevTop = sq_gettop(_vm);\n    sq_pushobject(_vm, container);\n    sq_pushobject(_vm, slotName);\n    bool hasSlot = SQ_SUCCEEDED(sq_get(_vm, -2));\n    if (hasSlot) {\n        HSQOBJECT value;\n        sq_getstackobj(_vm, -1, &value);\n        value._flags = SQOBJ_FLAG_IMMUTABLE;\n        _result = SQObjectPtr(value);\n    }\n    else if (expr->isNullable()) {\n        if (!sq_isnull(_vm->_lasterror)) {\n            SQObjectPtr err = _vm->_lasterror;\n            sq_reseterror(_vm);\n            sq_settop(_vm, prevTop);\n            throwGeneralErrorFmt(expr, \"error in get operation: %s\",\n                sq_isstring(err) ? _stringval(err) : \"<unknown>\");\n        }\n        _result.Null();\n    }\n    else {\n        sq_settop(_vm, prevTop);\n        _ctx.reportDiagnostic(DiagnosticsId::DI_CONSTANT_FIELD_NOT_FOUND,\n            expr->lineStart(), expr->columnStart(), expr->textWidth(),\n            _stringval(slotName));\n    }\n\n    sq_settop(_vm, prevTop);\n}\n\n\nvoid ConstGenVisitor::visitGetSlotExpr(GetSlotExpr *expr)\n{\n    expr->receiver()->visit(this);\n    SQObjectPtr container(_result);\n    _call_target = container;\n\n    expr->key()->visit(this);\n    SQObjectPtr key(_result);\n\n    SQInteger prevTop = sq_gettop(_vm);\n    sq_pushobject(_vm, container);\n    sq_pushobject(_vm, key);\n    bool hasSlot = SQ_SUCCEEDED(sq_get(_vm, -2));\n    if (hasSlot) {\n        HSQOBJECT value;\n        sq_getstackobj(_vm, -1, &value);\n        value._flags = SQOBJ_FLAG_IMMUTABLE;\n        _result = SQObjectPtr(value);\n    }\n    else if (expr->isNullable()) {\n        if (!sq_isnull(_vm->_lasterror)) {\n            SQObjectPtr err = _vm->_lasterror;\n            sq_reseterror(_vm);\n            sq_settop(_vm, prevTop);\n            throwGeneralErrorFmt(expr, \"error in get operation: %s\",\n                sq_isstring(err) ? _stringval(err) : \"<unknown>\");\n        }\n        _result.Null();\n    }\n    else {\n        SQObjectPtr keyAsString;\n        sq_pushobject(_vm, key);\n        if (SQ_SUCCEEDED(sq_tostring(_vm, -1))) {\n            SQObject t;\n            sq_getstackobj(_vm, -1, &t);\n            keyAsString = t;\n        } else {\n            keyAsString = _fs->CreateString(\"<???>\", 5);\n        }\n\n        sq_settop(_vm, prevTop);\n\n        Expr *errNode = expr->key();\n        _ctx.reportDiagnostic(DiagnosticsId::DI_CONSTANT_SLOT_NOT_FOUND,\n            errNode->lineStart(), errNode->columnStart(), errNode->textWidth(),\n            IdType2Name(sq_type(key)), _stringval(keyAsString));\n    }\n    sq_settop(_vm, prevTop);\n}\n\n\nvoid ConstGenVisitor::visitUnExpr(UnExpr *unary)\n{\n    sq_reseterror(_vm);\n    _call_target.Null();\n\n    switch (unary->op())\n    {\n    case TO_NEG:\n        unary->argument()->visit(this);\n        if (!_vm->NEG_OP(_result, _result)) {\n            SQObjectPtr err = _vm->_lasterror;\n            sq_reseterror(_vm);\n            throwGeneralError(unary->argument(),\n                sq_isstring(err) ? _stringval(err) : \"negation failed\");\n        }\n        break;\n    case TO_NOT:\n        unary->argument()->visit(this);\n        _result = SQObjectPtr(_vm->IsFalse(_result));\n        break;\n    case TO_BNOT:\n        unary->argument()->visit(this);\n        if(sq_type(_result) != OT_INTEGER)\n            throwGeneralError(unary->argument(), \"attempt to perform a bitwise op on a non-integer\");\n\n        _result = SQObjectPtr(~(_integer(_result)));\n        break;\n    case TO_TYPEOF:\n        unary->argument()->visit(this);\n        if (!_vm->TypeOf(_result, _result))\n            throwGeneralError(unary->argument(), \"typeof call failed\");\n        break;\n    case TO_INLINE_CONST:\n    case TO_PAREN:\n        // bypass\n        unary->argument()->visit(this);\n        break;\n    default:\n        throwUnsupported(unary, \"this unary expression\");\n    }\n}\n\nvoid ConstGenVisitor::visitBinExpr(BinExpr *expr)\n{\n    sq_reseterror(_vm);\n    _call_target.Null();\n\n    switch (expr->op()) {\n        case TO_NEWSLOT:\n            throwUnsupported(expr, \"new slot expression\");\n        case TO_ASSIGN:\n            throwUnsupported(expr, \"assignment expression\");\n        case TO_PLUSEQ:\n        case TO_MINUSEQ:\n        case TO_MULEQ:\n        case TO_DIVEQ:\n        case TO_MODEQ:\n            throwUnsupported(expr, \"compound arithmetic expression\");\n        default:\n            break;\n    }\n\n    expr->lhs()->visit(this);\n    SQObjectPtr lhs(_result);\n\n    expr->rhs()->visit(this);\n    SQObjectPtr rhs(_result);\n\n    assert(sq_isnull(_vm->_lasterror) && \"Error thrown while evaluating binary expression operands\");\n\n    bool ok = true;\n\n    switch (expr->op()) {\n        case TO_NULLC:\n            _result = sq_isnull(lhs) ? rhs : lhs;\n            break;\n        case TO_OROR:\n            _result = SQVM::IsFalse(lhs) ? rhs : lhs;\n            break;\n        case TO_ANDAND:\n            _result = SQVM::IsFalse(lhs) ? lhs : rhs;\n            break;\n        case TO_ADD:\n            ok = _vm->ARITH_OP('+', _result, lhs, rhs);\n            break;\n        case TO_SUB:\n            ok = _vm->ARITH_OP('-', _result, lhs, rhs);\n            break;\n        case TO_MUL:\n            ok = _vm->ARITH_OP('*', _result, lhs, rhs);\n            break;\n        case TO_DIV:\n            ok = _vm->ARITH_OP('/', _result, lhs, rhs);\n            break;\n        case TO_MOD:\n            ok = _vm->ARITH_OP('%', _result, lhs, rhs);\n            break;\n        case TO_OR:\n            ok = _vm->BW_OP(BW_OR, _result, lhs, rhs);\n            break;\n        case TO_AND:\n            ok = _vm->BW_OP(BW_AND, _result, lhs, rhs);\n            break;\n        case TO_XOR:\n            ok = _vm->BW_OP(BW_XOR, _result, lhs, rhs);\n            break;\n        case TO_USHR:\n            ok = _vm->BW_OP(BW_USHIFTR, _result, lhs, rhs);\n            break;\n        case TO_SHR:\n            ok = _vm->BW_OP(BW_SHIFTR, _result, lhs, rhs);\n            break;\n        case TO_SHL:\n            ok = _vm->BW_OP(BW_SHIFTL, _result, lhs, rhs);\n            break;\n\n        case TO_EQ:\n            _result = SQObjectPtr(_vm->IsEqual(lhs, rhs));\n            break;\n        case TO_NE:\n            _result = SQObjectPtr(!_vm->IsEqual(lhs, rhs));\n            break;\n\n        case TO_GE:\n            ok = _vm->CMP_OP(CMP_GE, lhs, rhs, _result);\n            break;\n        case TO_GT:\n            ok = _vm->CMP_OP(CMP_G, lhs, rhs, _result);\n            break;\n        case TO_LE:\n            ok = _vm->CMP_OP(CMP_LE, lhs, rhs, _result);\n            break;\n        case TO_LT:\n            ok = _vm->CMP_OP(CMP_L, lhs, rhs, _result);\n            break;\n        case TO_3CMP:\n            ok = _vm->CMP_OP(CMP_3W, lhs, rhs, _result);\n            break;\n\n        case TO_IN: {\n            SQObjectPtr tmpVal;\n            bool exists = _vm->Get(rhs, lhs, tmpVal, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_NO_TYPE_METHODS);\n            _result = SQObjectPtr(exists);\n            if (!sq_isnull(_vm->_lasterror)) { // handle errors that can happen in _get() metamethod\n                ok = false;\n                _vm->Raise_Error(\"Error while applying 'in' operator: %s\",\n                    sq_isstring(_vm->_lasterror) ? _stringval(_vm->_lasterror) : \"<unknown>\");\n            }\n            break;\n        }\n        case TO_INSTANCEOF: {\n            if (sq_type(rhs) != OT_CLASS)\n                throwGeneralError(expr->rhs(), \"checking instance with non-class\");\n            _result = SQObjectPtr(SQVM::IsInstanceOf(lhs, _class(rhs)));\n            break;\n        }\n        default:\n            assert(!\"Unknown binary expression\");\n            break;\n    }\n\n    assert(ok == sq_isnull(_vm->_lasterror));\n    if (!ok) {\n        SQObjectPtr err = _vm->_lasterror;\n        sq_reseterror(_vm);\n        throwGeneralError(expr, sq_isstring(err) ? _stringval(err) : \"internal error in binary operation\");\n    }\n}\n\n\nvoid ConstGenVisitor::visitTerExpr(TerExpr *expr)\n{\n    _call_target.Null();\n\n    expr->a()->visit(this);\n    Expr *resBranch = SQVM::IsFalse(_result) ? expr->c() : expr->b();\n    resBranch->visit(this);\n}\n\n\nvoid ConstGenVisitor::visitFunctionExpr(FunctionExpr *funcExpr)\n{\n    _call_target.Null();\n    _result = _codegen.compileConstFunc(funcExpr);\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/constgen.h",
    "content": "#pragma once\n\n#include \"ast.h\"\n#include \"opcodes.h\"\n#include \"compilationcontext.h\"\n#include <setjmp.h>\n\nstruct SQFuncState;\n\nnamespace SQCompilation {\n\nclass ConstGenVisitor : public Visitor {\nprivate:\n    SQCompilationContext &_ctx;\n    SQVM *_vm;\n    SQFuncState *_fs;\n    CodeGenVisitor &_codegen;\n\n    SQObjectPtr _result;\n    SQObjectPtr _call_target; //< must null it in every node visit and assign the container in get operations\n\npublic:\n    ConstGenVisitor(SQVM *vm, SQFuncState *fs, SQCompilationContext &ctx, CodeGenVisitor &codegen)\n        : _ctx(ctx), _fs(fs), _vm(vm), _codegen(codegen)\n    {\n    }\n\npublic:\n    virtual ~ConstGenVisitor() {}\n\n    void  process(Expr *expr, SQObjectPtr &out);\n\n    virtual void visitNode(Node *node) { node->visitChildren(this); }\n\n    virtual void visitExpr(Expr *expr) { visitNode(expr); }\n    virtual void visitUnExpr(UnExpr *expr);\n    virtual void visitBinExpr(BinExpr *expr);\n    virtual void visitTerExpr(TerExpr *expr);\n    virtual void visitCallExpr(CallExpr *expr);\n    virtual void visitId(Id *id);\n    virtual void visitAccessExpr(AccessExpr *expr) { throwUnsupported(expr, \"access expression\"); }\n    virtual void visitGetFieldExpr(GetFieldExpr *expr);\n    virtual void visitSetFieldExpr(SetFieldExpr *expr) { throwUnsupported(expr, \"set field expression\"); }\n    virtual void visitGetSlotExpr(GetSlotExpr *expr);\n    virtual void visitSetSlotExpr(SetSlotExpr *expr) { throwUnsupported(expr, \"set slot expression\"); }\n    virtual void visitBaseExpr(BaseExpr *expr) { throwUnsupported(expr, \"base expression\"); }\n    virtual void visitRootTableAccessExpr(RootTableAccessExpr *expr) { throwUnsupported(expr, \"root table access expression\"); }\n\n    virtual void visitLiteralExpr(LiteralExpr *expr);\n\n    virtual void visitIncExpr(IncExpr *expr) { throwUnsupported(expr, \"increment expression\"); }\n\n    virtual void visitArrayExpr(ArrayExpr *expr);\n    virtual void visitTableExpr(TableExpr *tbl);\n    virtual void visitClassExpr(ClassExpr *cls) { visitTableExpr(cls); }\n    virtual void visitFunctionExpr(FunctionExpr *f);\n\n    virtual void visitCommaExpr(CommaExpr *expr) { throwUnsupported(expr, \"comma expression\"); }\n    virtual void visitExternalValueExpr(ExternalValueExpr *expr) { throwUnsupported(expr, \"external value expression\"); }\n\n    virtual void visitStmt(Statement *stmt) { throwUnsupported(stmt, \"statement\"); }\n    virtual void visitBlock(Block *block) { throwUnsupported(block, \"block statement\"); }\n    virtual void visitIfStatement(IfStatement *ifstmt) { throwUnsupported(ifstmt, \"if statement\"); }\n    virtual void visitLoopStatement(LoopStatement *loop) { throwUnsupported(loop, \"loop statement\"); }\n    virtual void visitWhileStatement(WhileStatement *loop) { throwUnsupported(loop, \"while statement\"); }\n    virtual void visitDoWhileStatement(DoWhileStatement *loop) { throwUnsupported(loop, \"do-while statement\"); }\n    virtual void visitForStatement(ForStatement *loop) { throwUnsupported(loop, \"for statement\"); }\n    virtual void visitForeachStatement(ForeachStatement *loop) { throwUnsupported(loop, \"foreach statement\"); }\n    virtual void visitSwitchStatement(SwitchStatement *swtch) { throwUnsupported(swtch, \"switch statement\"); }\n    virtual void visitTryStatement(TryStatement *tr) { throwUnsupported(tr, \"try statement\"); }\n    virtual void visitTerminateStatement(TerminateStatement *term) { throwUnsupported(term, \"terminate statement\"); }\n    virtual void visitReturnStatement(ReturnStatement *ret) { throwUnsupported(ret, \"return statement\"); }\n    virtual void visitYieldStatement(YieldStatement *yld) { throwUnsupported(yld, \"yield statement\"); }\n    virtual void visitThrowStatement(ThrowStatement *thr) { throwUnsupported(thr, \"throw statement\"); }\n    virtual void visitJumpStatement(JumpStatement *jmp) { throwUnsupported(jmp, \"jump statement\"); }\n    virtual void visitBreakStatement(BreakStatement *jmp) { throwUnsupported(jmp, \"break statement\"); }\n    virtual void visitContinueStatement(ContinueStatement *jmp) { throwUnsupported(jmp, \"continue statement\"); }\n    virtual void visitExprStatement(ExprStatement *estmt) { throwUnsupported(estmt, \"expression statement\"); }\n    virtual void visitEmptyStatement(EmptyStatement *empty) { throwUnsupported(empty, \"empty statement\"); }\n\n    virtual void visitDecl(Decl *decl) { throwUnsupported(decl, \"declaration\"); }\n    virtual void visitValueDecl(ValueDecl *decl) { throwUnsupported(decl, \"value declaration\"); }\n    virtual void visitVarDecl(VarDecl *decl) { throwUnsupported(decl, \"variable declaration\"); }\n    virtual void visitParamDecl(ParamDecl *decl) { throwUnsupported(decl, \"parameter declaration\"); }\n    virtual void visitConstDecl(ConstDecl *cnst) { visitDecl(cnst); }\n    virtual void visitEnumDecl(EnumDecl *enm) { visitDecl(enm); }\n    virtual void visitDeclGroup(DeclGroup *grp) { visitDecl(grp); }\n    virtual void visitDestructuringDecl(DestructuringDecl  *destruct) { visitDecl(destruct); }\n\n    virtual void visitDirectiveStatement(DirectiveStmt *dir) { throwUnsupported(dir, \"directive statement\"); }\n\nprivate:\n    void throwUnsupported(Node *n, const char *type);\n    void throwGeneralError(Node *n, const char *msg);\n    void throwGeneralErrorFmt(Node *n, const char *fmt, ...);\n    SQObjectPtr convertLiteral(LiteralExpr *lit);\n};\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/lex_tokens.h",
    "content": "#pragma once\n\n#define TK_IDENTIFIER   258\n#define TK_STRING_LITERAL   259\n#define TK_INTEGER  260\n#define TK_FLOAT    261\n#define TK_BASE 262\n#define TK_DELETE   263\n#define TK_EQ   264\n#define TK_NE   265\n#define TK_LE   266\n#define TK_GE   267\n#define TK_SWITCH   268\n#define TK_ARROW    269\n#define TK_AND  270\n#define TK_OR   271\n#define TK_IF   272\n#define TK_ELSE 273\n#define TK_WHILE    274\n#define TK_BREAK    275\n#define TK_FOR  276\n#define TK_DO   277\n#define TK_NULL 278\n#define TK_FOREACH  279\n#define TK_IN   280\n#define TK_NEWSLOT  281\n#define TK_MODULO   282\n#define TK_LOCAL    283\n#define TK_CLONE    284\n#define TK_FUNCTION 285\n#define TK_RETURN   286\n#define TK_TYPEOF   287\n#define TK_UMINUS   288\n#define TK_PLUSEQ   289\n#define TK_MINUSEQ  290\n#define TK_CONTINUE 291\n#define TK_YIELD 292\n#define TK_TRY 293\n#define TK_CATCH 294\n#define TK_THROW 295\n#define TK_SHIFTL 296\n#define TK_SHIFTR 297\n#define TK_RESUME 298\n#define TK_DOUBLE_COLON 299\n#define TK_CASE 300\n#define TK_DEFAULT 301\n#define TK_THIS 302\n#define TK_PLUSPLUS 303\n#define TK_MINUSMINUS 304\n#define TK_3WAYSCMP 305\n#define TK_USHIFTR 306\n#define TK_CLASS 307\n#define TK_EXTENDS 308\n#define TK_CONSTRUCTOR 310\n#define TK_INSTANCEOF 311\n#define TK_VARPARAMS 312\n#define TK___LINE__ 313\n#define TK___FILE__ 314\n#define TK_TRUE 315\n#define TK_FALSE 316\n#define TK_MULEQ 317\n#define TK_DIVEQ 318\n#define TK_MODEQ 319\n//#define TK_ 320\n//#define TK_ 321\n#define TK_STATIC 322\n#define TK_ENUM 323\n#define TK_CONST 324\n#define TK_RESERVED_001 325\n#define TK_NULLGETSTR 326\n#define TK_NULLGETOBJ 327\n#define TK_NULLCOALESCE 328\n#define TK_NULLCALL 329\n//#define TK_ 330\n#define TK_GLOBAL 331\n#define TK_DIRECTIVE 332\n#define TK_READERMACRO 333\n#define TK_NOT 334\n//#define TK_ 335\n#define TK_LET 336\n#define TK_TEMPLATE_PREFIX 337\n#define TK_TEMPLATE_INFIX 338\n#define TK_TEMPLATE_SUFFIX 339\n#define TK_TEMPLATE_OP 340\n#define TK_TYPE_METHOD_GETSTR 341\n#define TK_NULLABLE_TYPE_METHOD_GETSTR 342\n#define TK_DOCSTRING 343\n#define TK_CODE_BLOCK_EXPR 344\n"
  },
  {
    "path": "squirrel/compiler/lexer.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include <stdlib.h>\n#include <float.h>\n#include \"sqtable.h\"\n#include \"sqstring.h\"\n#include \"lexer.h\"\n#include \"lex_tokens.h\"\n#include <sq_char_class.h>\n\n#define CUR_CHAR (_currdata)\n#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _prevflags = _flags; _flags = 0; _curtoken = t; return t;}\n#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB)\n#define NEXT() {Next();_currentcolumn++;}\n#define INIT_TEMP_STRING() { _longstr.resize(0);}\n#define APPEND_CHAR(c) { _longstr.push_back(c);}\n#define TERMINATE_BUFFER() {_longstr.push_back('\\0');}\n#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQObjectPtr(SQString::Create(_sharedstate, #key)), SQObjectPtr(SQInteger(id)))\n\nusing namespace SQCompilation;\n\nSQLexer::SQLexer(SQSharedState *ss, SQCompilationContext &ctx, Comments *comments)\n    : _sharedstate(ss)\n    , _longstr(ss->_alloc_ctx)\n    , _ctx(ctx)\n    , _comments(comments)\n    , _currentComment(ss->_alloc_ctx)\n{\n}\n\nSQLexer::~SQLexer()\n{\n    _keywords->Release();\n}\n\nusing CommentVec = sqvector<CommentData>;\n\nvoid SQLexer::Init(const char *sourceText, size_t sourceTextSize)\n{\n    _keywords = SQTable::Create(_sharedstate, 39);\n    ADD_KEYWORD(while, TK_WHILE);\n    ADD_KEYWORD(do, TK_DO);\n    ADD_KEYWORD(if, TK_IF);\n    ADD_KEYWORD(else, TK_ELSE);\n    ADD_KEYWORD(break, TK_BREAK);\n    ADD_KEYWORD(continue, TK_CONTINUE);\n    ADD_KEYWORD(return, TK_RETURN);\n    ADD_KEYWORD(null, TK_NULL);\n    ADD_KEYWORD(function, TK_FUNCTION);\n    ADD_KEYWORD(local, TK_LOCAL);\n    ADD_KEYWORD(for, TK_FOR);\n    ADD_KEYWORD(foreach, TK_FOREACH);\n    ADD_KEYWORD(in, TK_IN);\n    ADD_KEYWORD(typeof, TK_TYPEOF);\n    ADD_KEYWORD(base, TK_BASE);\n    ADD_KEYWORD(delete, TK_DELETE);\n    ADD_KEYWORD(try, TK_TRY);\n    ADD_KEYWORD(catch, TK_CATCH);\n    ADD_KEYWORD(throw, TK_THROW);\n    ADD_KEYWORD(clone, TK_CLONE);\n    ADD_KEYWORD(yield, TK_YIELD);\n    ADD_KEYWORD(resume, TK_RESUME);\n    ADD_KEYWORD(switch, TK_SWITCH);\n    ADD_KEYWORD(case, TK_CASE);\n    ADD_KEYWORD(default, TK_DEFAULT);\n    ADD_KEYWORD(this, TK_THIS);\n    ADD_KEYWORD(class,TK_CLASS);\n    ADD_KEYWORD(constructor,TK_CONSTRUCTOR);\n    ADD_KEYWORD(instanceof,TK_INSTANCEOF);\n    ADD_KEYWORD(true,TK_TRUE);\n    ADD_KEYWORD(false,TK_FALSE);\n    ADD_KEYWORD(static,TK_STATIC);\n    ADD_KEYWORD(enum,TK_ENUM);\n    ADD_KEYWORD(const,TK_CONST);\n    ADD_KEYWORD(__LINE__,TK___LINE__);\n    ADD_KEYWORD(__FILE__,TK___FILE__);\n    ADD_KEYWORD(global, TK_GLOBAL);\n    ADD_KEYWORD(not, TK_NOT);\n    ADD_KEYWORD(let, TK_LET);\n\n    _sourceText = sourceText;\n    _sourceTextSize = sourceTextSize;\n    _sourceTextPtr = 0;\n    _lasttokenline = _currentline = 1;\n    _lasttokencolumn = _currentcolumn = 0;\n    _prevtoken = -1;\n    _tokencolumn = 0;\n    _tokenline = 1;\n    _reached_eof = SQFalse;\n    if (_comments)\n      _comments->pushNewLine();\n    Next();\n}\n\nvoid SQLexer::Next()\n{\n  if (_sourceTextPtr >= _sourceTextSize) {\n      _reached_eof = SQTrue;\n      _currdata = SQUIRREL_EOB;\n  }\n  else {\n      _currdata = _sourceText[_sourceTextPtr++];\n  }\n}\n\nconst char *SQLexer::Tok2Str(SQInteger tok)\n{\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    while((nitr = _keywords->Next(false,itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n        if(((SQInteger)_integer(val)) == tok)\n            return _stringval(key);\n    }\n    return NULL;\n}\n\nvoid SQLexer::SetStringValue() {\n  _svalue = &_longstr[0];\n}\n\nvoid SQLexer::AddComment(enum CommentKind kind, SQInteger line, SQInteger start, SQInteger end) {\n  if (!_comments)\n    return;\n  size_t size = _currentComment.size();\n  char *data = (char *)sq_vm_malloc(_sharedstate->_alloc_ctx, (size + 1) * sizeof(char));\n  memcpy(data, &_currentComment[0], size);\n  data[size] = '\\0';\n\n  CurLineComments().push_back({ kind, size, data, line, start, end });\n\n  _currentComment.clear();\n}\n\nvoid SQLexer::LexBlockComment()\n{\n    enum CommentKind k = CK_BLOCK;\n    SQInteger line = 1;\n    SQInteger start = _currentcolumn;\n    bool done = false;\n    while(!done) {\n        _currentComment.push_back(CUR_CHAR);\n        switch(CUR_CHAR) {\n            case '*': { NEXT(); if(CUR_CHAR == '/') { done = true; NEXT(); }}; continue;\n            case '\\n':\n              k = CK_ML_BLOCK;\n              AddComment(k, line, start, _currentcolumn);\n              ++line;\n              nextLine();\n              NEXT();\n              start = _currentcolumn;\n              continue;\n            case SQUIRREL_EOB:\n              _ctx.reportDiagnostic(DiagnosticsId::DI_TRAILING_BLOCK_COMMENT, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n              return;\n            default: NEXT();\n        }\n    }\n\n    AddComment(k, k == CK_ML_BLOCK ? line : 0, start, _currentcolumn);\n}\n\nvoid SQLexer::LexLineComment()\n{\n    SQInteger start = _currentcolumn;\n    do {\n        NEXT();\n        _currentComment.push_back(CUR_CHAR);\n    } while (CUR_CHAR != '\\n' && (!IS_EOB()));\n    AddComment(CK_LINE, 0, start, _currentcolumn);\n}\n\nSQInteger SQLexer::Lex()\n{\n    return LexSingleToken();\n}\n\nvoid SQLexer::nextLine() {\n  ++_currentline;\n  if (_comments)\n    _comments->pushNewLine();\n}\n\nSQInteger SQLexer::LexSingleToken()\n{\n    _lasttokenline = _currentline;\n    _lasttokencolumn = _currentcolumn;\n\n    if (_state == LS_TEMPLATE && _expectedToken != TK_TEMPLATE_PREFIX) {\n      SQInteger stype = ReadString('\"', false, false);\n      if (stype != -1)\n        RETURN_TOKEN(stype);\n      _ctx.reportDiagnostic(DiagnosticsId::DI_LEX_ERROR_PARSE, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"the string\");\n    }\n\n    while(CUR_CHAR != SQUIRREL_EOB) {\n        _tokenline = _currentline;\n        _tokencolumn = _currentcolumn;\n        switch(CUR_CHAR){\n        case '\\t': case '\\r': case ' ': _flags |= TF_PREP_SPACE; NEXT(); continue;\n        case '\\n':\n            nextLine();\n            _prevtoken=_curtoken;\n            _flags |= TF_PREP_EOL;\n            _curtoken='\\n';\n            NEXT();\n            _currentcolumn=0;\n            continue;\n        case '/':\n            NEXT();\n            switch(CUR_CHAR){\n            case '*':\n                NEXT();\n                LexBlockComment();\n                continue;\n            case '/':\n                LexLineComment();\n                continue;\n            case '=':\n                NEXT();\n                RETURN_TOKEN(TK_DIVEQ);\n                continue;\n            default:\n                RETURN_TOKEN('/');\n            }\n        case '=':\n            NEXT();\n            if (CUR_CHAR != '='){ RETURN_TOKEN('=') }\n            else { NEXT(); RETURN_TOKEN(TK_EQ); }\n        case '<':\n            NEXT();\n            switch(CUR_CHAR) {\n            case '=':\n                NEXT();\n                if(CUR_CHAR == '>') {\n                    NEXT();\n                    RETURN_TOKEN(TK_3WAYSCMP);\n                }\n                RETURN_TOKEN(TK_LE)\n                break;\n            case '-': NEXT(); RETURN_TOKEN(TK_NEWSLOT); break;\n            case '<': NEXT(); RETURN_TOKEN(TK_SHIFTL); break;\n            }\n            RETURN_TOKEN('<');\n        case '>':\n            NEXT();\n            if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_GE);}\n            else if(CUR_CHAR == '>'){\n                NEXT();\n                if(CUR_CHAR == '>'){\n                    NEXT();\n                    RETURN_TOKEN(TK_USHIFTR);\n                }\n                RETURN_TOKEN(TK_SHIFTR);\n            }\n            else { RETURN_TOKEN('>') }\n        case '!':\n            NEXT();\n            if (CUR_CHAR != '='){ RETURN_TOKEN('!')}\n            else { NEXT(); RETURN_TOKEN(TK_NE); }\n        case '#': {\n            NEXT();\n            SQInteger stype = ReadDirective();\n            if (stype < 0)\n                _ctx.reportDiagnostic(DiagnosticsId::DI_LEX_ERROR_PARSE, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"directive\");\n            RETURN_TOKEN(TK_DIRECTIVE);\n            }\n        case '$': {\n            NEXT();\n            if (CUR_CHAR == '\"') {\n                RETURN_TOKEN(TK_TEMPLATE_OP);\n            }\n            else if (CUR_CHAR == '$') {  // $$\n                NEXT();\n                if (CUR_CHAR == '{') {  // $${\n                    NEXT();\n                    RETURN_TOKEN(TK_CODE_BLOCK_EXPR);\n                }\n                else\n                    RETURN_TOKEN('$');\n            }\n            else {\n                RETURN_TOKEN('$');\n            }\n            }\n        case '@': {\n            SQInteger stype;\n            NEXT();\n            if (CUR_CHAR == '@') {\n                NEXT();\n                stype = ReadString('\"', true);\n                if (stype != TK_STRING_LITERAL)\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_LEX_ERROR_PARSE, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"the docstring\");\n                RETURN_TOKEN(TK_DOCSTRING);\n            }\n            if (CUR_CHAR != '\"') {\n              RETURN_TOKEN('@');\n            }\n            if ((stype = ReadString('\"', true)) != -1) {\n              RETURN_TOKEN(stype);\n            }\n            _ctx.reportDiagnostic(DiagnosticsId::DI_LEX_ERROR_PARSE, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"the string\");\n            break;\n            }\n        case '\"':\n        case '\\'': {\n            SQInteger stype;\n            if((stype=ReadString(CUR_CHAR,false))!=-1){\n                RETURN_TOKEN(stype);\n            }\n            _ctx.reportDiagnostic(DiagnosticsId::DI_LEX_ERROR_PARSE, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"the string\");\n            break;\n            }\n        case '{': case '}': case '(': case ')': case '[': case ']':\n        case ';': case ',': case '^': case '~':\n            {SQInteger ret = CUR_CHAR;\n            NEXT(); RETURN_TOKEN(ret); }\n        case '?':\n            {NEXT();\n            if (CUR_CHAR == '.') {\n                NEXT();\n                if (CUR_CHAR == '$') {\n                    NEXT();\n                    RETURN_TOKEN(TK_NULLABLE_TYPE_METHOD_GETSTR);\n                }\n                else {\n                    RETURN_TOKEN(TK_NULLGETSTR);\n                }\n            }\n            if (CUR_CHAR == '[') { NEXT(); RETURN_TOKEN(TK_NULLGETOBJ); }\n            if (CUR_CHAR == '(') { NEXT(); RETURN_TOKEN(TK_NULLCALL); }\n            if (CUR_CHAR == '?') { NEXT(); RETURN_TOKEN(TK_NULLCOALESCE); }\n            RETURN_TOKEN('?'); }\n        case '.':\n            NEXT();\n            if (CUR_CHAR == '$') {\n                NEXT();\n                RETURN_TOKEN(TK_TYPE_METHOD_GETSTR);\n            }\n            if (CUR_CHAR != '.'){ RETURN_TOKEN('.') }\n            NEXT();\n            if (CUR_CHAR != '.'){\n              _ctx.reportDiagnostic(DiagnosticsId::DI_INVALID_TOKEN, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"..\");\n            }\n            NEXT();\n            RETURN_TOKEN(TK_VARPARAMS);\n        case '&':\n            NEXT();\n            if (CUR_CHAR != '&'){ RETURN_TOKEN('&') }\n            else { NEXT(); RETURN_TOKEN(TK_AND); }\n        case '|':\n            NEXT();\n            if (CUR_CHAR != '|'){ RETURN_TOKEN('|') }\n            else { NEXT(); RETURN_TOKEN(TK_OR); }\n        case ':':\n            NEXT();\n            if (CUR_CHAR != ':'){ RETURN_TOKEN(':') }\n            else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); }\n        case '*':\n            NEXT();\n            if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MULEQ);}\n            else RETURN_TOKEN('*');\n        case '%':\n            NEXT();\n            if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MODEQ);}\n            else RETURN_TOKEN('%');\n        case '-':\n            NEXT();\n            if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}\n            else if  (CUR_CHAR == '-'){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}\n            else RETURN_TOKEN('-');\n        case '+':\n            NEXT();\n            if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);}\n            else if (CUR_CHAR == '+'){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);}\n            else RETURN_TOKEN('+');\n        case SQUIRREL_EOB:\n            return 0;\n        default:{\n                if (sq_isdigit(CUR_CHAR)) {\n                    SQInteger ret = ReadNumber();\n                    RETURN_TOKEN(ret);\n                }\n                else if (sq_isalpha(CUR_CHAR) || CUR_CHAR == '_') {\n                    SQInteger t = ReadID();\n                    RETURN_TOKEN(t);\n                }\n                else {\n                    SQInteger c = CUR_CHAR;\n                    if (iscntrl((int)c))\n                        _ctx.reportDiagnostic(DiagnosticsId::DI_UNEXPECTED_CHAR, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"(control)\");\n                    NEXT();\n                    RETURN_TOKEN(c);\n                }\n            }\n        }\n    }\n    return 0;\n}\n\nSQInteger SQLexer::GetIDType(const char *s,SQInteger len)\n{\n    SQObjectPtr t;\n    if(_keywords->GetStr(s,len, t)) {\n        return SQInteger(_integer(t));\n    }\n    return TK_IDENTIFIER;\n}\n\nSQInteger SQLexer::AddUTF8(SQUnsignedInteger ch)\n{\n    if (ch < 0x80) {\n        APPEND_CHAR((char)ch);\n        return 1;\n    }\n    if (ch < 0x800) {\n        APPEND_CHAR((char)((ch >> 6) | 0xC0));\n        APPEND_CHAR((char)((ch & 0x3F) | 0x80));\n        return 2;\n    }\n    if (ch < 0x10000) {\n        APPEND_CHAR((char)((ch >> 12) | 0xE0));\n        APPEND_CHAR((char)(((ch >> 6) & 0x3F) | 0x80));\n        APPEND_CHAR((char)((ch & 0x3F) | 0x80));\n        return 3;\n    }\n    if (ch < 0x110000) {\n        APPEND_CHAR((char)((ch >> 18) | 0xF0));\n        APPEND_CHAR((char)(((ch >> 12) & 0x3F) | 0x80));\n        APPEND_CHAR((char)(((ch >> 6) & 0x3F) | 0x80));\n        APPEND_CHAR((char)((ch & 0x3F) | 0x80));\n        return 4;\n    }\n    return 0;\n}\n\nSQInteger SQLexer::ProcessStringHexEscape(char *dest, SQInteger maxdigits)\n{\n    NEXT();\n    if (!sq_isxdigit(CUR_CHAR))\n        _ctx.reportDiagnostic(DiagnosticsId::DI_HEX_NUMBERS_EXPECTED, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n    SQInteger n = 0;\n    while (sq_isxdigit(CUR_CHAR) && n < maxdigits) {\n        dest[n] = CUR_CHAR;\n        n++;\n        NEXT();\n    }\n    dest[n] = 0;\n    return n;\n}\n\nSQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim, bool advance)\n{\n    SQInteger t = TK_STRING_LITERAL;\n    if (_state == LS_TEMPLATE && ndelim != '\\\"') {\n        _ctx.reportDiagnostic(DiagnosticsId::DI_EXPECTED_LEX, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"string\");\n        return -1;\n    }\n    INIT_TEMP_STRING();\n    if (advance)\n      NEXT();\n    if(IS_EOB()) return -1;\n    for(;;) {\n        while(CUR_CHAR != ndelim) {\n            SQInteger x = CUR_CHAR;\n            switch (x) {\n            case SQUIRREL_EOB:\n                _ctx.reportDiagnostic(DiagnosticsId::DI_UNFINISHED_STRING, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n                return -1;\n            case '\\n':\n                if(!verbatim)\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_NEWLINE_IN_CONST, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n                APPEND_CHAR(CUR_CHAR); NEXT();\n                nextLine();\n                break;\n            case '\\\\':\n                if(verbatim) {\n                    APPEND_CHAR('\\\\'); NEXT();\n                }\n                else {\n                    NEXT();\n                    switch(CUR_CHAR) {\n                    case 'x':  {\n                        const SQInteger maxdigits = sizeof(char) * 2;\n                        char temp[maxdigits + 1];\n                        ProcessStringHexEscape(temp, maxdigits);\n                        char *stemp;\n                        APPEND_CHAR((char)strtoul(temp, &stemp, 16));\n                    }\n                    break;\n                    case 'U':\n                    case 'u':  {\n                        const SQInteger maxdigits = CUR_CHAR == 'u' ? 4 : 8;\n                        char temp[8 + 1];\n                        ProcessStringHexEscape(temp, maxdigits);\n                        char *stemp;\n                        AddUTF8(strtoul(temp, &stemp, 16));\n                    }\n                    break;\n                    case 't': APPEND_CHAR('\\t'); NEXT(); break;\n                    case 'a': APPEND_CHAR('\\a'); NEXT(); break;\n                    case 'b': APPEND_CHAR('\\b'); NEXT(); break;\n                    case 'n': APPEND_CHAR('\\n'); NEXT(); break;\n                    case 'r': APPEND_CHAR('\\r'); NEXT(); break;\n                    case 'v': APPEND_CHAR('\\v'); NEXT(); break;\n                    case 'f': APPEND_CHAR('\\f'); NEXT(); break;\n                    case '0': APPEND_CHAR('\\0'); NEXT(); break;\n                    case '\\\\': APPEND_CHAR('\\\\'); NEXT(); break;\n                    case '\"': APPEND_CHAR('\"'); NEXT(); break;\n                    case '\\'': APPEND_CHAR('\\''); NEXT(); break;\n                    case '{': case '}':\n                        if (_state == LS_TEMPLATE) {\n                          APPEND_CHAR(CUR_CHAR);\n                          NEXT();\n                          break;\n                        }\n                    // fall through -V796\n                    default:\n                        _ctx.reportDiagnostic(DiagnosticsId::DI_UNRECOGNISED_ESCAPER, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n                    break;\n                    }\n                }\n                break;\n            case '{':\n                if (_state == LS_TEMPLATE) {\n                    APPEND_CHAR(CUR_CHAR);\n                    NEXT();\n                    assert(_expectedToken > 0);\n                    t = _expectedToken;\n                    goto loop_exit;\n                }\n            default:\n                APPEND_CHAR(CUR_CHAR);\n                NEXT();\n            }\n        }\n        NEXT();\n\n        if (_state == LS_TEMPLATE)\n          t = TK_TEMPLATE_SUFFIX;\n\n        if(verbatim && CUR_CHAR == '\"') { //double quotation\n            APPEND_CHAR(CUR_CHAR);\n            NEXT();\n        }\n        else {\n            break;\n        }\n    }\n\nloop_exit:\n    TERMINATE_BUFFER();\n    SQInteger len = _longstr.size()-1;\n    if(ndelim == '\\'') {\n        assert(_state != LS_TEMPLATE);\n        if(len == 0)\n            _ctx.reportDiagnostic(DiagnosticsId::DI_EMPTY_LITERAL, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n        if(len > 1)\n            _ctx.reportDiagnostic(DiagnosticsId::DI_TOO_LONG_LITERAL, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n        _nvalue = _longstr[0];\n        return TK_INTEGER;\n    }\n    SetStringValue();\n    return t;\n}\n\nstatic void LexHexadecimal(const char *s,SQUnsignedInteger *res)\n{\n    *res = 0;\n    while(*s != 0)\n    {\n        if(sq_isdigit(*s)) *res = (*res)*16+((*s++)-'0');\n        else if(sq_isxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);\n        else { assert(0); }\n    }\n}\n\n#define INT_OVERFLOW_THRESHOLD (~SQUnsignedInteger(0) / 10)\n#define INT_OVERFLOW_DIGIT (~SQUnsignedInteger(0) % 10)\n\nstatic bool LexInteger(const char *s, SQUnsignedInteger *res)\n{\n\n    SQUnsignedInteger x = 0;\n    while(*s != 0)\n    {\n        SQUnsignedInteger digit = (*s++) - '0';\n        if (x > INT_OVERFLOW_THRESHOLD || (x == INT_OVERFLOW_THRESHOLD && digit > INT_OVERFLOW_DIGIT))\n            return false;\n        x = x * 10 + digit;\n    }\n    *res = x;\n    return x <= (~SQUnsignedInteger(0) >> 1);\n}\n\nstatic SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }\n\n\n#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)\n#define NUM_NEXT() { do NEXT() while (CUR_CHAR=='_'); }\nSQInteger SQLexer::ReadNumber()\n{\n#define TINT 1\n#define TFLOAT 2\n#define THEX 3\n#define TSCIENTIFIC 4\n\n    SQInteger type = TINT, firstchar = CUR_CHAR;\n    INIT_TEMP_STRING();\n    NUM_NEXT();\n    if(firstchar == '0' && sq_isdigit(CUR_CHAR))\n        _ctx.reportDiagnostic(DiagnosticsId::DI_OCTAL_NOT_SUPPORTED, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n    if(firstchar == '0' && (toupper(CUR_CHAR) == 'X') ) {\n        NUM_NEXT();\n        type = THEX;\n        while(sq_isxdigit(CUR_CHAR)) {\n            APPEND_CHAR(CUR_CHAR);\n            NUM_NEXT();\n        }\n        if(_longstr.size() > MAX_HEX_DIGITS)\n            _ctx.reportDiagnostic(DiagnosticsId::DI_HEX_TOO_MANY_DIGITS, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n        if(_longstr.size() == 0)\n            _ctx.reportDiagnostic(DiagnosticsId::DI_HEX_DIGITS_EXPECTED, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n    }\n    else {\n        APPEND_CHAR((char)firstchar);\n        bool hasExp = false;\n        bool hasDot = false;\n        while (CUR_CHAR == '.' || sq_isalnum(CUR_CHAR)) {\n            if(CUR_CHAR == '.') {\n                if(hasDot || hasExp)\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_MALFORMED_NUMBER, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n                hasDot = true;\n                type = TFLOAT;\n            }\n            else if(isexponent(CUR_CHAR)) {\n                if(hasExp)\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_MALFORMED_NUMBER, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n                hasExp = true;\n                type = TSCIENTIFIC;\n                APPEND_CHAR(CUR_CHAR);\n                NEXT();\n                if(CUR_CHAR == '+' || CUR_CHAR == '-'){\n                    APPEND_CHAR(CUR_CHAR);\n                    NEXT();\n                }\n                if(!sq_isdigit(CUR_CHAR))\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_FP_EXP_EXPECTED, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n            }\n            if(!sq_isdigit(CUR_CHAR) && !isexponent(CUR_CHAR) && CUR_CHAR != '.')\n                _ctx.reportDiagnostic(DiagnosticsId::DI_MALFORMED_NUMBER, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n\n            APPEND_CHAR(CUR_CHAR);\n            NUM_NEXT();\n        }\n    }\n    TERMINATE_BUFFER();\n    switch(type) {\n    case TSCIENTIFIC:\n    case TFLOAT:\n#if SQ_USE_STD_FROM_CHARS\n        {\n            auto ret = std::from_chars(&_longstr[0], &_longstr[0] + _longstr.size(), _fvalue);\n            if (ret.ec == std::errc::result_out_of_range)\n                _ctx.reportDiagnostic(_fvalue == 0 ? DiagnosticsId::DI_LITERAL_UNDERFLOW : DiagnosticsId::DI_LITERAL_OVERFLOW,\n                    _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"float\");\n\n            for (const char * c = ret.ptr; c < &_longstr[0] + _longstr.size() - 1; ++c)\n                if (*c != '0')\n                {\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_MALFORMED_NUMBER, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn);\n                    break;\n                }\n        }\n#else\n        {\n            char *sTemp;\n            volatile SQFloat value;\n            value = (SQFloat)strtod(&_longstr[0], &sTemp);\n            _fvalue = value;\n            if(value == 0)\n            {\n                for(int i = 0; i < _longstr.size(); i++)\n                {\n                    char c = _longstr[i];\n                    if (!c || c == 'e' || c == 'E')\n                        break;\n                    if (c != '.' && c != '0')\n                        _ctx.reportDiagnostic(DiagnosticsId::DI_LITERAL_UNDERFLOW, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"float\");\n                }\n            }\n        }\n#endif\n\n        if(sizeof(_fvalue) == sizeof(float))\n        {\n            if (_fvalue >= FLT_MAX)\n                _ctx.reportDiagnostic(DiagnosticsId::DI_LITERAL_OVERFLOW, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"float\");\n        }\n        else if(sizeof(_fvalue) == sizeof(double))\n        {\n            if (_fvalue >= DBL_MAX)\n                _ctx.reportDiagnostic(DiagnosticsId::DI_LITERAL_OVERFLOW, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"float\");\n        }\n        return TK_FLOAT;\n    case TINT:\n        if(!LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue))\n            _ctx.reportDiagnostic(DiagnosticsId::DI_LITERAL_OVERFLOW, _tokenline, _tokencolumn, _currentcolumn - _tokencolumn, \"integer\");\n        return TK_INTEGER;\n    case THEX:\n        LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);\n        return TK_INTEGER;\n    }\n    return 0;\n}\n\nSQInteger SQLexer::ReadID()\n{\n    SQInteger res;\n    INIT_TEMP_STRING();\n    do {\n        APPEND_CHAR(CUR_CHAR);\n        NEXT();\n    } while(sq_isalnum(CUR_CHAR) || CUR_CHAR == '_');\n    TERMINATE_BUFFER();\n    res = GetIDType(&_longstr[0],_longstr.size() - 1);\n    if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {\n        SetStringValue();\n    }\n    return res;\n}\n\nSQInteger SQLexer::ReadDirective()\n{\n    INIT_TEMP_STRING();\n    do {\n        APPEND_CHAR(CUR_CHAR);\n        NEXT();\n    } while(sq_isalnum(CUR_CHAR) || CUR_CHAR == '_' || CUR_CHAR == '-' || CUR_CHAR == ':');\n    TERMINATE_BUFFER();\n    if (!_longstr[0])\n        return -1;\n    SetStringValue();\n    return TK_DIRECTIVE;\n}\n"
  },
  {
    "path": "squirrel/compiler/lexer.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQLEXER_H_\n#define _SQLEXER_H_\n\n#include \"compilationcontext.h\"\n#include \"sourceloc.h\"\n\nenum SQLexerState {\n  LS_REGULAR,\n  LS_TEMPLATE\n};\n\nenum SQTokenFlags {\n  TF_PREP_EOL = 1 << 0,             // end of line after this token\n  TF_PREP_SPACE = 1 << 1,           // space after this token\n};\n\nstruct SQLexer\n{\n    using LexChar = unsigned char;\n\n    SQLexer(SQSharedState *ss, SQCompilation::SQCompilationContext &ctx, SQCompilation::Comments *comments);\n    ~SQLexer();\n    void Init(const char *code, size_t codeSize);\n    SQInteger Lex();\n    const char *Tok2Str(SQInteger tok);\n    void SetStringValue();\nprivate:\n    void nextLine();\n    SQInteger LexSingleToken();\n    SQInteger GetIDType(const char *s,SQInteger len);\n    SQInteger ReadString(SQInteger ndelim,bool verbatim, bool advance = true);\n    SQInteger ReadNumber();\n    void LexBlockComment();\n    void LexLineComment();\n    SQInteger ReadID();\n    SQInteger ReadDirective();\n    void Next();\n    SQInteger AddUTF8(SQUnsignedInteger ch);\n    SQInteger ProcessStringHexEscape(char *dest, SQInteger maxdigits);\n    SQCompilation::Comments::LineCommentsList &CurLineComments() { assert(_comments);  return _comments->commentsList().back(); }\n\n    void AddComment(enum SQCompilation::CommentKind kind, SQInteger line, SQInteger start, SQInteger end);\n\nprivate:\n    SQInteger _curtoken = -1;\n    SQTable *_keywords = nullptr;\n    SQBool _reached_eof = SQFalse;\n    SQCompilation::SQCompilationContext &_ctx;\n    const char *_sourceText = nullptr;\n    size_t _sourceTextSize = 0;\n    size_t _sourceTextPtr = 0;\n    SQCompilation::Comments *_comments = nullptr;\n    sqvector<char> _currentComment;\n\npublic:\n    SQCompilation::SourceSpan tokenSpan() const {\n        return {\n            {static_cast<int32_t>(_tokenline), static_cast<int32_t>(_tokencolumn)},\n            {static_cast<int32_t>(_currentline), static_cast<int32_t>(_currentcolumn)}\n        };\n    }\n\n    SQCompilation::SourceLoc tokenStart() const {\n        return {static_cast<int32_t>(_tokenline), static_cast<int32_t>(_tokencolumn)};\n    }\n\n    SQCompilation::SourceLoc currentPos() const {\n        return {static_cast<int32_t>(_currentline), static_cast<int32_t>(_currentcolumn)};\n    }\n\n    SQInteger _prevtoken = -1;\n    SQInteger _currentline = 1;\n    SQInteger _lasttokenline = -1;\n    SQInteger _lasttokencolumn = 0;\n    SQInteger _currentcolumn = 0;\n    SQInteger _tokencolumn = 0;\n    SQInteger _tokenline = 1;\n    SQInteger _expectedToken = -1;\n    unsigned _prevflags = 0;\n    unsigned _flags = 0;\n    enum SQLexerState _state = LS_REGULAR;\n    const char *_svalue = nullptr;\n    SQInteger _nvalue = 0;\n    SQFloat _fvalue = 0.0f;\n    LexChar _currdata = 0;\n    SQSharedState *_sharedstate = nullptr;\n    sqvector<char> _longstr;\n};\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/optimizations/closureHoisting.cpp",
    "content": "/*****\n\nThe basic algorithm:\n* Walk the AST top-down\n  * Calculate nesting depth\n  * Collect locals in each scope\n* For each closure, find the deepest scope it captures.\n* If the closure can be hoisted, create a VarDecl `let $chN = <FunctionExpr>`\n  and insert it into the highest scope reachable (the one where the deepest\n  captured variable lives). Within that scope's block, place it right before\n  the statement that (transitively) contains the closure to ensure correct\n  ordering with respect to imports and other declarations.\n* In Phase 2 (OriginalClosureReplacer) replace the original FunctionExpr\n  with an Id reference to the generated name ($ch0, $ch1, ...)\n\n*****/\n\n#include \"closureHoisting.h\"\n\n#include <algorithm>\n#include <cstdio>\n\nnamespace SQCompilation {\n\nClosureHoistingOpt::ClosureHoistingOpt(SQSharedState *ss, Arena *astA)\n  : _ss(ss)\n  , astArena(astA)\n  , arena(ss->_alloc_ctx, \"ClosureHoistingOpt\")\n  , varIdx(0)\n  , hoistedClosures(HoistedMap::Allocator(&arena))\n  , funcLocals(FuncLocalsMap::Allocator(&arena))\n{}\n\n\nconst char *ClosureHoistingOpt::generateName() {\n  char buffer[32];\n  int n = snprintf(buffer, sizeof(buffer), \"$ch%d\", varIdx++);\n  char *result = (char *)astArena->allocate((n + 1) * sizeof(char));\n  strcpy(result, buffer);\n  return result;\n}\n\n//------------------------------------------------------------------------------\n// Capture Analysis\n//------------------------------------------------------------------------------\n\n// Result of capture analysis for a single closure (internal to this file).\nstruct CaptureInfo {\n  int maxCaptureDepth;          // Deepest captured variable's depth (-1 if none)\n  bool capturesImmediateParent; // Does it capture from immediate parent? (blocks hoisting)\n  int maxIndirectCaptureDepth;  // Max depth with indirect capture (-1 if none)\n};\n\n// Visitor that analyzes what a closure captures.\n// Uses a scope stack (not a flat set) to correctly handle nested function\n// parameter shadowing: a nested function's parameter only masks names\n// within that nested function, not in the outer scope.\nclass CaptureAnalyzer : public Visitor {\n  CaptureInfo &info;\n  ScopeContext *funcScope;    // The function being analyzed\n  const char *selfName;       // The function's name (for self-reference detection)\n  FuncLocalsMap &funcLocals;  // Pre-computed locals per function\n\n  // Stack of local name sets for nested scopes.\n  // Bottom = the function being analyzed, top = innermost nested function.\n  // Names are checked from top to bottom; popping correctly un-shadows.\n  ArenaVector<const NameSet *> scopeStack;\n\n  bool isLocal(const char *name) {\n    for (int i = (int)scopeStack.size() - 1; i >= 0; i--)\n      if (scopeStack[i]->find(name) != scopeStack[i]->end())\n        return true;\n    return false;\n  }\n\n  // Once the function captures from its immediate parent, it can't be hoisted\n  // at all — stop traversing early.\n  bool canHoist() const { return !info.capturesImmediateParent; }\n\npublic:\n  CaptureAnalyzer(CaptureInfo &i, ScopeContext *fs, const char *sn,\n                   FuncLocalsMap &fl, Arena *a)\n      : info(i), funcScope(fs), selfName(sn), funcLocals(fl),\n        scopeStack(a) {}\n\n  void visitNode(Node *node) override {\n    if (!canHoist()) return;\n    node->visitChildren(this);\n  }\n\n  void visitId(Id *id) override {\n    if (!canHoist()) return;\n\n    const char *name = id->name();\n\n    // Self-reference to the function is treated as a capture from immediate parent\n    // (where the function name is declared). This blocks hoisting.\n    if (selfName && strcmp(name, selfName) == 0) {\n      if (funcScope->isInImmediateParent(name))\n        info.capturesImmediateParent = true;\n      return;\n    }\n\n    // Local to this function or a nested function at current nesting level\n    if (isLocal(name))\n      return;\n\n    // Check if captured from the function's immediate parent (blocks hoisting)\n    if (funcScope->isInImmediateParent(name))\n      info.capturesImmediateParent = true;\n\n    // Find capture depth relative to the function's parent\n    int depth = funcScope->parent ? funcScope->parent->findNameDepth(name) : -1;\n    if (depth >= 0) {\n      info.maxCaptureDepth = std::max(info.maxCaptureDepth, depth);\n\n      // Check if this capture is from a nested block (not directly in the scope's block).\n      // Such captures prevent hoisting to that depth.\n      if (funcScope->parent->isIndirectLocalAtDepth(name, depth)) { //-V1004\n        info.maxIndirectCaptureDepth = std::max(info.maxIndirectCaptureDepth, depth);\n      }\n    }\n  }\n\n  // Descend into nested functions: push their pre-computed locals, visit, pop.\n  // This correctly handles parameter shadowing — a nested function's param\n  // only masks names within that function's body.\n  void visitFunctionExpr(FunctionExpr *f) override {\n    if (!canHoist()) return;\n\n    // Visit parameter defaults FIRST, before pushing this function's locals.\n    // Defaults are evaluated in the enclosing scope, not the function body scope,\n    // so body locals must not shadow outer names during default analysis.\n    for (auto param : f->parameters()) {\n      if (!canHoist()) break;\n      if (param->defaultValue())\n        param->defaultValue()->visit(this);\n      if (param->getDestructuring()) {\n        for (auto decl : param->getDestructuring()->declarations()) {\n          if (decl->expression())\n            decl->expression()->visit(this);\n        }\n      }\n    }\n\n    auto it = funcLocals.find(f);\n    if (it != funcLocals.end()) {\n      scopeStack.push_back(it->second);\n    }\n\n    if (canHoist())\n      f->body()->visit(this);\n\n    if (it != funcLocals.end())\n      scopeStack.pop_back();\n  }\n};\n\n//------------------------------------------------------------------------------\n// Insert Hoisted Declarations\n//------------------------------------------------------------------------------\n\nvoid ClosureHoistingOpt::insertHoistedDecls(Block *block,\n                                             ArenaVector<HoistCandidate> &candidates) {\n  if (candidates.empty() || !block)\n    return;\n\n  // Sort candidates by insertion point to handle them in order\n  std::stable_sort(candidates.begin(), candidates.end(),\n    [](const HoistCandidate &a, const HoistCandidate &b) {\n      return a.insertionPoint < b.insertionPoint;\n    });\n\n  // Track how many we've inserted so far (to adjust subsequent indices)\n  int insertionsBeforePoint = 0;\n\n  for (auto &candidate : candidates) {\n    // Generate unique name ($ch0, $ch1, etc.)\n    candidate.generatedName = generateName();\n\n    // Record in hoistedClosures map (FunctionExpr* -> name)\n    hoistedClosures[candidate.func] = candidate.generatedName;\n\n    // Update hoisting level on FunctionExpr (for codegen)\n    candidate.func->hoistBy(candidate.hoistDepth);\n\n    // Create VarDecl with the same FunctionExpr* as initializer.\n    // The original location still references this FunctionExpr —\n    // OriginalClosureReplacer (Phase 2) will replace it with an Id.\n    //\n    // Use the insertion point statement's source position for the VarDecl,\n    // not the original lambda position. This ensures the _OP_CLOSURE\n    // instruction gets the correct line number for stack traces.\n    int actualIdx = candidate.insertionPoint + insertionsBeforePoint;\n    SourceLoc insertLoc = candidate.func->sourceSpan().start;\n    if (actualIdx < (int)block->statements().size()) {\n      Statement *atStmt = block->statements()[actualIdx];\n      // When inserting before a bare Block statement, use the first child\n      // statement's location instead of the block's opening brace location.\n      // The '{' brace doesn't generate instructions, so using its line would\n      // create a spurious line entry that changes stack traces.\n      if (atStmt->op() == TO_BLOCK) {\n        Block *blk = static_cast<Block *>(atStmt);\n        if (!blk->statements().empty())\n          insertLoc = blk->statements()[0]->sourceSpan().start;\n        else\n          insertLoc = atStmt->sourceSpan().start;\n      } else {\n        insertLoc = atStmt->sourceSpan().start;\n      }\n    }\n\n    Id *nameId = new (astArena) Id({insertLoc, insertLoc},\n                                    candidate.generatedName);\n    VarDecl *hoistedDecl = new (astArena) VarDecl(\n        insertLoc, nameId, candidate.func, false);\n\n    // Insert into block at the correct position\n    block->statements().insert(actualIdx, hoistedDecl);\n    insertionsBeforePoint++;\n  }\n}\n\n//------------------------------------------------------------------------------\n// Typed Default Parameter Safety Check\n//------------------------------------------------------------------------------\n\n// Check if a function has any parameter with both a type annotation and a\n// default value. The type check for such defaults happens at closure creation\n// time and can throw. Hoisting would move that throw to a different scope\n// (e.g. out of a try/catch), changing program behavior.\nstatic bool hasTypedDefaults(FunctionExpr *f) {\n  for (auto param : f->parameters()) {\n    if (param->getTypeMask() != ~0u && param->hasDefaultValue())\n      return true;\n  }\n  return false;\n}\n\n//------------------------------------------------------------------------------\n// HoistingVisitor Helpers\n//------------------------------------------------------------------------------\n\n// Pre-compute directLocalNames by scanning the block's direct child statements.\n// A local is \"direct\" if its declaration is a top-level statement of the block,\n// as opposed to being inside a for-loop init, if-body, try-body, etc.\nvoid ClosureHoistingOpt::collectDirectLocals(Block *block, ScopeContext &scope) {\n  if (!block) return;\n  for (auto stmt : block->statements()) {\n    switch (stmt->op()) {\n      case TO_VAR:\n        scope.directLocalNames->insert(static_cast<VarDecl *>(stmt)->name());\n        break;\n      case TO_CONST:\n        scope.directLocalNames->insert(static_cast<ConstDecl *>(stmt)->name());\n        break;\n      case TO_DECL_GROUP:\n      case TO_DESTRUCTURE:\n        for (auto decl : static_cast<DeclGroup *>(stmt)->declarations())\n          scope.directLocalNames->insert(decl->name());\n        break;\n      default:\n        break;\n    }\n  }\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::registerFunctionParams(\n    FunctionExpr *f, ScopeContext &scope) {\n  for (auto param : f->parameters()) {\n    scope.localNames->insert(param->name());\n    scope.directLocalNames->insert(param->name());\n    if (param->getDestructuring()) {\n      for (auto decl : param->getDestructuring()->declarations()) {\n        scope.localNames->insert(decl->name());\n        scope.directLocalNames->insert(decl->name());\n      }\n    }\n  }\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::tryHoistFunction(\n    FunctionExpr *f, ScopeContext &funcScope) {\n  // Don't hoist top-level functions or class methods\n  ScopeContext *parentScope = funcScope.parent;\n  if (!parentScope || !parentScope->parent)\n    return;\n  if (funcScope.isClassMethod())\n    return;\n  // Don't hoist const functions - they are compile-time constants\n  if (insideConstDecl)\n    return;\n\n  // Don't hoist functions with typed default parameters.\n  // The type check for defaults happens at closure creation and can throw.\n  // Hoisting moves the closure creation to a different scope, which can\n  // change error handling behavior (e.g. moving it out of a try/catch).\n  if (hasTypedDefaults(f))\n    return;\n\n  // Analyze what this closure captures\n  CaptureInfo captures = {-1, false, -1};\n  CaptureAnalyzer analyzer(captures, &funcScope, f->name(), owner->funcLocals, &owner->arena);\n  analyzer.visitFunctionExpr(f);\n\n  if (captures.capturesImmediateParent)\n    return;\n\n  // Compute target depth based on captures\n  int targetDepth;\n  if (captures.maxCaptureDepth < 0) {\n    targetDepth = 0;  // No captures — hoist all the way to root\n  } else {\n    // Can't hoist above the deepest capture.\n    // Indirect captures (in nested blocks) require staying one level deeper.\n    targetDepth = captures.maxCaptureDepth;\n    if (captures.maxIndirectCaptureDepth >= 0)\n      targetDepth = std::max(targetDepth, captures.maxIndirectCaptureDepth + 1);\n  }\n\n  if (targetDepth >= funcScope.depth)\n    return;\n\n  // Walk up to the target scope\n  ScopeContext *target = parentScope;\n  while (target && target->depth > targetDepth)\n    target = target->parent;\n\n  if (target && target->localCount() < ScopeContext::MAX_LOCALS_FOR_HOISTING) {\n    int hoistDepth = funcScope.depth - targetDepth;\n    target->pendingHoists.push_back({f, hoistDepth, nullptr, target->currentStatementIndex});\n  }\n}\n\n//------------------------------------------------------------------------------\n// HoistingVisitor Implementation\n//------------------------------------------------------------------------------\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitBlock(Block *b) {\n  bool isOwnBlock = currentScope && currentScope->block == b;\n  int savedIndex = currentScope ? currentScope->currentStatementIndex : 0;\n\n  for (int i = 0; i < (int)b->statements().size(); ++i) {\n    if (isOwnBlock)\n      currentScope->currentStatementIndex = i;\n    b->statements()[i]->visit(this);\n  }\n\n  if (isOwnBlock)\n    currentScope->currentStatementIndex = savedIndex;\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitFunctionExpr(FunctionExpr *f) {\n  ScopeContext newScope(&owner->arena, currentScope, /*isClassScope=*/false, f->body());\n  registerFunctionParams(f, newScope);\n  collectDirectLocals(f->body(), newScope);\n\n  ScopeContext *prevScope = currentScope;\n  currentScope = &newScope;\n  for (auto param : f->parameters())\n    param->visit(this);\n  f->body()->visit(this);\n  currentScope = prevScope;\n\n  // Save locals for CaptureAnalyzer (zero-copy pointer sharing)\n  owner->funcLocals[f] = newScope.localNames;\n\n  newScope.enforceLocalsLimit();\n  owner->insertHoistedDecls(f->body(), newScope.pendingHoists);\n  tryHoistFunction(f, newScope);\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitClassExpr(ClassExpr *c) {\n  if (c->classBase())\n    c->classBase()->visit(this);\n\n  ScopeContext newScope(&owner->arena, currentScope, /*isClassScope=*/true, nullptr);\n\n  ScopeContext *prevScope = currentScope;\n  currentScope = &newScope;\n\n  if (c->classKey() && c->classKey()->op() != TO_ID)\n    c->classKey()->visit(this);\n\n  for (auto &member : c->members()) {\n    if (member.key) member.key->visit(this);\n    if (member.value) member.value->visit(this);\n  }\n\n  currentScope = prevScope;\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitVarDecl(VarDecl *v) {\n  currentScope->localNames->insert(v->name());\n  if (v->expression())\n    v->expression()->visit(this);\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitParamDecl(ParamDecl *p) {\n  if (p->defaultValue())\n    p->defaultValue()->visit(this);\n  if (p->getDestructuring()) {\n    for (auto decl : p->getDestructuring()->declarations()) {\n      if (decl->expression())\n        decl->expression()->visit(this);\n    }\n  }\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitConstDecl(ConstDecl *c) {\n  currentScope->localNames->insert(c->name());\n  if (c->value()) {\n    bool wasInConstDecl = insideConstDecl;\n    insideConstDecl = true;\n    c->value()->visit(this);\n    insideConstDecl = wasInConstDecl;\n  }\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitTryStatement(TryStatement *stmt) {\n  stmt->tryStatement()->visit(this);\n  currentScope->localNames->insert(stmt->exceptionId()->name());\n  stmt->catchStatement()->visit(this);\n}\n\nvoid ClosureHoistingOpt::HoistingVisitor::visitForeachStatement(ForeachStatement *fe) {\n  if (fe->idx()) currentScope->localNames->insert(fe->idx()->name());\n  if (fe->val()) currentScope->localNames->insert(fe->val()->name());\n  fe->container()->visit(this);\n  fe->body()->visit(this);\n}\n\n//------------------------------------------------------------------------------\n// OriginalClosureReplacer Implementation\n//------------------------------------------------------------------------------\n\nNode *ClosureHoistingOpt::OriginalClosureReplacer::transformFunctionExpr(FunctionExpr *f) {\n  auto it = hoistedClosures.find(f);\n  if (it != hoistedClosures.end()) {\n    // First encounter is the hoisted VarDecl initializer — keep it.\n    // Second encounter is the original location — replace with Id.\n    if (resolved.find(f) == resolved.end()) {\n      resolved.insert(f);\n      f->transformChildren(this);\n      return f;\n    }\n    const char *hoistedName = it->second;\n    return new (astArena) Id(f->sourceSpan(), hoistedName);\n  }\n\n  f->transformChildren(this);\n  return f;\n}\n\n//------------------------------------------------------------------------------\n// Main Entry Point\n//------------------------------------------------------------------------------\n\nvoid ClosureHoistingOpt::run(RootBlock *root) {\n  if (!_ss->checkCompilationOption(CompilationOptions::CO_CLOSURE_HOISTING_OPT))\n    return;\n\n  // Phase 1: Traverse AST, collect scope info, and insert hoisted VarDecls.\n  // After this, each hoisted FunctionExpr is referenced from two places:\n  // the new VarDecl (at the target scope) and the original location.\n  ScopeContext rootScope(&arena, nullptr, /*isClassScope=*/false, root);\n  collectDirectLocals(root, rootScope);\n  HoistingVisitor visitor(this, &rootScope);\n  root->visit(&visitor);\n\n  rootScope.enforceLocalsLimit();\n  insertHoistedDecls(root, rootScope.pendingHoists);\n\n  // Phase 2: Resolve the duplication — replace original FunctionExpr\n  // occurrences with Id references to the hoisted variable names.\n  if (!hoistedClosures.empty()) {\n    OriginalClosureReplacer transformer(hoistedClosures, &arena, astArena);\n    root->transform(&transformer);\n  }\n}\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/optimizations/closureHoisting.h",
    "content": "#pragma once\n\n#include \"../ast.h\"\n#include \"../arena.h\"\n#include \"../sqstate.h\"\n\nnamespace SQCompilation {\n\n// TODO: Unify this with functions from static analyzer\nstruct str_hash {\n  size_t operator()(const char *s) const {\n    size_t h = 0;\n    for (; *s; ++s)\n      h = h * 31 + (unsigned char)*s;\n    return h;\n  }\n};\nstruct str_eq {\n  bool operator()(const char *a, const char *b) const {\n    return std::strcmp(a, b) == 0;\n  }\n};\n\ntypedef ArenaUnorderedSet<const char *, str_hash, str_eq> NameSet;\n\n// Represents a closure that CAN be hoisted\nstruct HoistCandidate {\n  FunctionExpr *func;\n  int hoistDepth;              // How many levels to hoist\n  const char *generatedName;   // $ch0, $ch1, etc. (assigned when hoisting)\n  int insertionPoint;          // Index in target block where to insert (before this statement)\n};\n\n// Function/class-level scope context (NOT per-block). Created for: root scope,\n// each FunctionExpr, and each ClassExpr. Block-level constructs (for, foreach,\n// try, if, while) do NOT create their own ScopeContext — their variables are\n// tracked in the enclosing function's localNames. The directLocalNames subset\n// distinguishes top-level declarations from those inside nested blocks.\n// The localNames/directLocalNames sets are arena-allocated and survive scope exit,\n// allowing CaptureAnalyzer to share them via pointer (zero-copy).\nstruct ScopeContext {\n  ScopeContext *parent;        // null for root scope\n  bool isClassScope;           // true only for class body (not methods inside it)\n  int depth;                   // Nesting depth (class scopes don't increment)\n  Block *block;                // The block where hoisted decls go\n  int currentStatementIndex;   // Index of statement currently being visited in this scope's block\n\n  // ALL locals declared in this function scope (params, vars, for-loop inits,\n  // foreach vars, try exception vars). Used for capture depth calculation.\n  // Arena-allocated pointer: survives scope exit for CaptureAnalyzer reuse.\n  NameSet *localNames;\n\n  // Subset of localNames: only locals declared as direct children of this\n  // scope's block (params + top-level let/const/destructuring). Excludes\n  // for-loop init vars, foreach vars, try exception vars, etc.\n  // Used by isIndirectLocalAtDepth() to detect captures from nested blocks.\n  NameSet *directLocalNames;\n\n  // Candidates found in child scopes that should hoist to THIS level\n  ArenaVector<HoistCandidate> pendingHoists;\n\n  static NameSet *makeNameSet(Arena *arena) {\n    void *mem = arena->allocate(sizeof(NameSet));\n    return new (mem) NameSet(NameSet::Allocator(arena));\n  }\n\n  // Constructor computes depth, skipping class scopes\n  ScopeContext(Arena *arena, ScopeContext *p, bool isClass, Block *b)\n      : parent(p),\n        isClassScope(isClass),\n        depth(p ? p->depth + (p->isClassScope ? 0 : 1) : 0),\n        block(b),\n        currentStatementIndex(0),\n        localNames(makeNameSet(arena)),\n        directLocalNames(makeNameSet(arena)),\n        pendingHoists(arena) {}\n\n  int findNameDepth(const char *name) const {\n    if (localNames->find(name) != localNames->end()) return depth;\n    if (parent) return parent->findNameDepth(name);\n    return -1;  // Not found (global/builtin)\n  }\n\n  bool isInImmediateParent(const char *name) const {\n    if (!parent) return false;\n    return parent->localNames->find(name) != parent->localNames->end();\n  }\n\n  // Check if a name at a given depth is in a nested block (not directly in that scope's block).\n  // Returns true if the name is a local at that depth but NOT a direct block declaration.\n  bool isIndirectLocalAtDepth(const char *name, int targetDepth) const {\n    // Walk up to scope at targetDepth\n    const ScopeContext *scope = this;\n    while (scope && scope->depth > targetDepth) {\n      scope = scope->parent;\n    }\n    if (!scope || scope->depth != targetDepth) {\n      return false;  // Couldn't find scope at this depth\n    }\n    // Check if name is in scope's localNames but NOT in directLocalNames\n    if (scope->localNames->find(name) != scope->localNames->end()) {\n      return scope->directLocalNames->find(name) == scope->directLocalNames->end();\n    }\n    return false;\n  }\n\n  bool isClassMethod() const {\n    return parent && parent->isClassScope;\n  }\n\n  // Count of locals including pending hoists (for frame size limit)\n  size_t localCount() const {\n    return localNames->size() + pendingHoists.size();\n  }\n\n  // Leave some room for temporary variables\n  static const size_t MAX_LOCALS_FOR_HOISTING = 200;\n\n  // Trim pending hoists if adding them would exceed the locals limit\n  void enforceLocalsLimit() {\n    int maxHoists = std::max(0, (int)MAX_LOCALS_FOR_HOISTING - (int)localNames->size());\n    while ((int)pendingHoists.size() > maxHoists) {\n      pendingHoists.pop_back();\n    }\n  }\n};\n\n// Pre-computed locals per function: FunctionExpr* -> its localNames set.\n// Populated during HoistingVisitor, consumed by CaptureAnalyzer.\n// Shares the same arena-allocated NameSet pointers from ScopeContext.\ntypedef ArenaUnorderedMap<FunctionExpr *, const NameSet *> FuncLocalsMap;\n\nclass ClosureHoistingOpt {\npublic:\n  ClosureHoistingOpt(SQSharedState *ss, Arena *astArena);\n  void run(RootBlock *root);\n\nprivate:\n  SQSharedState *_ss;\n  Arena *astArena;             // For AST node allocation\n  Arena arena;                 // Internal arena for temporary data structures\n  int varIdx;                  // Counter for generating $ch0, $ch1, etc.\n\n  // FunctionExpr* -> generated name mapping\n  typedef ArenaUnorderedMap<FunctionExpr *, const char *> HoistedMap;\n  HoistedMap hoistedClosures;\n\n  FuncLocalsMap funcLocals;\n\n  // Pre-compute which locals are declared directly in a block (not in nested\n  // for/if/try/while blocks).\n  static void collectDirectLocals(Block *block, ScopeContext &scope);\n\n  // Single-pass visitor that collects local names, evaluates hoisting,\n  // and inserts hoisted VarDecls at scope boundaries\n  class HoistingVisitor : public Visitor {\n    ClosureHoistingOpt *owner;\n    ScopeContext *currentScope;\n    bool insideConstDecl = false;\n\n    void registerFunctionParams(FunctionExpr *f, ScopeContext &scope);\n    void tryHoistFunction(FunctionExpr *f, ScopeContext &funcScope);\n\n  public:\n    HoistingVisitor(ClosureHoistingOpt *o, ScopeContext *root)\n        : owner(o), currentScope(root) {}\n\n    void visitBlock(Block *b) override;\n    void visitFunctionExpr(FunctionExpr *f) override;\n    void visitClassExpr(ClassExpr *c) override;\n    void visitVarDecl(VarDecl *v) override;\n    void visitParamDecl(ParamDecl *p) override;\n    void visitConstDecl(ConstDecl *c) override;\n    void visitTryStatement(TryStatement *stmt) override;\n    void visitForeachStatement(ForeachStatement *fe) override;\n  };\n\n  // After Phase 1, each hoisted FunctionExpr is referenced from two places:\n  // the new VarDecl (at the target scope) and the original location.\n  // This transformer resolves the duplication by replacing the original\n  // occurrence with an Id reference to the hoisted variable.\n  class OriginalClosureReplacer : public Transformer {\n    HoistedMap &hoistedClosures;\n    ArenaUnorderedSet<FunctionExpr *> resolved;  // Hoisted FunctionExprs already resolved (kept at VarDecl)\n    Arena *astArena;\n\n  public:\n    OriginalClosureReplacer(HoistedMap &map, Arena *arena, Arena *astA)\n        : hoistedClosures(map),\n          resolved(decltype(resolved)::Allocator(arena)),\n          astArena(astA) {}\n\n    Node *transformFunctionExpr(FunctionExpr *f) override;\n  };\n\n  // Helper methods\n  const char *generateName();\n  void insertHoistedDecls(Block *block, ArenaVector<HoistCandidate> &candidates);\n};\n\n} // namespace SQCompilation\n"
  },
  {
    "path": "squirrel/compiler/optimizer.cpp",
    "content": "#include \"sqpcheader.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqtable.h\"\n#include \"opcodes.h\"\n#include \"sqfuncstate.h\"\n#include \"optimizer.h\"\n#include \"sq_safe_shift.h\"\n\nSQOptimizer::SQOptimizer(SQFuncState & func_state) : fs(&func_state), jumps(func_state._full_line_infos._alloc_ctx), codeChanged(false) {}\n#undef _DEBUG_DUMP\n\n#ifdef _DEBUG_DUMP\n void SQOptimizer::debugPrintInstructionPos(const char * message, int instructionIndex)\n {\n    for (int i = 0; i < fs->_full_line_infos.size(); i++)\n        if (fs->_full_line_infos[i]._op >= instructionIndex) {\n            printf(\"OPTIMIZER: %s  %s:%d\\n\", message, _stringval(fs->_sourcename), fs->_full_line_infos[i]._line);\n            return;\n        }\n    if (fs->_full_line_infos.size() > 0)\n        printf(\"OPTIMIZER: %s  %s:%d\\n\", message, _stringval(fs->_sourcename), fs->_full_line_infos.top()._line);\n }\n#endif\n\n\nbool SQOptimizer::isUnsafeJumpRange(int start, int count) const\n{\n    for (int i = 0, ie = jumps.size(); i < ie; i++) {\n        int to = jumps[i].jumpTo;\n        if (to > start && to < start + count)\n            return true;\n    }\n    return false;\n}\n\nbool SQOptimizer::isLocalVarInstructions(int start, int count) const\n{\n    for (int i = 0, ie = fs->_localvarinfos.size(); i < ie; i++) {\n        int pos = int(fs->_localvarinfos[i]._start_op);\n        if (pos > start && pos < start + count)\n            return true;\n    }\n\n    return false;\n}\n\nbool SQOptimizer::isUnsafeRange(int start, int count) const\n{\n    return isUnsafeJumpRange(start, count) || isLocalVarInstructions(start, count);\n}\n\nbool SQOptimizer::isLocalVarRegister(int reg, int instrIndex) const\n{\n    for (int i = 0, ie = fs->_localvarinfos.size(); i < ie; i++) {\n        const SQLocalVarInfo & v = fs->_localvarinfos[i];\n        if ((int)v._pos == reg && (int)v._start_op <= instrIndex &&\n            (v._end_op == UINT32_MINUS_ONE || (int)v._end_op > instrIndex))\n            return true;\n    }\n    return false;\n}\n\nvoid SQOptimizer::cutRange(int start, int old_count, int new_count)\n{\n    assert(new_count < old_count);\n    int tmpStart = start + new_count;\n    int tmpCount = old_count - new_count;\n    //printf(\"cut: start=%d count=%d\\n\", tmpStart, tmpCount);\n    for (int i = 0; i < jumps.size(); i++) {\n        if (jumps[i].jumpTo >= tmpStart + 1) {\n            jumps[i].jumpTo -= tmpCount;\n            jumps[i].modified = true;\n        }\n        if (jumps[i].instructionIndex >= tmpStart) {\n            jumps[i].instructionIndex -= tmpCount;\n            jumps[i].modified = true;\n        }\n    }\n\n    memmove(&fs->_instructions[tmpStart], &fs->_instructions[tmpStart + tmpCount],\n        sizeof(fs->_instructions[0]) * (fs->_instructions.size() - tmpStart - tmpCount));\n    fs->_instructions.resize(fs->_instructions.size() - tmpCount);\n\n    for (int i = 0; i < fs->_localvarinfos.size(); i++) {\n        SQLocalVarInfo & varinfo = fs->_localvarinfos[i];\n        if (varinfo._start_op > tmpStart) {\n            if (varinfo._end_op < varinfo._start_op) {\n                varinfo._end_op = varinfo._start_op - tmpCount - 1;\n                if (varinfo._end_op > tmpStart)\n                    varinfo._end_op = 0;\n            }\n            varinfo._start_op -= tmpCount;\n        }\n        if (varinfo._end_op >= tmpStart && varinfo._end_op != UINT32_MINUS_ONE) {\n            int n = int(varinfo._end_op) - tmpCount;\n            if (n < tmpStart - 1)\n                n = tmpStart - 1;\n            if (n < 0)\n                n = 0;\n            varinfo._end_op = n;\n        }\n    }\n\n    for (int i = 0; i < fs->_full_line_infos.size(); i++)\n        if (fs->_full_line_infos[i]._op > tmpStart)\n            fs->_full_line_infos[i]._op -= tmpCount;\n\n    codeChanged = true;\n}\n\n\nvoid SQOptimizer::optimizeConstFolding()\n{\n    SQInstructionVec & instr = fs->_instructions;\n    bool changed = false;\n    for (int i = 0; i + 2 < instr.size(); i++) {\n        do {\n            changed = false;\n            if (i + 3 < instr.size()) {\n                const SQInstruction & operation = instr[i + 2];\n                const SQInstruction & loadA = instr[i];\n                const SQInstruction & loadB = instr[i + 1];\n                int s = operation.op;\n\n                if ((s == _OP_ADD || s == _OP_SUB || s == _OP_MUL || s == _OP_DIV || s == _OP_MOD || s == _OP_BITW) &&\n                        (loadA.op == _OP_LOADINT || loadA.op == _OP_LOADFLOAT) &&\n                        (loadB.op == _OP_LOADINT || loadB.op == _OP_LOADFLOAT) &&\n                        loadA._arg0 != loadB._arg0 &&\n                        ((loadB._arg0 == operation._arg2 && loadA._arg0 == operation._arg1) ||\n                        (loadB._arg0 == operation._arg1 && loadA._arg0 == operation._arg2))\n                        && !isUnsafeJumpRange(i, 3)) {\n\n                    bool applyOpt = true;\n                    const bool reversed = (loadB._arg0 == operation._arg2 && loadA._arg0 == operation._arg1);\n                    bool removeLoadAVar = false, removeLoadBVar = false;\n                    if (!isLocalVarInstructions(i, 3))\n                        removeLoadAVar = removeLoadBVar = true;\n                    else if (!isLocalVarInstructions(i, 2))\n                        removeLoadAVar = true;\n                    else if (!isLocalVarInstructions(i + 1, 2))\n                        removeLoadBVar = true;\n                    if (removeLoadAVar && isLocalVarRegister(loadA._arg0, i))\n                        removeLoadAVar = false;\n                    if (removeLoadBVar && isLocalVarRegister(loadB._arg0, i + 1))\n                        removeLoadBVar = false;\n                    if (removeLoadAVar && !removeLoadBVar)\n                        removeLoadAVar = false;\n                    const int targetInst = removeLoadAVar ? i : removeLoadBVar ? i + 1 : i + 2;\n\n                    if (loadA.op == _OP_LOADINT && loadB.op == _OP_LOADINT) {\n                        SQInteger res = 0;\n                        SQInt32 lv = loadA._arg1;\n                        SQInt32 rv = loadB._arg1;\n                        if (reversed)\n                        {\n                            SQInt32 t = lv; lv = rv; rv = t;\n                        }\n                        switch (s) {\n                            case _OP_ADD: res = SQInteger(lv) + SQInteger(rv); break;\n                            case _OP_SUB: res = SQInteger(lv) - SQInteger(rv); break;\n                            case _OP_MUL: res = SQInteger(lv) * SQInteger(rv); break;\n                            case _OP_DIV:\n                                if (rv < -1 || rv > 0)\n                                    res = lv / rv;\n                                else\n                                    applyOpt = false;\n                                break;\n                            case _OP_MOD:\n                                if (rv < -1 || rv > 0)\n                                    res = lv % rv;\n                                else\n                                    applyOpt = false;\n                                break;\n                            case _OP_BITW:\n                                switch (operation._arg3) {\n                                    case BW_AND: res = lv & rv; break;\n                                    case BW_OR: res = lv | rv; break;\n                                    case BW_XOR: res = lv ^ rv; break;\n                                    case BW_SHIFTL: res = sq_safe_shift_left(SQInteger(lv), rv); break;\n                                    default: applyOpt = false; break;\n                                }\n                                break;\n\n                            default: applyOpt = false; break;\n                        }\n\n                        if (applyOpt) {\n                            instr[targetInst]._arg0 = operation._arg0;\n                            if (res < SQInteger(INT_MIN) || res > SQInteger(INT_MAX))\n                            {\n                                instr[targetInst].op = _OP_LOAD;\n                                instr[targetInst]._arg1 = fs->GetNumericConstant(res);\n                            } else {\n                                instr[targetInst].op = _OP_LOADINT;\n                                instr[targetInst]._arg1 = (SQInt32)res;\n                            }\n                            changed = true;\n                            codeChanged = true;\n                            #ifdef _DEBUG_DUMP\n                                debugPrintInstructionPos(\"Const folding\", i);\n                            #endif\n                        }\n                    } else { // float\n                        assert(sizeof(SQFloat) == sizeof(SQInt32));\n                        SQFloat res = 0;\n                        SQFloat lv = (loadA.op == _OP_LOADFLOAT) ? loadA._farg1 : SQFloat(loadA._arg1);\n                        SQFloat rv = (loadB.op == _OP_LOADFLOAT) ? loadB._farg1 : SQFloat(loadB._arg1);\n                        if (reversed)\n                        {\n                            SQFloat t = lv; lv = rv; rv = t;\n                        }\n                        switch (s) {\n                            case _OP_ADD: res = lv + rv; break;\n                            case _OP_SUB: res = lv - rv; break;\n                            case _OP_MUL: res = lv * rv; break;\n                            case _OP_DIV:\n                                if (rv != 0)\n                                    res = lv / rv;\n                                else\n                                    applyOpt = false;\n                                break;\n                            default: applyOpt = false; break;\n                        }\n\n                        if (applyOpt) {\n                            instr[targetInst].op = _OP_LOADFLOAT;\n                            instr[targetInst]._farg1 = res;\n                            instr[targetInst]._arg0 = operation._arg0;\n                            changed = true;\n                            codeChanged = true;\n                            #ifdef _DEBUG_DUMP\n                                debugPrintInstructionPos(\"Const folding\", i);\n                            #endif\n                        }\n                    }\n                    if (applyOpt && (removeLoadAVar || removeLoadBVar))\n                    {\n                        if (removeLoadAVar && removeLoadBVar)\n                            cutRange(i, 3, 1);\n                        else\n                        {\n                            if (removeLoadAVar)\n                                cutRange(i, 1, 0);\n                            cutRange(i + 1, 2, 1);\n                        }\n                    }\n                }\n            }\n            if (i + 2 < instr.size()) {\n                const SQInstruction operation = instr[i + 1];\n                const SQInstruction loadA = instr[i];\n                int s = operation.op;\n\n                if (s == _OP_ADDI && (loadA.op == _OP_LOADINT || loadA.op == _OP_LOADFLOAT) && loadA._arg0 == operation._arg2 && !isUnsafeJumpRange(i, 2)){\n                    bool applyOpt = true;\n                    bool removeLoadAVar = !isLocalVarInstructions(i, 2);\n                    if (removeLoadAVar && isLocalVarRegister(loadA._arg0, i))\n                        removeLoadAVar = false;\n                    const int targetInst = removeLoadAVar ? i : i + 1;\n\n                    if (loadA.op == _OP_LOADINT) {\n                        SQInteger res = 0;\n                        SQInt32 lv = loadA._arg1;\n                        SQInt32 rv = operation._arg1;\n                        switch (s) { // -V785\n                            case _OP_ADDI: res = SQInteger(lv) + SQInteger(rv); break;\n                            default: applyOpt = false; break;\n                        }\n\n                        if (applyOpt) { // -V547\n                            instr[targetInst]._arg0 = operation._arg0;\n                            if (res < SQInteger(INT_MIN) || res > SQInteger(INT_MAX))\n                            {\n                                instr[targetInst].op = _OP_LOAD;\n                                instr[targetInst]._arg1 = fs->GetNumericConstant(res);\n                            } else\n                            {\n                                instr[targetInst].op = _OP_LOADINT;\n                                instr[targetInst]._arg1 = (SQInt32)res;\n                            }\n                            changed = true;\n                            codeChanged = true;\n                            #ifdef _DEBUG_DUMP\n                                debugPrintInstructionPos(\"Const folding\", i);\n                            #endif\n                        }\n                    } else { // float\n                        assert(sizeof(SQFloat) == sizeof(SQInt32));\n                        SQFloat res = 0;\n                        SQFloat lv = loadA._farg1;\n                        SQFloat rv = SQFloat(operation._arg1);\n                        switch (s) { // -V785\n                            case _OP_ADDI: res = lv + rv; break;\n                            default: applyOpt = false; break;\n                        }\n\n                        if (applyOpt) { // -V547\n                            instr[targetInst].op = _OP_LOADFLOAT;\n                            instr[targetInst]._farg1 = res;\n                            instr[targetInst]._arg0 = operation._arg0;\n                            changed = true;\n                            codeChanged = true;\n                            #ifdef _DEBUG_DUMP\n                                debugPrintInstructionPos(\"Const folding\", i);\n                            #endif\n                        }\n                    }\n                    if (applyOpt && removeLoadAVar) // -V547\n                        cutRange(i, 2, 1);\n                }\n                if (s == _OP_JCMP && (loadA.op == _OP_LOADINT || loadA.op == _OP_LOADFLOAT || loadA.op == _OP_LOAD) &&\n                    loadA._arg0 == operation._arg0 &&\n                    loadA._arg0 != operation._arg2 &&\n                    ( loadA._arg1 <= 255 || (loadA.op != _OP_LOAD && operation._arg1 >= -128 && operation._arg1 <= 127) ) &&\n                    !isUnsafeJumpRange(i, 2))\n                {\n                    bool removeLoadAVar = !isLocalVarInstructions(i, 2);\n                    if (removeLoadAVar && isLocalVarRegister(loadA._arg0, i))\n                        removeLoadAVar = false;\n                    const int targetInst = removeLoadAVar ? i : i + 1;\n                    bool applyOpt = true;\n                    if (loadA.op == _OP_LOAD)\n                    {\n                        instr[targetInst]._arg1 = operation._arg1;\n                        instr[targetInst]._arg2 = operation._arg2;\n                        instr[targetInst]._arg3 = operation._arg3;\n                        instr[targetInst]._arg0 = loadA._arg1;\n                        instr[targetInst].op = _OP_JCMPK;\n                    } else if (operation._arg1 < -128 || operation._arg1 > 127) // we can't fit into JCMP(I|F) due to big jump distance\n                    {\n                        const uint32_t constI = fs->GetConstant(loadA.op == _OP_LOADFLOAT ? SQObjectPtr(loadA._farg1) : SQObjectPtr((SQInteger)loadA._arg1), 255);\n                        if (constI <= 255u)\n                        {\n                            instr[targetInst]._arg1 = operation._arg1;\n                            instr[targetInst]._arg2 = operation._arg2;\n                            instr[targetInst]._arg3 = operation._arg3;\n                            instr[targetInst]._arg0 = constI;\n                            instr[targetInst].op = _OP_JCMPK;\n                        } else\n                            applyOpt = false;\n                    } else {\n                        instr[targetInst]._arg3 = operation._arg3; // cmp type\n                        instr[targetInst]._arg1 = loadA._arg1; // compare value\n                        instr[targetInst]._arg2 = operation._arg2;\n                        instr[targetInst]._arg0 = operation._arg1;  // jump target\n                        instr[targetInst].op = loadA.op == _OP_LOADINT ? _OP_JCMPI : _OP_JCMPF;\n                    }\n                    if (applyOpt)\n                    {\n                        if (removeLoadAVar)\n                            cutRange(i, 2, 1);\n                        const bool convertJumpTarget = instr[targetInst].op == _OP_JCMPI || instr[targetInst].op == _OP_JCMPF;\n                        if (convertJumpTarget)\n                            for (int ji = 0, jie = jumps.size(); ji < jie; ji++)\n                            {\n                                if (jumps[ji].instructionIndex == targetInst)\n                                {\n                                    assert(jumps[ji].jumpArg == JumpArg::JUMP_ARG1);\n                                    jumps[ji].jumpArg = JumpArg::JUMP_ARG0;\n                                    break;\n                                }\n                            }\n                        changed = true;\n                        codeChanged = true;\n                        #ifdef _DEBUG_DUMP\n                            debugPrintInstructionPos(\"Jump Const folding\", i);\n                        #endif\n                    }\n\n                }\n            }\n\n        } while (changed && i + 2 < instr.size());\n    }\n}\n\n\nvoid SQOptimizer::optimizeJumpFolding()\n{\n    SQInstructionVec & instr = fs->_instructions;\n    bool changed = true;\n    for (int pass = 0; pass < 4 && changed; pass++) {\n        changed = false;\n        for (int i = 0; i < instr.size(); i++) {\n            int op = instr[i].op;\n            if (op == _OP_JMP || op == _OP_JCMP || op == _OP_JCMPK || op == _OP_JZ || op == _OP_AND || op == _OP_OR || op == _OP_PUSHTRAP) {\n                int to = (i + instr[i]._arg1 + 1);\n                if (instr[to].op == _OP_JMP) {\n                    changed = true;\n                    codeChanged = true;\n                    instr[i]._arg1 += instr[to]._arg1 + 1;\n                    #ifdef _DEBUG_DUMP\n                        debugPrintInstructionPos(\"Jump folding\", i);\n                    #endif\n                }\n            }\n            if (op == _OP_JCMPI || op == _OP_JCMPF) {\n                int to = (i + instr[i]._sarg0() + 1);\n                if (instr[to].op == _OP_JMP) {\n                    const int nextJumpOfs = instr[i]._sarg0() + instr[to]._arg1 + 1;\n                    if (nextJumpOfs >= -128 && nextJumpOfs <= 127)\n                    {\n                        changed = true;\n                        codeChanged = true;\n                        instr[i]._arg0 = nextJumpOfs;\n                        #ifdef _DEBUG_DUMP\n                            debugPrintInstructionPos(\"Jump folding\", i);\n                        #endif\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid SQOptimizer::optimizeEmptyJumps()\n{\n    SQInstructionVec & instr = fs->_instructions;\n    if (!instr.size())\n        return;\n\n    for (int i = instr.size() - 1; i > 0; i--) {\n        int op = instr[i].op;\n        if (op == _OP_JMP && instr[i]._arg1 == 0) {\n            codeChanged = true;\n            cutRange(i, 1, 0);\n            #ifdef _DEBUG_DUMP\n                debugPrintInstructionPos(\"Empty jump\", i);\n            #endif\n        }\n    }\n}\n\nvoid SQOptimizer::optimize()\n{\n    codeChanged = true;\n    for (int pass = 0; pass < 2 && codeChanged; pass++) {\n        jumps.resize(0);\n        SQInstructionVec & instr = fs->_instructions;\n        for (int i = 0; i < instr.size(); i++)\n            switch (instr[i].op) {\n                case _OP_JMP:\n                case _OP_JCMP:\n                case _OP_JCMPK:\n                case _OP_JZ:\n                case _OP_AND:\n                case _OP_OR:\n                case _OP_PUSHTRAP:\n                case _OP_FOREACH:\n                case _OP_PREFOREACH:\n                case _OP_POSTFOREACH:\n                    jumps.push_back({i, i, i + instr[i]._arg1 + 1, i + instr[i]._arg1 + 1, false, JumpArg::JUMP_ARG1});\n                    break;\n                case _OP_JCMPI:\n                case _OP_JCMPF:\n                    jumps.push_back({i, i, i + instr[i]._sarg0() + 1, i + instr[i]._sarg0() + 1, false, JumpArg::JUMP_ARG0});\n                    break;\n                case _OP_NULLCOALESCE:\n                    jumps.push_back({i, i, i + instr[i]._arg1, i + instr[i]._arg1, false, JumpArg::JUMP_ARG1});\n                    break;\n\n                case _OP_DATA_NOP: {\n                        int saveInstr = i + ((instr[i]._arg2 << 8) + instr[i]._arg3);\n                        if ((instr[i]._arg0 || instr[i]._arg1 || instr[i]._arg2 || instr[i]._arg3) && saveInstr > 0 && saveInstr < instr.size() &&\n                            instr[saveInstr].op == _OP_SAVE_STATIC_MEMO)\n                        {\n                            int loadInstr = saveInstr + 1 - ((instr[saveInstr]._arg2 << 8) + instr[saveInstr]._arg3);\n                            if (loadInstr == i)\n                                jumps.push_back({i, i, saveInstr + 1, saveInstr + 1, false, JumpArg::JUMP_ARG_PLUS_23});\n                        }\n                    }\n                    break;\n\n                case _OP_SAVE_STATIC_MEMO: {\n                        int loadInstr = i + 1 - ((instr[i]._arg2 << 8) + instr[i]._arg3);\n                        jumps.push_back({i, i, loadInstr, loadInstr, false, JumpArg::JUMP_ARG_MINUS_23});\n                    }\n                    break;\n\n\n                default:\n                    break;\n            }\n\n        codeChanged = false;\n        optimizeConstFolding();\n        optimizeEmptyJumps();\n\n        if (codeChanged)\n            for (int i = 0; i < jumps.size(); i++)\n                if (jumps[i].modified) {\n                    const int change = (jumps[i].jumpTo - jumps[i].originalJumpTo) - (jumps[i].instructionIndex - jumps[i].originalInstructionIndex);\n                    if (jumps[i].jumpArg == JumpArg::JUMP_ARG1)\n                        instr[jumps[i].instructionIndex]._arg1 += change;\n                    else if (jumps[i].jumpArg == JumpArg::JUMP_ARG0) {\n                        const SQInstruction originalJump = instr[jumps[i].instructionIndex];\n                        const int nextJumpVal = originalJump._sarg0() + change;\n                        if (nextJumpVal >= -128 && nextJumpVal <= 127)\n                        {\n                            instr[jumps[i].instructionIndex]._arg0 = nextJumpVal; // still fit\n                        } else if (instr[jumps[i].instructionIndex].op == _OP_JCMPF || instr[jumps[i].instructionIndex].op == _OP_JCMPI) {\n                            const uint32_t constI = fs->GetConstant(instr[jumps[i].instructionIndex].op == _OP_JCMPF ? SQObjectPtr(originalJump._farg1) : SQObjectPtr((SQInteger)originalJump._arg1), 255);\n                            if (constI <= 255u) // we still fit in const table\n                            {\n                              jumps[i].jumpArg = JumpArg::JUMP_ARG1;\n                              instr[jumps[i].instructionIndex]._arg1 = nextJumpVal;\n                              instr[jumps[i].instructionIndex]._arg0 = constI;\n                              instr[jumps[i].instructionIndex].op = _OP_JCMPK;\n                            } else\n                              assert(0);//todo: we need to convert back to OP_JCMP, and we need to generate load instruction for that\n                        } else\n                          assert(0);//todo: we need to convert back to OP_JCMP, and we need to generate load instruction for that\n                    }\n                    else if (jumps[i].jumpArg == JumpArg::JUMP_ARG_PLUS_23) {\n                        SQInstruction & ci = instr[jumps[i].instructionIndex];\n                        int jmp = (ci._arg2 << 8) + ci._arg3;\n                        jmp += change;\n                        assert(jmp > 0 && jmp < 0xFFFF);\n                        ci._arg2 = jmp >> 8;\n                        ci._arg3 = jmp & 0xFF;\n                    }\n                    else if (jumps[i].jumpArg == JumpArg::JUMP_ARG_MINUS_23) {\n                        SQInstruction & ci = instr[jumps[i].instructionIndex];\n                        int jmp = (ci._arg2 << 8) + ci._arg3;\n                        jmp -= change;\n                        assert(jmp > 0 && jmp < 0xFFFF);\n                        ci._arg2 = jmp >> 8;\n                        ci._arg3 = jmp & 0xFF;\n                    }\n                    else\n                      assert(0);\n                }\n    }\n\n    optimizeJumpFolding();\n\n#ifdef _DEBUG_DUMP\n    for (int i = 0; i < jumps.size(); i++)\n        printf(\"JUMPS:  instruction: %d  to: %d\\n\", jumps[i].instructionIndex, jumps[i].jumpTo);\n#endif\n\n}\n\n\n"
  },
  {
    "path": "squirrel/compiler/optimizer.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQOPTIMIZER_H_\n#define _SQOPTIMIZER_H_\n///////////////////////////////////\n#include \"sqfuncstate.h\"\n\n\nstruct SQOptimizer\n{\n    SQOptimizer(SQFuncState & func_state);\n    void optimize();\n\nprivate:\n    bool isUnsafeRange(int start, int count) const;\n    bool isUnsafeJumpRange(int start, int count) const;\n    bool isLocalVarInstructions(int start, int count) const;\n    bool isLocalVarRegister(int reg, int instrIndex) const;\n    void cutRange(int start, int old_count, int new_count);\n\n    void optimizeConstFolding();\n    void optimizeJumpFolding();\n    void optimizeEmptyJumps();\n    enum class JumpArg : uint8_t {JUMP_ARG1, JUMP_ARG0, JUMP_ARG_PLUS_23, JUMP_ARG_MINUS_23};\n    struct Jump {\n        int originalInstructionIndex;\n        int instructionIndex;\n        int originalJumpTo;\n        int jumpTo;\n        bool modified;\n        JumpArg jumpArg;\n    };\n    sqvector<Jump> jumps;\n    SQFuncState * fs;\n\n    bool codeChanged;\n\n#ifdef _DEBUG_DUMP\n    void debugPrintInstructionPos(const char * message, int instructionIndex);\n#endif\n};\n\n\n#endif // _SQOPTIMIZER_H_\n\n"
  },
  {
    "path": "squirrel/compiler/parser.cpp",
    "content": "#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include \"opcodes.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"parser.h\"\n#include \"compiler.h\"\n#include \"compilationcontext.h\"\n#include \"sqtypeparser.h\"\n#include <stdarg.h>\n#include <sq_char_class.h>\n\nnamespace SQCompilation {\n\nstruct NestingChecker {\n    SQParser *_p;\n    const uint32_t _max_depth;\n    uint32_t _depth;\n    NestingChecker(SQParser *p) : _p(p), _depth(0), _max_depth(500) {\n        inc();\n    }\n\n    ~NestingChecker() {\n        _p->_depth -= _depth;\n    }\n\n    void inc() {\n        if (_p->_depth > _max_depth) {\n            _p->reportDiagnostic(DiagnosticsId::DI_TOO_BIG_AST);\n        }\n        _p->_depth += 1;\n        _depth += 1;\n    }\n};\n\nSQParser::SQParser(SQVM *v, const char *sourceText, size_t sourceTextSize, const char* sourcename, Arena *astArena, SQCompilationContext &ctx, Comments *comments)\n    : _lex(_ss(v), ctx, comments)\n    , _ctx(ctx)\n    , _astArena(astArena)\n    , _docObjectStack(astArena)\n{\n    _vm=v;\n    _lex.Init(sourceText, sourceTextSize);\n    _sourcename = sourcename;\n    _expression_context = SQE_REGULAR;\n    _lang_features = _ss(v)->defaultLangFeatures;\n    _depth = 0;\n    _token = 0;\n    _docObjectStack.push_back(&_moduleDocObject);\n}\n\n\nvoid SQParser::reportDiagnostic(int32_t id, ...) {\n    va_list vargs;\n    va_start(vargs, id);\n\n    SourceSpan span = _lex.tokenSpan();\n    _ctx.vreportDiagnostic((enum DiagnosticsId)id, span.start.line, span.start.column, span.textWidth(), vargs);\n\n    va_end(vargs);\n}\n\n\nbool SQParser::ProcessPosDirective()\n{\n    const char *sval = _lex._svalue;\n    if (strncmp(sval, \"pos:\", 4) != 0)\n        return false;\n\n    sval += 4;\n    if (!sq_isdigit(*sval))\n        reportDiagnostic(DiagnosticsId::DI_EXPECTED_LINENUM);\n    char * next = NULL;\n    _lex._currentline = scstrtol(sval, &next, 10);\n    if (!next || *next != ':') {\n        reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \":\");\n        return false;\n    }\n    next++;\n    if (!sq_isdigit(*next))\n        reportDiagnostic(DiagnosticsId::DI_EXPECTED_COLNUM);\n    _lex._currentcolumn = scstrtol(next, NULL, 10);\n    return true;\n}\n\nstruct SQPragmaDescriptor {\n  const char *id;\n  SQInteger setFlags, clearFlags;\n};\n\nstatic const SQPragmaDescriptor pragmaDescriptors[] = {\n  { \"strict\", LF_STRICT, 0 },\n  { \"relaxed\", 0, LF_STRICT },\n  { \"forbid-root-table\", LF_FORBID_ROOT_TABLE, 0 },\n  { \"allow-root-table\", 0, LF_FORBID_ROOT_TABLE },\n  { \"disable-optimizer\", LF_DISABLE_OPTIMIZER, 0 },\n  { \"enable-optimizer\", 0, LF_DISABLE_OPTIMIZER },\n  { \"forbid-delete-operator\", LF_FORBID_DELETE_OP, 0 },\n  { \"allow-delete-operator\", 0, LF_FORBID_DELETE_OP },\n  { \"forbid-clone-operator\", LF_FORBID_CLONE_OP, 0 },\n  { \"allow-clone-operator\", 0, LF_FORBID_CLONE_OP },\n  { \"forbid-switch-statement\", LF_FORBID_SWITCH_STMT, 0 },\n  { \"allow-switch-statement\", 0, LF_FORBID_SWITCH_STMT },\n  { \"forbid-implicit-type-methods\", LF_FORBID_IMPLICIT_TYPE_METHODS, 0 },\n  { \"allow-implicit-type-methods\", 0, LF_FORBID_IMPLICIT_TYPE_METHODS },\n  { \"forbid-auto-freeze\", 0, LF_ALLOW_AUTO_FREEZE },\n  { \"allow-auto-freeze\", LF_ALLOW_AUTO_FREEZE, 0 },\n  { \"forbid-compiler-internals\", 0, LF_ALLOW_COMPILER_INTERNALS },\n  { \"allow-compiler-internals\", LF_ALLOW_COMPILER_INTERNALS, 0 },\n};\n\nStatement* SQParser::parseDirectiveStatement()\n{\n    const char *sval = _lex._svalue;\n\n    bool applyToDefault = false;\n    if (strncmp(sval, \"default:\", 8) == 0) {\n        applyToDefault = true;\n        sval += 8;\n    }\n\n    const SQPragmaDescriptor *pragmaDesc = nullptr;\n\n    for (const auto &desc : pragmaDescriptors) {\n      if (strcmp(sval, desc.id) == 0) {\n        pragmaDesc = &desc;\n        break;\n      }\n    }\n\n    if (pragmaDesc == nullptr) {\n      reportDiagnostic(DiagnosticsId::DI_UNSUPPORTED_DIRECTIVE, sval);\n      return nullptr;\n    }\n\n    SQInteger setFlags = pragmaDesc->setFlags, clearFlags = pragmaDesc->clearFlags;\n\n    DirectiveStmt *d = newNode<DirectiveStmt>(_lex.tokenSpan());\n    d->applyToDefault = applyToDefault;\n    d->setFlags = setFlags;\n    d->clearFlags = clearFlags;\n\n    _lang_features = (_lang_features | setFlags) & ~clearFlags;\n    if (applyToDefault)\n        _ss(_vm)->defaultLangFeatures = (_ss(_vm)->defaultLangFeatures | setFlags) & ~clearFlags;\n\n    Lex();\n    return d;\n}\n\nvoid SQParser::checkBraceIndentationStyle()\n{\n  if (_token == '{' && (_lex._prevflags & TF_PREP_EOL))\n    reportDiagnostic(DiagnosticsId::DI_EGYPT_BRACES);\n}\n\nvoid SQParser::Lex()\n{\n    _token = _lex.Lex();\n\n    while (_token == TK_DIRECTIVE)\n    {\n        bool endOfLine = (_lex._prevtoken == '\\n');\n        if (ProcessPosDirective()) {\n            _token = _lex.Lex();\n            if (endOfLine)\n                _lex._prevtoken = '\\n';\n        } else\n            break;\n    }\n\n    const bool forceIdentifier =\n           (_token == TK_CLONE && (_lang_features & LF_FORBID_CLONE_OP))\n        || ((_token == TK_SWITCH || _token == TK_CASE || _token == TK_DEFAULT) && (_lang_features & LF_FORBID_SWITCH_STMT));\n\n    if (forceIdentifier) {\n      _token = TK_IDENTIFIER;\n      _lex.SetStringValue();\n    }\n}\n\n\nExpr* SQParser::Expect(SQInteger tok)\n{\n    if(_token != tok) {\n        if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {\n            //do nothing\n        }\n        else {\n            if(tok > 255) {\n                const char *etypename;\n                switch(tok)\n                {\n                case TK_IDENTIFIER:\n                    etypename = \"IDENTIFIER\";\n                    break;\n                case TK_STRING_LITERAL:\n                    etypename = \"STRING_LITERAL\";\n                    break;\n                case TK_INTEGER:\n                    etypename = \"INTEGER\";\n                    break;\n                case TK_FLOAT:\n                    etypename = \"FLOAT\";\n                    break;\n                default:\n                    etypename = _lex.Tok2Str(tok);\n                }\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, etypename);\n            }\n            else {\n                char s[2] = {(char)tok, 0};\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, s);\n            }\n        }\n    }\n    Expr *ret = NULL;\n    switch(tok)\n    {\n    case TK_IDENTIFIER:\n        ret = newId(_lex._svalue);\n        break;\n    case TK_STRING_LITERAL:\n        ret = newStringLiteral(_lex._svalue);\n        break;\n    case TK_INTEGER:\n        ret = newNode<LiteralExpr>(_lex.tokenSpan(), _lex._nvalue);\n        break;\n    case TK_FLOAT:\n        ret = newNode<LiteralExpr>(_lex.tokenSpan(), _lex._fvalue);\n        break;\n    }\n    Lex();\n    return ret;\n}\n\n\nvoid SQParser::OptionalSemicolon()\n{\n    if(_token == ';') { Lex(); return; }\n    if(!IsEndOfStatement()) {\n        reportDiagnostic(DiagnosticsId::DI_END_OF_STMT_EXPECTED);\n    }\n}\n\n\nRootBlock* SQParser::parse()\n{\n    try {\n        Lex();\n        SourceLoc start = _lex.tokenStart();\n        RootBlock *rootBlock = newNode<RootBlock>(arena(), start);\n        while(_token > 0){\n            rootBlock->addStatement(parseStatement());\n            if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();\n        }\n        rootBlock->setSpanEnd(_lex.currentPos());\n        return rootBlock;\n    }\n    catch (SQCompilation::CompilerError &) {\n        return NULL;\n    }\n}\n\n\nBlock* SQParser::parseStatements(SourceLoc start)\n{\n    NestingChecker nc(this);\n    Block *result = newNode<Block>(arena(), start);\n    while(_token != '}' && _token != TK_DEFAULT && _token != TK_CASE) {\n        Statement *stmt = parseStatement();\n        result->addStatement(stmt);\n        if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();\n    }\n    result->setSpanEnd(_lex.currentPos());\n    return result;\n}\n\n\nvoid SQParser::onDocString(const char *doc_string)\n{\n    if (_docObjectStack.back()->getDocString() != nullptr)\n        reportDiagnostic(DiagnosticsId::DI_MULTIPLE_DOCSTRINGS);\n    else {\n        SQString *docStringCopy = SQString::Create(_ss(_vm), doc_string);\n        if (docStringCopy)\n            _docObjectStack.back()->setDocString(docStringCopy->_val);\n    }\n}\n\n\nStatement* SQParser::parseStatement(bool closeframe)\n{\n    NestingChecker nc(this);\n    Statement *result = NULL;\n\n    bool allowsImport = false;\n\n    switch(_token) {\n    case ';':\n        allowsImport = true;\n        result = newNode<EmptyStatement>(_lex.tokenSpan());\n        Lex();\n        break;\n    case TK_DOCSTRING: {\n        SourceSpan span = _lex.tokenSpan();\n        onDocString(_lex._svalue);\n        result = newNode<EmptyStatement>(span);\n        Lex();\n        break;\n    }\n    case TK_DIRECTIVE:\n        allowsImport = true;\n        result = parseDirectiveStatement();\n        break;\n    case TK_IF:     result = parseIfStatement();          break;\n    case TK_WHILE:  result = parseWhileStatement();       break;\n    case TK_DO:     result = parseDoWhileStatement();     break;\n    case TK_FOR:    result = parseForStatement();         break;\n    case TK_FOREACH:result = parseForEachStatement();     break;\n    case TK_SWITCH: result = parseSwitchStatement();      break;\n    case TK_LOCAL:\n    case TK_LET:\n        result = parseLocalDeclStatement();\n        break;\n    case TK_RETURN:\n    case TK_YIELD: {\n        bool isReturn = (_token == TK_RETURN);\n        SourceSpan keywordSpan = _lex.tokenSpan();\n        Lex();\n\n        Expr *arg = NULL;\n        if(!IsEndOfStatement()) {\n            arg = Expression(SQE_RVALUE);\n        }\n\n        if (isReturn) {\n            return newNode<ReturnStatement>(keywordSpan, arg);\n        } else {\n            return newNode<YieldStatement>(keywordSpan, arg);\n        }\n    }\n    case TK_BREAK: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        return newNode<BreakStatement>(span, nullptr);\n    }\n    case TK_CONTINUE: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        return newNode<ContinueStatement>(span, nullptr);\n    }\n    case TK_FUNCTION: {\n        SourceLoc funcStart = _lex.tokenStart();\n        result = parseLocalFunctionExprStmt(false, funcStart);\n        break;\n    }\n    case TK_CLASS: {\n        SourceLoc classStart = _lex.tokenStart();\n        result = parseLocalClassExprStmt(false, classStart);\n        break;\n    }\n    case TK_ENUM:\n        result = parseEnumStatement(false);\n        break;\n    case '{':\n    {\n        SQUnsignedInteger savedLangFeatures = _lang_features;\n        SourceLoc blockStart = _lex.tokenStart();\n        Lex();\n        Block *block = parseStatements(blockStart);\n        block->setSpanEnd(_lex.currentPos());\n        Expect('}');\n        _lang_features = savedLangFeatures;\n        result = block;\n        break;\n    }\n    case TK_TRY:\n        result = parseTryCatchStatement();\n        break;\n    case TK_THROW: {\n        SourceSpan keywordSpan = _lex.tokenSpan();\n        Lex();\n        Expr *e = Expression(SQE_RVALUE);\n        return newNode<ThrowStatement>(keywordSpan, e);\n    }\n    case TK_CONST:\n        result = parseConstStatement(false);\n        break;\n    case TK_GLOBAL: {\n        SourceLoc globalStart = _lex.tokenStart();\n        Lex();\n        if (_token == TK_CONST)\n            result = parseConstStatement(true, globalStart);\n        else if (_token == TK_ENUM)\n            result = parseEnumStatement(true, globalStart);\n        else\n            reportDiagnostic(DiagnosticsId::DI_GLOBAL_CONSTS_ONLY);\n        break;\n    }\n    default: {\n        // Check for contextual import keywords to switch parsing mode\n        if (_are_imports_still_allowed && _token == TK_IDENTIFIER) {\n            if (strcmp(_lex._svalue, \"import\") == 0 || strcmp(_lex._svalue, \"from\") == 0) {\n                allowsImport = true;\n                result = parseImportStatement();\n                break;\n            }\n        }\n        Expr *e = Expression(SQE_REGULAR);\n        return newNode<ExprStatement>(e);\n      }\n    }\n\n    assert(result);\n\n    if (!allowsImport)\n        _are_imports_still_allowed = false;\n\n    return result;\n}\n\n\nExpr* SQParser::parseCommaExpr(SQExpressionContext expression_context)\n{\n    NestingChecker nc(this);\n    Expr *expr = Expression(expression_context);\n\n    if (_token == ',') {\n        ArenaVector<Expr *> exprs(arena());\n        exprs.push_back(expr);\n        while (_token == ',') {\n            Lex();\n            exprs.push_back(Expression(expression_context));\n        }\n        expr = newNode<CommaExpr>(arena(), std::move(exprs));\n    }\n\n    return expr;\n}\n\n\nExpr* SQParser::Expression(SQExpressionContext expression_context)\n{\n    NestingChecker nc(this);\n    SQExpressionContext saved_expression_context = _expression_context;\n    _expression_context = expression_context;\n\n    Expr *expr = LogicalNullCoalesceExp();\n\n    switch(_token)  {\n    case '=':\n    case TK_NEWSLOT:\n    case TK_MINUSEQ:\n    case TK_PLUSEQ:\n    case TK_MULEQ:\n    case TK_DIVEQ:\n    case TK_MODEQ: {\n        SQInteger op = _token;\n        Lex();\n        Expr *e2 = Expression(SQE_RVALUE);\n\n        switch (op) {\n        case TK_NEWSLOT:\n            expr = newNode<BinExpr>(TO_NEWSLOT, expr, e2);\n            break;\n        case '=': //ASSIGN\n            switch (expression_context)\n            {\n            case SQE_IF:\n                reportDiagnostic(DiagnosticsId::DI_ASSIGN_INSIDE_FORBIDDEN, \"if\");\n                break;\n            case SQE_LOOP_CONDITION:\n                reportDiagnostic(DiagnosticsId::DI_ASSIGN_INSIDE_FORBIDDEN, \"loop condition\");\n                break;\n            case SQE_SWITCH:\n                reportDiagnostic(DiagnosticsId::DI_ASSIGN_INSIDE_FORBIDDEN, \"switch\");\n                break;\n            case SQE_FUNCTION_ARG:\n                reportDiagnostic(DiagnosticsId::DI_ASSIGN_INSIDE_FORBIDDEN, \"function argument\");\n                break;\n            case SQE_RVALUE:\n                reportDiagnostic(DiagnosticsId::DI_ASSIGN_INSIDE_FORBIDDEN, \"expression\");\n                break;\n            case SQE_ARRAY_ELEM:\n                reportDiagnostic(DiagnosticsId::DI_ASSIGN_INSIDE_FORBIDDEN, \"array element\");\n                break;\n            case SQE_REGULAR:\n                break;\n            }\n            expr = newNode<BinExpr>(TO_ASSIGN, expr, e2);\n            break;\n        case TK_MINUSEQ: expr = newNode<BinExpr>(TO_MINUSEQ, expr, e2); break;\n        case TK_PLUSEQ: expr = newNode<BinExpr>(TO_PLUSEQ, expr, e2); break;\n        case TK_MULEQ: expr = newNode<BinExpr>(TO_MULEQ, expr, e2); break;\n        case TK_DIVEQ: expr = newNode<BinExpr>(TO_DIVEQ, expr, e2); break;\n        case TK_MODEQ: expr = newNode<BinExpr>(TO_MODEQ, expr, e2); break;\n        }\n    }\n    break;\n    case '?': {\n        Consume('?');\n\n        Expr *ifTrue = Expression(SQE_RVALUE);\n\n        Expect(':');\n\n        Expr *ifFalse = Expression(SQE_RVALUE);\n\n        expr = newNode<TerExpr>(expr, ifTrue, ifFalse);\n    }\n    break;\n    }\n\n    _expression_context = saved_expression_context;\n    return expr;\n}\n\n\ntemplate<typename T> Expr* SQParser::BIN_EXP(T f, enum TreeOp top, Expr *lhs)\n{\n\n    SQInteger prevTok = _lex._prevtoken, tok = _token;\n    unsigned prevFlags = _lex._prevflags;\n\n    Lex();\n\n    checkSuspiciousUnaryOp(prevTok, tok, prevFlags);\n\n    SQExpressionContext old = _expression_context;\n    _expression_context = SQE_RVALUE;\n\n    Expr *rhs = (this->*f)();\n\n    _expression_context = old;\n\n    return newNode<BinExpr>(top, lhs, rhs);\n}\n\n\nExpr* SQParser::LogicalNullCoalesceExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = LogicalOrExp();\n    for (;;) {\n        nc.inc();\n        if (_token == TK_NULLCOALESCE) {\n            Lex();\n\n            Expr *rhs = LogicalNullCoalesceExp();\n            lhs = newNode<BinExpr>(TO_NULLC, lhs, rhs);\n        }\n        else return lhs;\n    }\n}\n\n\nExpr* SQParser::LogicalOrExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = LogicalAndExp();\n    for (;;) {\n        nc.inc();\n        if (_token == TK_OR) {\n            Lex();\n\n            Expr *rhs = LogicalOrExp();\n            lhs = newNode<BinExpr>(TO_OROR, lhs, rhs);\n        }\n        else return lhs;\n    }\n}\n\nExpr* SQParser::LogicalAndExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = BitwiseOrExp();\n    for (;;) {\n        nc.inc();\n        switch (_token) {\n        case TK_AND: {\n            Lex();\n\n            Expr *rhs = LogicalAndExp();\n            lhs = newNode<BinExpr>(TO_ANDAND, lhs, rhs);\n        }\n        default:\n            return lhs;\n        }\n    }\n}\n\nExpr* SQParser::BitwiseOrExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = BitwiseXorExp();\n    for (;;) {\n        nc.inc();\n        if (_token == '|') {\n            return BIN_EXP(&SQParser::BitwiseOrExp, TO_OR, lhs);\n        }\n        else return lhs;\n    }\n}\n\nExpr* SQParser::BitwiseXorExp()\n{\n    NestingChecker nc(this);\n    Expr * lhs = BitwiseAndExp();\n    for (;;) {\n        nc.inc();\n        if (_token == '^') {\n            lhs = BIN_EXP(&SQParser::BitwiseAndExp, TO_XOR, lhs);\n        }\n        else return lhs;\n    }\n}\n\nExpr* SQParser::BitwiseAndExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = EqExp();\n    for (;;) {\n        nc.inc();\n        if (_token == '&') {\n            lhs = BIN_EXP(&SQParser::EqExp, TO_AND, lhs);\n        }\n        else return lhs;\n    }\n}\n\nExpr* SQParser::EqExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = CompExp();\n    for (;;) {\n        nc.inc();\n        switch (_token) {\n        case TK_EQ: lhs = BIN_EXP(&SQParser::CompExp, TO_EQ, lhs); break;\n        case TK_NE: lhs = BIN_EXP(&SQParser::CompExp, TO_NE, lhs); break;\n        case TK_3WAYSCMP: lhs = BIN_EXP(&SQParser::CompExp, TO_3CMP, lhs); break;\n        default: return lhs;\n        }\n    }\n}\n\nExpr* SQParser::CompExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = ShiftExp();\n    for (;;) {\n        nc.inc();\n        switch (_token) {\n        case '>': lhs = BIN_EXP(&SQParser::ShiftExp, TO_GT, lhs); break;\n        case '<': lhs = BIN_EXP(&SQParser::ShiftExp, TO_LT, lhs); break;\n        case TK_GE: lhs = BIN_EXP(&SQParser::ShiftExp, TO_GE, lhs); break;\n        case TK_LE: lhs = BIN_EXP(&SQParser::ShiftExp, TO_LE, lhs); break;\n        case TK_IN: lhs = BIN_EXP(&SQParser::ShiftExp, TO_IN, lhs); break;\n        case TK_INSTANCEOF: lhs = BIN_EXP(&SQParser::ShiftExp, TO_INSTANCEOF, lhs); break;\n        case TK_NOT: {\n            SourceLoc notStart = _lex.tokenStart();\n            Lex();\n            if (_token == TK_IN) {\n                lhs = BIN_EXP(&SQParser::ShiftExp, TO_IN, lhs);\n                lhs = newNode<UnExpr>(TO_NOT, notStart, lhs);\n            }\n            else\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"in\");\n        }\n        default: return lhs;\n        }\n    }\n}\n\nExpr* SQParser::ShiftExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = PlusExp();\n    for (;;) {\n        nc.inc();\n        switch (_token) {\n        case TK_USHIFTR: lhs = BIN_EXP(&SQParser::PlusExp, TO_USHR, lhs); break;\n        case TK_SHIFTL: lhs = BIN_EXP(&SQParser::PlusExp, TO_SHL, lhs); break;\n        case TK_SHIFTR: lhs = BIN_EXP(&SQParser::PlusExp, TO_SHR, lhs); break;\n        default: return lhs;\n        }\n    }\n}\n\nvoid SQParser::checkSuspiciousUnaryOp(SQInteger pprevTok, SQInteger tok, unsigned pprevFlags) {\n  if (tok == '+' || tok == '-') {\n    if (_expression_context == SQE_ARRAY_ELEM || _expression_context == SQE_FUNCTION_ARG) {\n      if ((pprevFlags & (TF_PREP_EOL | TF_PREP_SPACE)) && (pprevTok != ',') && ((_lex._prevflags & TF_PREP_SPACE) == 0)) {\n        reportDiagnostic(DiagnosticsId::DI_NOT_UNARY_OP, tok == '+' ? \"+\" : \"-\");\n      }\n    }\n  }\n}\n\nExpr* SQParser::PlusExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = MultExp();\n    for (;;) {\n        nc.inc();\n        switch (_token) {\n        case '+': lhs = BIN_EXP(&SQParser::MultExp, TO_ADD, lhs); break;\n        case '-': lhs = BIN_EXP(&SQParser::MultExp, TO_SUB, lhs); break;\n\n        default: return lhs;\n        }\n    }\n}\n\nExpr* SQParser::MultExp()\n{\n    NestingChecker nc(this);\n    Expr *lhs = PrefixedExpr();\n    for (;;) {\n        nc.inc();\n        switch (_token) {\n        case '*': lhs = BIN_EXP(&SQParser::PrefixedExpr, TO_MUL, lhs); break;\n        case '/': lhs = BIN_EXP(&SQParser::PrefixedExpr, TO_DIV, lhs); break;\n        case '%': lhs = BIN_EXP(&SQParser::PrefixedExpr, TO_MOD, lhs); break;\n\n        default: return lhs;\n        }\n    }\n}\n\nvoid SQParser::checkSuspiciousBracket() {\n  assert(_token == '(' || _token == '[');\n  if (_expression_context == SQE_ARRAY_ELEM || _expression_context == SQE_FUNCTION_ARG) {\n    if (_lex._prevtoken != ',') {\n      if (_lex._prevflags & (TF_PREP_EOL | TF_PREP_SPACE)) {\n        char op[] = { (char)_token, '\\0' };\n        reportDiagnostic(DiagnosticsId::DI_SUSPICIOUS_BRACKET, op, _token == '(' ? \"function call\" : \"access to member\");\n      }\n    }\n  }\n}\n\nstatic const char *opname(SQInteger op) {\n  switch (op)\n  {\n    case '.': return \".\";\n    case TK_NULLGETSTR: return \"?.\";\n    case TK_TYPE_METHOD_GETSTR: return \".$\";\n    case TK_NULLABLE_TYPE_METHOD_GETSTR: return \"?.$\";\n    default: return \"<unknown>\";\n  }\n}\n\nExpr* SQParser::PrefixedExpr()\n{\n    NestingChecker nc(this);\n    //if 'pos' != -1 the previous variable is a local variable\n    SQInteger pos;\n    Expr *e = Factor(pos);\n    bool nextIsNullable = false;\n    for(;;) {\n        nc.inc();\n        switch(_token) {\n        case '.':\n        case TK_NULLGETSTR:\n        case TK_TYPE_METHOD_GETSTR:\n        case TK_NULLABLE_TYPE_METHOD_GETSTR: {\n            if (_token == TK_NULLGETSTR || _token == TK_NULLABLE_TYPE_METHOD_GETSTR || nextIsNullable) {\n                nextIsNullable = true;\n            }\n\n            bool isTypeMethod = _token == TK_TYPE_METHOD_GETSTR || _token == TK_NULLABLE_TYPE_METHOD_GETSTR;\n\n            SQInteger tok = _token;\n\n            Lex();\n\n            if ((_lex._prevflags & (TF_PREP_SPACE | TF_PREP_EOL)) != 0) {\n              reportDiagnostic(DiagnosticsId::DI_SPACE_SEP_FIELD_NAME, opname(tok));\n            }\n\n            Expr *receiver = e;\n            Id *id = (Id *)Expect(TK_IDENTIFIER);\n            assert(id);\n            // Use end from Id's span (after the identifier)\n            e = newNode<GetFieldExpr>(receiver, id->name(), nextIsNullable, isTypeMethod, id->sourceSpan().end); //-V522\n            break;\n        }\n        case '[':\n        case TK_NULLGETOBJ: {\n            if (_token == TK_NULLGETOBJ || nextIsNullable)\n            {\n                nextIsNullable = true;\n            }\n            if(_lex._prevtoken == '\\n')\n                reportDiagnostic(DiagnosticsId::DI_BROKEN_SLOT_DECLARATION);\n            if (_token == '[')\n              checkSuspiciousBracket();\n\n            Lex();\n            Expr *receiver = e;\n            Expr *key = Expression(SQE_RVALUE);\n            SourceLoc end = _lex.currentPos();\n            Expect(']');\n            e = newNode<GetSlotExpr>(receiver, key, nextIsNullable, end);\n            break;\n        }\n        case TK_MINUSMINUS:\n        case TK_PLUSPLUS:\n            {\n                nextIsNullable = false;\n                if(IsEndOfStatement()) return e;\n                SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;\n                SourceLoc opEnd = _lex.currentPos();\n                Lex();\n                e = newNode<IncExpr>(e, diff, IF_POSTFIX, opEnd);\n            }\n            return e;\n        case '(':\n        case TK_NULLCALL: {\n            if (_lex._prevflags & TF_PREP_EOL && _token == '(') {\n                reportDiagnostic(DiagnosticsId::DI_PAREN_IS_FUNC_CALL);\n            }\n            SQInteger nullcall = (_token==TK_NULLCALL || nextIsNullable);\n            nextIsNullable = !!nullcall;\n            CallExpr *call = newNode<CallExpr>(arena(), e, nullcall);\n\n            if (_token == '(')\n              checkSuspiciousBracket();\n\n            Lex();\n            while (_token != ')') {\n                call->addArgument(Expression(SQE_FUNCTION_ARG));\n                if (_token == ',') {\n                    Lex();\n                }\n            }\n\n            call->setSpanEnd(_lex.currentPos());\n            Lex();\n            e = call;\n            break;\n        }\n        default: return e;\n        }\n    }\n}\n\nstatic void appendStringData(sqvector<char> &dst, const char *b) {\n  while (*b) {\n    dst.push_back(*b++);\n  }\n}\n\nExpr *SQParser::parseStringTemplate() {\n\n    // '$' TK_TEMPLATE_PREFIX? (arg TK_TEMPLATE_INFIX)* arg? TK_TEMPLATE_SUFFX\n\n    _lex._state = LS_TEMPLATE;\n    _lex._expectedToken = TK_TEMPLATE_PREFIX;\n\n    Lex();\n    int idx = 0;\n\n    sqvector<char> formatString(_ctx.allocContext());\n    sqvector<Expr *> args(_ctx.allocContext());\n    char buffer[64] = {0};\n\n    SourceLoc fmtStart = _lex.tokenStart();\n    SQInteger tok = -1;\n\n    while ((tok = _token) != SQUIRREL_EOB) {\n\n      if (tok != TK_TEMPLATE_PREFIX && tok != TK_TEMPLATE_INFIX && tok != TK_TEMPLATE_SUFFIX) {\n          reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"STRING_LITERAL\");\n          return nullptr;\n      }\n\n      appendStringData(formatString, _lex._svalue);\n      if (tok != TK_TEMPLATE_SUFFIX) {\n        snprintf(buffer, sizeof buffer, \"%d\", idx++);\n        appendStringData(formatString, buffer);\n        _lex._expectedToken = -1;\n        _lex._state = LS_REGULAR;\n        Lex();\n        Expr *arg = Expression(SQE_FUNCTION_ARG);\n        args.push_back(arg);\n\n        if (_token != '}') {\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"}\");\n            return nullptr;\n        }\n\n        formatString.push_back('}');\n\n        _lex._state = LS_TEMPLATE;\n        _lex._expectedToken = TK_TEMPLATE_INFIX;\n      }\n      else {\n        break;\n      }\n      Lex();\n    }\n\n    formatString.push_back('\\0');\n\n    SourceLoc templateEnd = _lex.currentPos();\n\n    Expr *result = nullptr;\n    SourceSpan fmtSpan = {fmtStart, templateEnd};\n    LiteralExpr *fmt = newNode<LiteralExpr>(fmtSpan, copyString(&formatString[0]));\n\n    if (args.empty()) {\n      result = fmt;\n    }\n    else {\n      // GetFieldExpr: from fmt start to current position (synthetic .subst access)\n      Expr *callee = newNode<GetFieldExpr>(fmt, \"subst\", false, /* force type method */ true, templateEnd);\n      // CallExpr: from callee start to end of arguments (which is templateEnd for string templates)\n      CallExpr *call = newNode<CallExpr>(arena(), callee, false, templateEnd);\n\n      for (Expr *arg : args)\n        call->addArgument(arg);\n\n      result = call;\n    }\n\n    _lex._expectedToken = -1;\n    _lex._state = LS_REGULAR;\n    Lex();\n\n    return result;\n}\n\nExpr* SQParser::Factor(SQInteger &pos)\n{\n    NestingChecker nc(this);\n    Expr *r = NULL;\n\n    switch(_token)\n    {\n    case TK_STRING_LITERAL:\n        r = newStringLiteral(_lex._svalue);\n        Lex();\n        break;\n    case TK_TEMPLATE_OP:\n        r = parseStringTemplate();\n        break;\n    case TK_BASE: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        r = newNode<BaseExpr>(span);\n        break;\n    }\n    case TK_IDENTIFIER:\n        r = newId(_lex._svalue);\n        Lex();\n        break;\n    case TK_CONSTRUCTOR: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        r = newNode<Id>(span, \"constructor\");\n        break;\n    }\n    case TK_THIS: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        r = newNode<Id>(span, \"this\");\n        break;\n    }\n    case TK_DOUBLE_COLON: { // \"::\"\n        if (_lang_features & LF_FORBID_ROOT_TABLE)\n            reportDiagnostic(DiagnosticsId::DI_ROOT_TABLE_FORBIDDEN);\n        SourceSpan span = _lex.tokenSpan();\n        _token = '.'; /* hack: drop into PrefixExpr, case '.'*/\n        r = newNode<RootTableAccessExpr>(span);\n        break;\n    }\n    case TK_NULL: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        r = newNode<LiteralExpr>(span);\n        break;\n    }\n    case TK_INTEGER: {\n        SourceSpan span = _lex.tokenSpan();\n        SQInteger val = _lex._nvalue;\n        Lex();\n        r = newNode<LiteralExpr>(span, val);\n        break;\n    }\n    case TK_FLOAT: {\n        SourceSpan span = _lex.tokenSpan();\n        SQFloat val = _lex._fvalue;\n        Lex();\n        r = newNode<LiteralExpr>(span, val);\n        break;\n    }\n    case TK_TRUE: case TK_FALSE: {\n        SourceSpan span = _lex.tokenSpan();\n        bool val = (_token == TK_TRUE);\n        Lex();\n        r = newNode<LiteralExpr>(span, val);\n        break;\n    }\n    case '[': {\n            SourceLoc start = _lex.tokenStart();\n            Lex();\n            ArrayExpr *arr = newNode<ArrayExpr>(arena(), start);\n            bool commaSeparated = false;\n            bool spaceSeparated = false;\n            bool reported = false;\n            while(_token != ']') {\n                Expr *v = Expression(SQE_ARRAY_ELEM);\n                arr->addValue(v);\n                if (_token == ',') {\n                    commaSeparated = true;\n                }\n                else if (_token != ']') {\n                    spaceSeparated = true;\n                }\n\n                if (commaSeparated && spaceSeparated && !reported) {\n                    reported = true; // do not spam in output, a single diag seems to be enough\n                    reportDiagnostic(DiagnosticsId::DI_MIXED_SEPARATORS, \"elements of array\");\n                }\n\n                if (_token == ',') {\n                    Lex();\n                }\n            }\n            arr->setSpanEnd(_lex.currentPos());\n            Lex();\n            r = arr;\n        }\n        break;\n    case '{': {\n        SourceLoc start = _lex.tokenStart();\n        Lex();\n        TableExpr *t = newNode<TableExpr>(arena(), start);\n        _docObjectStack.push_back(&t->docObject);\n        ParseTableOrClass(t, ',', '}');\n        _docObjectStack.pop_back();\n        // TableExpr end is set by ParseTableOrClass via Lex() after '}'\n        r = t;\n        break;\n    }\n    case TK_FUNCTION:\n        r = FunctionExp(false);\n        break;\n    case '@':\n        r = FunctionExp(true);\n        break;\n    case TK_CLASS: {\n        SourceLoc classStart = _lex.tokenStart();\n        Lex();\n        r = ClassExp(classStart, NULL);\n        break;\n    }\n    case '-': {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        switch(_token) {\n        case TK_INTEGER: {\n            SourceSpan span = {opStart, _lex.currentPos()};\n            SQInteger val = -_lex._nvalue;\n            Lex();\n            r = newNode<LiteralExpr>(span, val);\n            break;\n        }\n        case TK_FLOAT: {\n            SourceSpan span = {opStart, _lex.currentPos()};\n            SQFloat val = -_lex._fvalue;\n            Lex();\n            r = newNode<LiteralExpr>(span, val);\n            break;\n        }\n        default:\n            r = newNode<UnExpr>(TO_NEG, opStart, PrefixedExpr());\n            break;\n        }\n        break;\n    }\n    case '!': {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        r = newNode<UnExpr>(TO_NOT, opStart, PrefixedExpr());\n        break;\n    }\n    case '~': {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        if(_token == TK_INTEGER)  {\n            SourceSpan span = {opStart, _lex.currentPos()};\n            SQInteger val = ~_lex._nvalue;\n            Lex();\n            r = newNode<LiteralExpr>(span, val);\n        }\n        else {\n            r = newNode<UnExpr>(TO_BNOT, opStart, PrefixedExpr());\n        }\n        break;\n    }\n    case TK_TYPEOF: {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        r = newNode<UnExpr>(TO_TYPEOF, opStart, PrefixedExpr());\n        break;\n    }\n    case TK_RESUME: {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        r = newNode<UnExpr>(TO_RESUME, opStart, PrefixedExpr());\n        break;\n    }\n    case TK_CLONE: {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        r = newNode<UnExpr>(TO_CLONE, opStart, PrefixedExpr());\n        break;\n    }\n    case TK_STATIC: {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        r = newNode<UnExpr>(TO_STATIC_MEMO, opStart, PrefixedExpr());\n        break;\n    }\n    case TK_CONST: {\n        SourceLoc opStart = _lex.tokenStart();\n        Lex();\n        r = newNode<UnExpr>(TO_INLINE_CONST, opStart, PrefixedExpr());\n        break;\n    }\n    case TK_MINUSMINUS :\n    case TK_PLUSPLUS :\n        r = PrefixIncDec(_token);\n        break;\n    case TK_DELETE :\n        if (_lang_features & LF_FORBID_DELETE_OP) {\n            reportDiagnostic(DiagnosticsId::DI_DELETE_OP_FORBIDDEN);\n        }\n        r = DeleteExpr();\n        break;\n    case '(': {\n        SourceLoc start = _lex.tokenStart();\n        Lex();\n        Expr *inner = Expression(_expression_context);\n        Expect(')');\n        r = newNode<UnExpr>(TO_PAREN, start, inner);\n        break;\n    }\n    case TK_CODE_BLOCK_EXPR: {\n        if ((_lang_features & LF_ALLOW_COMPILER_INTERNALS) == 0)\n            reportDiagnostic(DiagnosticsId::DI_COMPILER_INTERNALS_FORBIDDEN);\n        SQExpressionContext saved_expression_context = _expression_context;\n        _expression_context = SQE_REGULAR;\n        SQUnsignedInteger savedLangFeatures = _lang_features;\n        SourceLoc start = _lex.tokenStart();\n        Lex();\n        Block *blk = parseStatements(start);\n        blk->setIsExprBlock();\n        blk->setSpanEnd(_lex.currentPos());\n        r = newNode<CodeBlockExpr>(blk);\n        Expect('}');\n        _lang_features = savedLangFeatures;\n        _expression_context = saved_expression_context;\n        break;\n    }\n    case TK___LINE__: {\n        SourceSpan span = _lex.tokenSpan();\n        SQInteger val = _lex._currentline;\n        Lex();\n        r = newNode<LiteralExpr>(span, val);\n        break;\n    }\n    case TK___FILE__: {\n        SourceSpan span = _lex.tokenSpan();\n        Lex();\n        r = newNode<LiteralExpr>(span, _sourcename);\n        break;\n    }\n    default:\n        reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"expression\");\n    }\n    return r;\n}\n\nvoid SQParser::ParseTableOrClass(TableExpr *decl, SQInteger separator, SQInteger terminator)\n{\n    NestingChecker nc(this);\n    NewObjectType otype = separator==',' ? NEWOBJ_TABLE : NEWOBJ_CLASS;\n\n    while(_token != terminator) {\n        SourceSpan keySpan = _lex.tokenSpan();\n        unsigned flags = 0;\n        //check if is an static\n        if(otype == NEWOBJ_CLASS) {\n            if(_token == TK_STATIC) {\n                flags |= TMF_STATIC;\n                Lex();\n                keySpan = _lex.tokenSpan();\n            }\n        }\n\n        switch (_token) {\n        case TK_DOCSTRING: {\n            onDocString(_lex._svalue);\n            Lex();\n            break;\n        }\n        case TK_FUNCTION:\n        case TK_CONSTRUCTOR: {\n            SQInteger tk = _token;\n            SourceLoc funcStart = _lex.tokenStart();\n            Lex();\n            FuncAttrFlagsType attr = ParseFunctionAttributes();\n            Id *funcName = tk == TK_FUNCTION ? (Id *)Expect(TK_IDENTIFIER) : newNode<Id>(_lex.tokenSpan(), \"constructor\");\n            assert(funcName);\n            LiteralExpr *key = newNode<LiteralExpr>(funcName->sourceSpan(), funcName->name()); //-V522\n            Expect('(');\n            FunctionExpr *f = CreateFunction(funcStart, funcName, false, tk == TK_CONSTRUCTOR);\n            f->setPure(attr & FATTR_PURE);\n            f->setNodiscard(attr & FATTR_NODISCARD);\n            decl->addMember(key, f, flags);\n        }\n        break;\n        case '[': {\n            Lex();\n\n            Expr *key = Expression(SQE_RVALUE); //-V522\n            assert(key);\n            Expect(']');\n            Expect('=');\n            Expr *value = Expression(SQE_RVALUE);\n            decl->addMember(key, value, flags | TMF_DYNAMIC_KEY);\n            break;\n        }\n        case TK_STRING_LITERAL: //JSON\n            if (otype == NEWOBJ_TABLE) { //only works for tables\n                LiteralExpr *key = (LiteralExpr *)Expect(TK_STRING_LITERAL);  //-V522\n                assert(key);\n                Expect(':');\n                Expr *expr = Expression(SQE_RVALUE);\n                decl->addMember(key, expr, flags | TMF_JSON);\n                break;\n            }  //-V796\n        default: {\n            Id *id = (Id *)Expect(TK_IDENTIFIER);\n            assert(id);\n            LiteralExpr *key = newNode<LiteralExpr>(keySpan, id->name()); //-V522\n\n            if ((otype == NEWOBJ_TABLE) &&\n                (_token == TK_IDENTIFIER || _token == separator || _token == terminator || _token == '['\n                    || _token == TK_FUNCTION)) {\n                decl->addMember(key, id, flags);\n            }\n            else {\n                Expect('=');\n                Expr *expr = Expression(SQE_RVALUE);\n                decl->addMember(key, expr, flags);\n            }\n        }\n        }\n        if (_token == separator) Lex(); //optional comma/semicolon\n    }\n\n    decl->setSpanEnd(_lex.currentPos());\n    Lex();\n}\n\nDecl *SQParser::parseLocalFunctionExprStmt(bool assignable, SourceLoc keywordStart)\n{\n    SourceLoc funcStart = _lex.tokenStart();\n\n    assert(_token == TK_FUNCTION);\n    Lex();\n\n    FuncAttrFlagsType attr = ParseFunctionAttributes();\n    Id *varname = (Id *)Expect(TK_IDENTIFIER);\n    Expect('(');\n    FunctionExpr *f = CreateFunction(funcStart, varname, false);\n    f->setPure(attr & FATTR_PURE);\n    f->setNodiscard(attr & FATTR_NODISCARD);\n    VarDecl *d = newNode<VarDecl>(keywordStart, varname, f, assignable); //-V522\n    return d;\n}\n\nDecl *SQParser::parseLocalClassExprStmt(bool assignable, SourceLoc keywordStart)\n{\n    SourceLoc classStart = _lex.tokenStart();\n\n    assert(_token == TK_CLASS);\n    Lex();\n\n    Id *varname = (Id *)Expect(TK_IDENTIFIER);\n    ClassExpr *cls = ClassExp(classStart, NULL);\n    VarDecl *d = newNode<VarDecl>(keywordStart, varname, cls, assignable); //-V522\n    return d;\n}\n\nDecl* SQParser::parseLocalDeclStatement(bool onlySingleVariable)\n{\n    NestingChecker nc(this);\n\n    assert(_token == TK_LET || _token == TK_LOCAL);\n    SourceLoc keywordStart = _lex.tokenStart();\n    bool assignable = _token == TK_LOCAL;\n    Lex();\n\n    if (_token == TK_FUNCTION) {\n        return parseLocalFunctionExprStmt(assignable, keywordStart);\n    } else if (_token == TK_CLASS) {\n        return parseLocalClassExprStmt(assignable, keywordStart);\n    }\n\n\n    DeclGroup *decls = NULL;\n    DestructuringDecl  *dd = NULL;\n    Decl *decl = NULL;\n    SQInteger destructurer = 0;\n\n    if (_token == '{' || _token == '[') {\n        if (onlySingleVariable)\n            reportDiagnostic(DiagnosticsId::DI_ONLY_SINGLE_VARIABLE_DECLARATION);\n\n        destructurer = _token;\n        Lex();\n        // Use keywordStart (position of 'local'/'let') so span includes the keyword\n        decls = dd = newNode<DestructuringDecl>(arena(), keywordStart, destructurer == '{' ? DT_TABLE : DT_ARRAY);\n    }\n\n    do {\n        Id *varname = (Id *)Expect(TK_IDENTIFIER);\n        assert(varname);\n        VarDecl *cur = NULL;\n        unsigned typeMask = _token == ':' ? parseTypeMask(destructurer == 0) : ~0u;\n\n        // Determine start position:\n        // - For destructured vars, use varname's span start (keyword covered by DestructuringDecl)\n        // - For first non-destructured var, use keywordStart (to include 'local'/'let')\n        // - For subsequent vars in a group, use varname's span start (group covers keyword)\n        bool isFirstNonDestructured = (!destructurer && decl == NULL && decls == NULL);\n        SourceLoc varStart = isFirstNonDestructured ? keywordStart : varname->sourceSpan().start; //-V522\n\n        if(_token == '=') {\n            Lex();\n            Expr *expr = Expression(SQE_REGULAR);\n            if (!assignable && expr->op() == TO_FUNCTION) {\n              FunctionExpr *f = expr->asFunctionExpr();\n              if (!f->name() || f->name()[0] == '(') {\n                f->setName(varname->name());\n              }\n            }\n            cur = newNode<VarDecl>(varStart, varname, expr, assignable, destructurer != 0); //-V522\n        }\n        else {\n            if (!assignable && !destructurer)\n                _ctx.reportDiagnostic(DiagnosticsId::DI_UNINITIALIZED_BINDING, varname->lineStart(), varname->columnStart(), varname->textWidth(), varname->name()); //-V522\n            cur = newNode<VarDecl>(varStart, varname, nullptr, assignable, destructurer != 0);\n        }\n\n        cur->setTypeMask(typeMask);\n\n        if (decls) {\n            decls->addDeclaration(cur);\n        } else if (decl) {\n            decls = newNode<DeclGroup>(arena(), keywordStart);\n            decls->addDeclaration(static_cast<VarDecl *>(decl));\n            decls->addDeclaration(cur);\n            decl = decls;\n        } else {\n            decl = cur;\n        }\n\n        if (destructurer) {\n            if (_token == ',') {\n                Lex();\n                if (_token == ']' || _token == '}')\n                    break;\n            }\n            else if (_token == TK_IDENTIFIER)\n                continue;\n            else\n                break;\n        }\n        else {\n            if (_token == ',') {\n                if (onlySingleVariable)\n                    reportDiagnostic(DiagnosticsId::DI_ONLY_SINGLE_VARIABLE_DECLARATION);\n                Lex();\n            }\n            else\n                break;\n        }\n    } while(1);\n\n    if (destructurer) {\n        Expect(destructurer=='[' ? ']' : '}');\n        Expect('=');\n        assert(dd);\n        dd->setExpression(Expression(SQE_RVALUE)); //-V522\n        return dd;\n    } else {\n        return decls ? static_cast<Decl*>(decls) : decl;\n    }\n}\n\nStatement* SQParser::IfLikeBlock(bool &wrapped)\n{\n    NestingChecker nc(this);\n    Statement *stmt = NULL;\n    if (_token == '{')\n    {\n        wrapped = false;\n        SourceLoc blockStart = _lex.tokenStart();\n        Lex();\n        Block *block = parseStatements(blockStart);\n        block->setSpanEnd(_lex.currentPos());\n        Expect('}');\n        stmt = block;\n    }\n    else {\n        wrapped = true;\n        stmt = parseStatement();\n        SourceSpan stmtSpan = stmt->sourceSpan(); //-V522\n        Block *block = newNode<Block>(arena(), stmtSpan.start);\n        block->addStatement(stmt);\n        block->setSpanEnd(stmtSpan.end);\n        stmt = block;\n        if (_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon();\n    }\n\n    return stmt;\n}\n\nStatement * SQParser::parseIfStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    SQInteger prevTok = _lex._prevtoken;\n\n    Consume(TK_IF);\n\n    Statement *initializer = NULL;\n    Expr *cond = NULL;\n\n    Expect('(');\n    if (_token == TK_LOCAL || _token == TK_LET) {\n        initializer = parseLocalDeclStatement(true);\n        assert(initializer);\n        if (initializer->asDeclaration()->asVarDecl()->initializer() == NULL) //-V522\n            reportDiagnostic(DiagnosticsId::DI_INITIALIZATION_REQUIRED);\n\n        if (_token == ';') {\n            Lex();\n            cond = Expression(SQE_IF);\n        }\n        else {\n            Id* nameId = initializer->asDeclaration()->asVarDecl()->nameId(); //-V522\n            cond = newNode<Id>(nameId->sourceSpan(), nameId->name());\n        }\n    }\n    else {\n        cond = Expression(SQE_IF);\n    }\n    Expect(')');\n\n    checkBraceIndentationStyle();\n\n    bool wrapped = false;\n\n    Statement *thenB = IfLikeBlock(wrapped);\n    Statement *elseB = NULL;\n    if (_token == TK_ELSE) {\n        SourceSpan elseSpan = _lex.tokenSpan();\n        Lex();\n        if (_token != '{' && prevTok != TK_ELSE && wrapped && start.line != elseSpan.start.line && start.column != elseSpan.start.column) {\n          _ctx.reportDiagnostic(DiagnosticsId::DI_SUSPICIOUS_FMT, elseSpan.start.line, elseSpan.start.column, elseSpan.textWidth());\n        }\n        checkBraceIndentationStyle();\n        elseB = IfLikeBlock(wrapped);\n        if (!IsEndOfStatement()) {\n          reportDiagnostic(DiagnosticsId::DI_STMT_SAME_LINE, \"else\");\n        }\n    }\n    else if (!IsEndOfStatement()) {\n      reportDiagnostic(DiagnosticsId::DI_STMT_SAME_LINE, \"then\");\n    }\n\n\n    if (_token != SQUIRREL_EOB && _token != '}' && _token != ']' && _token != ')' && _token != ',') {\n      int32_t lastLine = elseB ? elseB->lineEnd() : thenB->lineEnd();\n      SourceLoc curTok = _lex.tokenStart();\n      if (curTok.line != lastLine && curTok.column > start.column) {\n        reportDiagnostic(DiagnosticsId::DI_SUSPICIOUS_FMT);\n      }\n    }\n\n    if (initializer) {\n        // wrap initializer and condition in a {} block so they are properly scoped\n        Block *block = newNode<Block>(arena(), start);\n        block->addStatement(initializer);\n        block->addStatement(newNode<IfStatement>(start, cond, thenB, elseB));\n        block->setSpanEnd((elseB ? elseB : thenB)->sourceSpan().end);\n        return block;\n    }\n    else {\n        return newNode<IfStatement>(start, cond, thenB, elseB);\n    }\n}\n\nWhileStatement* SQParser::parseWhileStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    Consume(TK_WHILE);\n\n    Expect('(');\n    Expr *cond = Expression(SQE_LOOP_CONDITION);\n    Expect(')');\n\n    bool wrapped = false;\n    checkBraceIndentationStyle();\n    Statement *body = IfLikeBlock(wrapped);\n\n    if (!IsEndOfStatement()) {\n      reportDiagnostic(DiagnosticsId::DI_STMT_SAME_LINE, \"while loop body\");\n    }\n\n    if (_token != SQUIRREL_EOB && _token != '}') {\n      SourceLoc curTok = _lex.tokenStart();\n      if (curTok.line != body->lineEnd() && curTok.column > start.column) {\n        reportDiagnostic(DiagnosticsId::DI_SUSPICIOUS_FMT);\n      }\n    }\n\n    return newNode<WhileStatement>(start, cond, body);\n}\n\nDoWhileStatement* SQParser::parseDoWhileStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    Consume(TK_DO); // DO\n\n    bool wrapped = false;\n    checkBraceIndentationStyle();\n    Statement *body = IfLikeBlock(wrapped);\n\n    Expect(TK_WHILE);\n\n    Expect('(');\n    Expr *cond = Expression(SQE_LOOP_CONDITION);\n    SourceLoc end = _lex.currentPos();\n    Expect(')');\n\n    return newNode<DoWhileStatement>(start, body, cond, end);\n}\n\nForStatement* SQParser::parseForStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    Consume(TK_FOR);\n\n    Expect('(');\n\n    Node *init = NULL;\n    if (_token == TK_LOCAL)\n        init = parseLocalDeclStatement();\n    else if (_token != ';') {\n        init = parseCommaExpr(SQE_REGULAR);\n    }\n    Expect(';');\n\n    Expr *cond = NULL;\n    if(_token != ';') {\n        cond = Expression(SQE_LOOP_CONDITION);\n    }\n    Expect(';');\n\n    Expr *mod = NULL;\n    if(_token != ')') {\n        mod = parseCommaExpr(SQE_REGULAR);\n    }\n    Expect(')');\n\n    bool wrapped = false;\n    checkBraceIndentationStyle();\n    Statement *body = IfLikeBlock(wrapped);\n\n    if (!IsEndOfStatement()) {\n      reportDiagnostic(DiagnosticsId::DI_STMT_SAME_LINE, \"for loop body\");\n    }\n\n    if (_token != SQUIRREL_EOB && _token != '}') {\n      SourceLoc curTok = _lex.tokenStart();\n      if (curTok.line != body->lineEnd() && curTok.column > start.column) {\n        reportDiagnostic(DiagnosticsId::DI_SUSPICIOUS_FMT);\n      }\n    }\n\n    return newNode<ForStatement>(start, init, cond, mod, body);\n}\n\nvoid SQParser::parseDestructuringFields(DestructuringDecl *destr)\n{\n    while (_token != '}' && _token != ']' && _token != SQUIRREL_EOB) {\n        Id *fieldname = (Id *)Expect(TK_IDENTIFIER);\n        assert(fieldname);\n        if (!fieldname)\n            break;\n\n        unsigned typeMask = _token == ':' ? parseTypeMask(false) : ~0u;\n        SourceLoc varStart = fieldname->sourceSpan().start;\n\n        Expr *defaultExpr = nullptr;\n        if (_token == '=') {\n            Lex();\n            defaultExpr = Expression(SQE_REGULAR);\n        }\n\n        VarDecl *fieldDecl = newNode<VarDecl>(varStart, fieldname, defaultExpr, /*assignable*/false, /*destructured*/true);\n        fieldDecl->setTypeMask(typeMask);\n        destr->addDeclaration(fieldDecl);\n\n        if (_token == ',') {\n            Lex();\n            if (_token == ']' || _token == '}')\n                break;\n        }\n        else if (_token == TK_IDENTIFIER)\n            continue;\n        else\n            break;\n    }\n}\n\nForeachStatement* SQParser::parseForEachStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    Consume(TK_FOREACH);\n\n    Expect('(');\n\n    Id *idxname = NULL;\n    Id *valname = NULL;\n    DestructuringDecl *valDestr = NULL;\n\n    auto parseValDestructuring = [this, &valDestr]() -> Id* {\n        SQInteger destructurer = _token;\n        SourceLoc keywordStart = _lex.tokenStart();\n        char buf[32];\n        snprintf(buf, sizeof(buf), \"@FE_VAL%u\", _foreachDestrCounter++);\n        Id *surrogateName = newId(buf);\n        Lex(); // consume '{' or '['\n        valDestr = newNode<DestructuringDecl>(arena(), keywordStart, destructurer == '{' ? DT_TABLE : DT_ARRAY);\n        parseDestructuringFields(valDestr);\n        Expect(destructurer == '{' ? '}' : ']');\n        valDestr->setExpression(surrogateName);\n        return surrogateName;\n    };\n\n    if (_token == '{' || _token == '[') {\n        valname = parseValDestructuring();\n    }\n    else {\n        valname = (Id *)Expect(TK_IDENTIFIER);\n        assert(valname);\n\n        if (_token == ',') {\n            idxname = valname;\n            Lex();\n            if (_token == '{' || _token == '[') {\n                valname = parseValDestructuring();\n            }\n            else {\n                valname = (Id *)Expect(TK_IDENTIFIER);\n                assert(valname);\n                if (strcmp(idxname->name(), valname->name()) == 0) //-V522\n                    _ctx.reportDiagnostic(DiagnosticsId::DI_SAME_FOREACH_KV_NAMES, valname->lineStart(), valname->columnStart(), valname->textWidth(), valname->name());\n            }\n        }\n    }\n\n    Expect(TK_IN);\n\n    Expr *contnr = Expression(SQE_RVALUE);\n    Expect(')');\n\n    bool wrapped = false;\n    checkBraceIndentationStyle();\n    Statement *body = IfLikeBlock(wrapped);\n\n    if (!IsEndOfStatement()) {\n      reportDiagnostic(DiagnosticsId::DI_STMT_SAME_LINE, \"foreach loop body\");\n    }\n\n    if (_token != SQUIRREL_EOB && _token != '}') {\n      SourceLoc curTok = _lex.tokenStart();\n      if (curTok.line != body->lineEnd() && curTok.column > start.column) {\n        reportDiagnostic(DiagnosticsId::DI_SUSPICIOUS_FMT);\n      }\n    }\n\n    if (valDestr) {\n        Block *wrap = newNode<Block>(arena(), body->sourceSpan().start);\n        wrap->addStatement(valDestr);\n        wrap->addStatement(body);\n        wrap->setSpanEnd(body->sourceSpan().end);\n        body = wrap;\n    }\n\n    VarDecl *idxDecl = idxname ? newNode<VarDecl>(idxname->sourceSpan().start, idxname, nullptr, false) : NULL;\n    VarDecl *valDecl = valname ? newNode<VarDecl>(valname->sourceSpan().start, valname, nullptr, false) : NULL;\n\n    return newNode<ForeachStatement>(start, idxDecl, valDecl, contnr, body);\n}\n\nSwitchStatement* SQParser::parseSwitchStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    Consume(TK_SWITCH);\n\n    Expect('(');\n    Expr *switchExpr = Expression(SQE_SWITCH);\n    Expect(')');\n\n    checkBraceIndentationStyle();\n    Expect('{');\n\n    SwitchStatement *switchStmt = newNode<SwitchStatement>(start, arena(), switchExpr);\n\n    while(_token == TK_CASE) {\n        Consume(TK_CASE);\n\n        Expr *cond = Expression(SQE_RVALUE);\n        Expect(':');\n        SourceLoc caseBodyStart = _lex.currentPos();\n\n        checkBraceIndentationStyle();\n        Statement *caseBody = parseStatements(caseBodyStart);\n        switchStmt->addCases(cond, caseBody);\n    }\n\n    if(_token == TK_DEFAULT) {\n        Consume(TK_DEFAULT);\n        Expect(':');\n        SourceLoc defaultBodyStart = _lex.currentPos();\n\n        checkBraceIndentationStyle();\n        switchStmt->addDefault(parseStatements(defaultBodyStart));\n    }\n\n    switchStmt->setSpanEnd(_lex.currentPos());\n    Expect('}');\n\n    return switchStmt;\n}\n\n\nLiteralExpr* SQParser::ExpectScalar()\n{\n    NestingChecker nc(this);\n    LiteralExpr *ret = NULL;\n    SourceLoc start = _lex.tokenStart();\n\n    switch(_token) {\n        case TK_NULL:\n            ret = newNode<LiteralExpr>(_lex.tokenSpan());\n            break;\n        case TK_INTEGER:\n            ret = newNode<LiteralExpr>(_lex.tokenSpan(), _lex._nvalue);\n            break;\n        case TK_FLOAT:\n            ret = newNode<LiteralExpr>(_lex.tokenSpan(), _lex._fvalue);\n            break;\n        case TK_STRING_LITERAL:\n            ret = newStringLiteral(_lex._svalue);\n            break;\n        case TK_TRUE:\n        case TK_FALSE:\n            ret = newNode<LiteralExpr>(_lex.tokenSpan(), (bool)(_token == TK_TRUE ? 1 : 0));\n            break;\n        case '-': {\n            Lex();\n            SourceSpan span = {start, _lex.currentPos()};\n            switch(_token)\n            {\n            case TK_INTEGER:\n                ret = newNode<LiteralExpr>(span, -_lex._nvalue);\n            break;\n            case TK_FLOAT:\n                ret = newNode<LiteralExpr>(span, -_lex._fvalue);\n            break;\n            default:\n                reportDiagnostic(DiagnosticsId::DI_SCALAR_EXPECTED, \"integer, float\");\n            }\n            break;\n        }\n        default:\n            reportDiagnostic(DiagnosticsId::DI_SCALAR_EXPECTED, \"integer, float, or string\");\n    }\n\n    Lex();\n    return ret;\n}\n\n\nConstDecl* SQParser::parseConstFunctionExprStmt(bool global, SourceLoc globalStart)\n{\n    SourceLoc start = globalStart.isValid() ? globalStart : _lex.tokenStart();\n\n    assert(_token == TK_FUNCTION);\n    Lex();\n\n    FuncAttrFlagsType attr = ParseFunctionAttributes();\n    Id *funcName = (Id *)Expect(TK_IDENTIFIER);\n    Expect('(');\n    FunctionExpr *f = CreateFunction(start, funcName, false);\n    f->setPure(attr & FATTR_PURE);\n    f->setNodiscard(attr & FATTR_NODISCARD);\n\n    // Wrap function in const inline operator\n    Expr *constFunc = newNode<UnExpr>(TO_INLINE_CONST, start, f);\n    ConstDecl *d = newNode<ConstDecl>(start, funcName->name(), constFunc, global); //-V522\n    return d;\n}\n\nConstDecl* SQParser::parseConstStatement(bool global, SourceLoc globalStart)\n{\n    NestingChecker nc(this);\n    SourceLoc start = globalStart.isValid() ? globalStart : _lex.tokenStart();\n    Lex();\n\n    if (_token == TK_FUNCTION) {\n        return parseConstFunctionExprStmt(global, globalStart);\n    }\n\n    Id *id = (Id *)Expect(TK_IDENTIFIER);\n\n    Expect('=');\n    Expr *valExpr = Expression(SQE_RVALUE);\n    ConstDecl *d = newNode<ConstDecl>(start, id->name(), valExpr, global); //-V522\n\n    OptionalSemicolon();\n\n    return d;\n}\n\n\nEnumDecl* SQParser::parseEnumStatement(bool global, SourceLoc globalStart)\n{\n    NestingChecker nc(this);\n    SourceLoc start = globalStart.isValid() ? globalStart : _lex.tokenStart();\n    Lex();\n    Id *id = (Id *)Expect(TK_IDENTIFIER);\n\n    EnumDecl *decl = newNode<EnumDecl>(arena(), start, id->name(), global); //-V522\n\n    checkBraceIndentationStyle();\n    Expect('{');\n\n    SQInteger nval = 0;\n    while(_token != '}') {\n        Id *key = (Id *)Expect(TK_IDENTIFIER);\n\n        const char* keyName = key->name(); //-V522\n        for (EnumConst& ec : decl->consts())\n            if (*keyName == *ec.id && !strcmp(keyName, ec.id))\n                reportDiagnostic(DiagnosticsId::DI_DUPLICATE_KEY, keyName);\n\n        LiteralExpr *valExpr = NULL;\n        if(_token == '=') {\n            // TODO1: should it behave like C does?\n            // TODO2: should float and string literal be allowed here?\n            Lex();\n            valExpr = ExpectScalar();\n        }\n        else {\n            valExpr = newNode<LiteralExpr>(key->sourceSpan(), nval++);\n        }\n\n        decl->addConst(keyName, valExpr); //-V522\n\n        if(_token == ',') Lex();\n    }\n\n    decl->setSpanEnd(_lex.currentPos());\n    Lex();\n\n    return decl;\n}\n\n\nTryStatement* SQParser::parseTryCatchStatement()\n{\n    NestingChecker nc(this);\n\n    SourceLoc start = _lex.tokenStart();\n\n    Consume(TK_TRY);\n\n    checkBraceIndentationStyle();\n    Statement *t = parseStatement();\n\n    Expect(TK_CATCH);\n\n    Expect('(');\n    Id *exid = (Id *)Expect(TK_IDENTIFIER);\n    Expect(')');\n\n    checkBraceIndentationStyle();\n    Statement *cth = parseStatement();\n\n    return newNode<TryStatement>(start, t, exid, cth);\n}\n\n\nId* SQParser::generateSurrogateFunctionName()\n{\n    const char * fileName = _sourcename ? _sourcename : \"unknown\";\n    int lineNum = int(_lex._currentline);\n\n    const char * rightSlash = std::max(strrchr(fileName, '/'), strrchr(fileName, '\\\\'));\n\n    constexpr int maxLen = 256;\n\n    char buf[maxLen];\n    scsprintf(buf, maxLen, \"(%s:%d)\", rightSlash ? (rightSlash + 1) : fileName, lineNum);\n    return newId(buf);\n}\n\n\nSQParser::FuncAttrFlagsType SQParser::ParseFunctionAttributes() {\n    if (_token != '[')\n        return 0;\n\n    Lex();\n\n    FuncAttrFlagsType attrVal = 0;\n    while (_token != ']') {\n        if (_token == TK_IDENTIFIER) {\n            FuncAttrFlagsType flag = 0;\n            if (strcmp(_lex._svalue, \"pure\")==0) {\n                flag = FATTR_PURE;\n            } else if (strcmp(_lex._svalue, \"nodiscard\")==0) {\n                flag = FATTR_NODISCARD;\n            } else {\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"valid attribute name\");\n            }\n            if (attrVal & flag) {\n                reportDiagnostic(DiagnosticsId::DI_DUPLICATE_FUNC_ATTR, _lex._svalue);\n            }\n            attrVal |= flag;\n        } else {\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"attribute name\");\n        }\n\n        Lex();\n        if (_token == ',') {\n            Lex();\n        }\n    }\n\n    Expect(']');\n    return attrVal;\n}\n\n\nFunctionExpr* SQParser::FunctionExp(bool lambda)\n{\n    NestingChecker nc(this);\n    SourceLoc start = _lex.tokenStart();\n    Lex();\n    FuncAttrFlagsType attr = ParseFunctionAttributes();\n    Id *funcName = (_token == TK_IDENTIFIER) ? (Id *)Expect(TK_IDENTIFIER) : generateSurrogateFunctionName();\n    Expect('(');\n\n    FunctionExpr *f = CreateFunction(start, funcName, lambda);\n    f->setPure(attr & FATTR_PURE);\n    f->setNodiscard(attr & FATTR_NODISCARD);\n\n    return f;\n}\n\n\nClassExpr* SQParser::ClassExp(SourceLoc classStart, Expr *key)\n{\n    NestingChecker nc(this);\n    Expr *baseExpr = NULL;\n    if(_token == TK_EXTENDS) {\n        Lex();\n        baseExpr = Expression(SQE_RVALUE);\n    }\n    else if (_token == '(') {\n      Lex();\n      baseExpr = Expression(SQE_RVALUE);\n      Expect(')');\n    }\n    checkBraceIndentationStyle();\n    Expect('{');\n    ClassExpr *d = newNode<ClassExpr>(arena(), classStart, key, baseExpr);\n    _docObjectStack.push_back(&d->docObject);\n    ParseTableOrClass(d, ';','}');\n    _docObjectStack.pop_back();\n    return d;\n}\n\n\nExpr* SQParser::DeleteExpr()\n{\n    NestingChecker nc(this);\n    SourceLoc opStart = _lex.tokenStart();\n    Consume(TK_DELETE);\n    Expr *arg = PrefixedExpr();\n    return newNode<UnExpr>(TO_DELETE, opStart, arg);\n}\n\n\nExpr* SQParser::PrefixIncDec(SQInteger token)\n{\n    NestingChecker nc(this);\n    SourceLoc opStart = _lex.tokenStart();\n    SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;\n    Lex();\n    Expr *arg = PrefixedExpr();\n    return newNode<IncExpr>(arg, diff, IF_PREFIX, opStart);\n}\n\n\nstatic bool can_be_type_name(int token)\n{\n    return token == TK_IDENTIFIER || token == TK_NULL || token == TK_FUNCTION || token == TK_CLASS;\n}\n\nunsigned SQParser::parseTypeMask(bool eol_breaks_type_parsing)\n{\n    unsigned typeMask = 0;\n    Lex();\n    bool requireParen = false;\n    if (_token == '(') {\n        requireParen = true;\n        Lex();\n    }\n\n    if (!can_be_type_name(_token))\n        reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"TYPE_NAME\");\n\n    while (can_be_type_name(_token)) {\n        const char* suggestion = nullptr;\n        SQUnsignedInteger32 currentMask = 0;\n\n        const char* name = (_token == TK_IDENTIFIER) ? _lex._svalue :\n            (_token == TK_NULL) ? \"null\" :\n            (_token == TK_FUNCTION) ? \"function\" :\n            (_token == TK_CLASS) ? \"class\" :\n            \"<not-implemented>\";\n\n        bool found = sq_type_string_to_mask(name, currentMask, suggestion);\n        if (!found) {\n           if (suggestion)\n               reportDiagnostic(DiagnosticsId::DI_INVALID_TYPE_NAME_SUGGESTION, name, suggestion);\n           else\n               reportDiagnostic(DiagnosticsId::DI_INVALID_TYPE_NAME, name);\n        }\n        typeMask |= currentMask;\n        Lex();\n\n        if (_lex._prevtoken == '\\n' && eol_breaks_type_parsing && !requireParen)\n            break;\n\n        if (_token == '|')\n            Lex();\n        else\n            break;\n\n        if (!can_be_type_name(_token))\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"TYPE_NAME\");\n    }\n\n    if (requireParen)\n        Expect(')');\n\n    return typeMask;\n}\n\n\nFunctionExpr* SQParser::CreateFunction(SourceLoc start, Id *name, bool lambda, bool ctor)\n{\n    NestingChecker nc(this);\n    FunctionExpr *f = ctor ? newNode<FunctionExpr>(arena(), start, name->name()) : newNode<FunctionExpr>(arena(), start, name);\n\n    SQInteger defparams = 0;\n\n    auto &params = f->parameters();\n\n    while (_token!=')') {\n        SourceSpan paramSpan = _lex.tokenSpan();\n        if (_token == TK_VARPARAMS) {\n            if(defparams > 0)\n                reportDiagnostic(DiagnosticsId::DI_VARARG_WITH_DEFAULT_ARG);\n            f->addParameter(paramSpan, \"vargv\");\n            f->setVararg(true);\n            params.back()->setVararg();\n            Lex();\n            unsigned typeMask = _token == ':' ? parseTypeMask(false) : ~0u;\n            params.back()->setTypeMask(typeMask);\n            if(_token != ')')\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \")\");\n            break;\n        }\n        else {\n            if (_token == '{' || _token == '[') {\n                SourceSpan argSpan = _lex.tokenSpan();\n                SourceLoc keywordStart = _lex.tokenStart();\n                SQInteger destructurer = _token;\n                constexpr int maxLen = 16;\n                char buf[maxLen];\n                snprintf(buf, maxLen, \"@arg%d\", int(params.size() + 1));\n                Id *surrogateName = newId(buf);\n\n                Lex(); // skip '{' or '['\n                DestructuringDecl *destrDecl = newNode<DestructuringDecl>(arena(), keywordStart, destructurer == '{' ? DT_TABLE : DT_ARRAY);\n                destrDecl->setExpression(surrogateName);\n\n                parseDestructuringFields(destrDecl);\n\n                Expect(destructurer == '{' ? '}' : ']');\n                f->addParameter(argSpan, surrogateName->name(), nullptr);\n                ParamDecl *p = params.back();\n                p->setDestructuring(destrDecl);\n                p->setTypeMask(destructurer == '{' ? (_RT_TABLE | _RT_INSTANCE | _RT_CLASS) : (_RT_ARRAY));\n\n            }\n            else {\n                Id *paramname = (Id *)Expect(TK_IDENTIFIER);\n                unsigned typeMask = _token == ':' ? parseTypeMask(false) : ~0u;\n                Expr *defVal = NULL;\n                if (_token == '=') {\n                    Lex();\n                    defVal = Expression(SQE_RVALUE);\n                    defparams++;\n                }\n                else {\n                    if (defparams > 0)\n                        reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"=\");\n                }\n\n                // Use Id's span for parameter name span\n                f->addParameter(paramname->sourceSpan(), paramname->name(), defVal); //-V522\n                ParamDecl *p = params.back();\n                p->setTypeMask(typeMask);\n            }\n\n            if(_token == ',') Lex();\n            else if(_token != ')')\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \") or ,\");\n        }\n    }\n\n    Expect(')');\n    unsigned resultTypeMask = _token == ':' ? parseTypeMask(false) : ~0u;\n\n    Block *body = NULL;\n\n    SQUnsignedInteger savedLangFeatures = _lang_features;\n    _docObjectStack.push_back(&f->docObject);\n\n    if (lambda) {\n        Expr *expr = Expression(SQE_REGULAR);\n        SourceSpan exprSpan = expr->sourceSpan();\n        // For lambda, use expression span as the synthetic \"return\" span\n        ReturnStatement *retStmt = newNode<ReturnStatement>(exprSpan, expr);\n        retStmt->setIsLambda();\n        body = newNode<Block>(arena(), exprSpan.start);\n        body->addStatement(retStmt);\n        body->setSpanEnd(exprSpan.end);\n    }\n    else {\n        if (_token != '{')\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"{\");\n        checkBraceIndentationStyle();\n        body = (Block *)parseStatement(false);\n    }\n\n    _docObjectStack.pop_back();\n\n    f->setBody(body);\n\n    f->setSourceName(_sourcename);\n    f->setLambda(lambda);\n    f->setResultTypeMask(resultTypeMask);\n\n    _lang_features = savedLangFeatures;\n\n    return f;\n}\n\n\nImportStmt* SQParser::parseImportStatement()\n{\n    if (!_are_imports_still_allowed)\n        reportDiagnostic(DiagnosticsId::DI_GENERAL_COMPILE_ERROR, \"import statements must be at the top of the file\");\n\n    // Reuse lexer for the specific import syntax\n\n    SourceLoc start = _lex.tokenStart();\n    ImportStmt *importStmt = nullptr;\n\n    const char *keyword = _lex._svalue;\n\n    if (strcmp(keyword, \"from\") == 0) {\n        // from \"module\" import x, y, z\n        Lex();\n\n        if (_token != TK_STRING_LITERAL)\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"module name\");\n\n        const char *moduleName = copyString(_lex._svalue);\n        Lex();\n\n        if (_token != TK_IDENTIFIER || strcmp(_lex._svalue, \"import\") != 0)\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"import\");\n        Lex();\n\n        importStmt = newNode<ImportStmt>(arena(), start, moduleName, nullptr);\n        importStmt->nameCol = _lex.tokenStart().column;\n        importStmt->aliasCol = _lex.tokenStart().column;\n\n        // Parse import list: x, y, z as foo, *\n        do {\n            SQModuleImportSlot slot{};\n\n            if (_token != '*' && _token != TK_IDENTIFIER)\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"identifier or *\");\n\n            bool isWildcard = (_token == '*');\n\n            slot.name = copyString(isWildcard ? \"*\" : _lex._svalue);\n            SourceLoc slotLoc = _lex.tokenStart();\n            slot.line = slotLoc.line;\n            slot.column = slotLoc.column;\n            Lex();\n\n            // Check for an alias\n            if (_token == TK_IDENTIFIER && strcmp(_lex._svalue, \"as\") == 0) {\n                Lex();\n                if (_token != TK_IDENTIFIER)\n                    reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"identifier\");\n                if (isWildcard)\n                    reportDiagnostic(DiagnosticsId::DI_GENERAL_COMPILE_ERROR, \"cannot rename *\");\n                slot.alias = copyString(_lex._svalue);\n                Lex();\n            }\n\n            importStmt->slots.push_back(slot);\n\n            if (_token == ',')\n                Lex();\n            else\n                break;\n        } while (true);\n\n    } else if (strcmp(keyword, \"import\") == 0) {\n        // import \"module\" [as alias]\n        Lex();\n\n        if (_token != TK_STRING_LITERAL)\n            reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"module name string\");\n\n        const char *moduleName = copyString(_lex._svalue);\n        int32_t nameCol = _lex.tokenStart().column;\n        int32_t aliasCol = nameCol;\n        Lex();\n\n        const char *moduleAlias = nullptr;\n        if (_token == TK_IDENTIFIER && strcmp(_lex._svalue, \"as\") == 0) {\n            Lex();\n            if (_token != TK_IDENTIFIER)\n                reportDiagnostic(DiagnosticsId::DI_EXPECTED_TOKEN, \"identifier\");\n            moduleAlias = copyString(_lex._svalue);\n            aliasCol = _lex.tokenStart().column;\n            Lex();\n        }\n\n        importStmt = newNode<ImportStmt>(arena(), start, moduleName, moduleAlias);\n        importStmt->nameCol = nameCol;\n        importStmt->aliasCol = aliasCol;\n    }\n\n    if (importStmt) {\n        // Set end position to current position (after the last parsed token)\n        importStmt->setSpanEnd(_lex.tokenStart());\n    }\n\n    return importStmt;\n}\n\n} // namespace SQCompilation\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/parser.h",
    "content": "#pragma once\n\n#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include <algorithm>\n#include \"lexer.h\"\n#include \"lex_tokens.h\"\n#include \"sqvm.h\"\n#include \"compilationcontext.h\"\n#include \"ast.h\"\n\nnamespace SQCompilation {\n\nclass SQParser\n{\n    enum SQExpressionContext {\n        SQE_REGULAR = 0,\n        SQE_IF,\n        SQE_SWITCH,\n        SQE_LOOP_CONDITION,\n        SQE_FUNCTION_ARG,\n        SQE_RVALUE,\n        SQE_ARRAY_ELEM,\n    };\n\n    using FuncAttrFlagsType = uint8_t;\n    enum FuncAttribute : FuncAttrFlagsType {\n        FATTR_PURE = 0x01,\n        FATTR_NODISCARD = 0x02,\n    };\n\n    Arena *_astArena;\n\n    template<typename N, typename ... Args>\n    N *newNode(Args&&... args) const {\n        return new (arena()) N(std::forward<Args>(args)...);\n    }\n\n    char *copyString(const char *s) const {\n        size_t len = strlen(s);\n        size_t memLen = (len + 1) * sizeof(char);\n        char *buf = (char *)arena()->allocate(memLen);\n        memcpy(buf, s, memLen);\n        return buf;\n    }\n\n    Id *newId(const char *name) const {\n        return newNode<Id>(_lex.tokenSpan(), copyString(name));\n    }\n\n    LiteralExpr *newStringLiteral(const char *s) const {\n        return newNode<LiteralExpr>(_lex.tokenSpan(), copyString(s));\n    }\n\n    Arena *arena() const { return _astArena; }\n\n    void checkSuspiciousUnaryOp(SQInteger prevTok, SQInteger tok, unsigned prevFlags);\n    void checkSuspiciousBracket();\npublic:\n    SQCompilationContext &_ctx;\n\n    void reportDiagnostic(int32_t id, ...);\n\n    uint32_t _depth;\n\n    SQParser(SQVM *v, const char *sourceText, size_t sourceTextSize, const char* sourcename, Arena *astArena, SQCompilationContext &ctx, Comments *comments);\n\n    bool ProcessPosDirective();\n    void Lex();\n\n    void checkBraceIndentationStyle();\n\n    void Consume(SQInteger tok) {\n        assert(tok == _token);\n        Lex();\n    }\n\n    Expr*   Expect(SQInteger tok);\n    bool    IsEndOfStatement() const {\n        return ((_lex._prevtoken == '\\n') || (_token == SQUIRREL_EOB) || (_token == '}') || (_token == ';'))\n            || (_token == TK_DIRECTIVE);\n    }\n    void    OptionalSemicolon();\n\n    RootBlock*  parse();\n    Block*      parseStatements(SourceLoc start);\n    Statement*  parseStatement(bool closeframe = true);\n    Expr*       parseCommaExpr(SQExpressionContext expression_context);\n    Expr*       Expression(SQExpressionContext expression_context);\n\n    template<typename T> Expr *BIN_EXP(T f, enum TreeOp top, Expr *lhs);\n\n    Expr*   LogicalNullCoalesceExp();\n    Expr*   LogicalOrExp();\n    Expr*   LogicalAndExp();\n    Expr*   BitwiseOrExp();\n    Expr*   BitwiseXorExp();\n    Expr*   BitwiseAndExp();\n    Expr*   EqExp();\n    Expr*   CompExp();\n    Expr*   ShiftExp();\n    Expr*   PlusExp();\n    Expr*   MultExp();\n    Expr*   PrefixedExpr();\n    Expr*   Factor(SQInteger &pos);\n\n    void ParseTableOrClass(TableExpr *decl, SQInteger separator, SQInteger terminator);\n\n    Decl *parseLocalDeclStatement(bool onlySingleVariable = false);\n    Decl *parseLocalFunctionExprStmt(bool assignable, SourceLoc keywordStart);\n    Decl *parseLocalClassExprStmt(bool assignable, SourceLoc keywordStart);\n    void parseDestructuringFields(DestructuringDecl *destr);\n\n    Statement* IfLikeBlock(bool &wrapped);\n    Statement* parseIfStatement();\n    WhileStatement* parseWhileStatement();\n    DoWhileStatement* parseDoWhileStatement();\n    ForStatement* parseForStatement();\n    ForeachStatement* parseForEachStatement();\n    SwitchStatement* parseSwitchStatement();\n    Expr *parseStringTemplate();\n    unsigned parseTypeMask(bool eol_breaks_type_parsing);\n    LiteralExpr* ExpectScalar();\n    ConstDecl* parseConstStatement(bool global, SourceLoc globalStart = SourceLoc::invalid());\n    ConstDecl* parseConstFunctionExprStmt(bool global, SourceLoc globalStart = SourceLoc::invalid());\n    EnumDecl* parseEnumStatement(bool global, SourceLoc globalStart = SourceLoc::invalid());\n    TryStatement* parseTryCatchStatement();\n    Id* generateSurrogateFunctionName();\n    FunctionExpr* FunctionExp(bool lambda);\n    FuncAttrFlagsType ParseFunctionAttributes();\n    ClassExpr* ClassExp(SourceLoc classStart, Expr *key);\n    Expr* DeleteExpr();\n    Expr* PrefixIncDec(SQInteger token);\n    FunctionExpr* CreateFunction(SourceLoc start, Id *name, bool lambda = false, bool ctor = false);\n    Statement* parseDirectiveStatement();\n    ImportStmt* parseImportStatement();\n    void onDocString(const char *doc_string);\n\n    DocObject& getModuleDocObject() { return _moduleDocObject; }\n\nprivate:\n    ArenaVector<DocObject *> _docObjectStack;\n    DocObject _moduleDocObject;\n    SQInteger _token;\n    const char *_sourcename;\n    SQLexer _lex;\n    SQExpressionContext _expression_context;\n    SQUnsignedInteger _lang_features;\n    SQVM *_vm;\n    bool _are_imports_still_allowed = true;\n    uint32_t _foreachDestrCounter = 0;\n};\n\n} // namespace SQCompilation\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/sourceloc.h",
    "content": "#pragma once\n#ifndef _SQSOURCELOC_H_\n#define _SQSOURCELOC_H_\n\n#include <cstdint>\n#include <algorithm>\n\nnamespace SQCompilation {\n\nstruct SourceLoc {\n    int32_t line;    // 1-based\n    int32_t column;  // 0-based\n\n    static SourceLoc invalid() { return {-1, -1}; }\n    bool isValid() const { return line >= 0; }\n\n    bool operator==(const SourceLoc &other) const {\n        return line == other.line && column == other.column;\n    }\n\n    bool operator!=(const SourceLoc &other) const {\n        return !(*this == other);\n    }\n};\n\nstruct SourceSpan {\n    SourceLoc start;\n    SourceLoc end;  // Exclusive (one past last char)\n\n    static SourceSpan invalid() { return {SourceLoc::invalid(), SourceLoc::invalid()}; }\n    bool isValid() const { return start.isValid() && end.isValid(); }\n\n    static SourceSpan merge(const SourceSpan &a, const SourceSpan &b) {\n        return {a.start, b.end};\n    }\n\n    int32_t textWidth() const {\n        if (start.line != end.line) return 1;\n        return std::max(1, end.column - start.column);\n    }\n\n    bool operator==(const SourceSpan &other) const {\n        return start == other.start && end == other.end;\n    }\n\n    bool operator!=(const SourceSpan &other) const {\n        return !(*this == other);\n    }\n};\n\n} // namespace SQCompilation\n\n#endif // _SQSOURCELOC_H_\n"
  },
  {
    "path": "squirrel/compiler/sqdump.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqtable.h\"\n#include \"opcodes.h\"\n#include \"sqvm.h\"\n#include \"sqio.h\"\n#include \"sqclosure.h\"\n#include \"sqarray.h\"\n\n#include <stdarg.h>\n\n#define SQ_OPCODE(id) {#id},\n\nSQInstructionDesc g_InstrDesc[]={\n    SQ_OPCODES_LIST\n};\n\n#undef SQ_OPCODE\n\n\nstatic void streamprintf(OutputStream *stream, const char *fmt, ...) {\n    static char buffer[4096] = { 0 };\n    va_list vl;\n    va_start(vl, fmt);\n    vsnprintf(buffer, 4096, fmt, vl);\n    va_end(vl);\n    stream->writeString(buffer);\n}\n\nstatic void DumpLiteral(OutputStream *stream, const SQObjectPtr &o)\n{\n    switch (sq_type(o)) {\n        case OT_NULL: streamprintf(stream, \"null\"); break;\n        case OT_STRING: streamprintf(stream, \"string(\\\"%s\\\")\", _stringval(o)); break;\n        case OT_FLOAT: streamprintf(stream, \"float(%1.9g)\", _float(o)); break;\n        case OT_INTEGER: streamprintf(stream, \"int(\" _PRINT_INT_FMT \")\", _integer(o)); break;\n        case OT_BOOL: streamprintf(stream, \"%s\", _integer(o) ? \"bool(true)\" : \"bool(false)\"); break;\n        case OT_ARRAY: streamprintf(stream, \"array(0x%p size=%d)\", (void*)_rawval(o), int(_array(o)->Size())); break;\n        case OT_TABLE: streamprintf(stream, \"table(0x%p size=%d)\", (void*)_rawval(o), int(_table(o)->CountUsed())); break;\n        case OT_CLOSURE:\n        {\n            SQFunctionProto *func = _closure(o)->_function;\n            const char *funcName = sq_isstring(func->_name) ? _stringval(func->_name) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)func, funcName);\n            break;\n        }\n        case OT_NATIVECLOSURE:\n        {\n            SQNativeClosure *nc = _nativeclosure(o);\n            const char* funcName = sq_isstring(nc->_name) ? _stringval(nc->_name) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)nc, funcName);\n            break;\n        }\n        case OT_FUNCPROTO:\n        {\n            SQFunctionProto *func = _funcproto(o);\n            const char* funcName = sq_isstring(func->_name) ? _stringval(func->_name) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)func, funcName);\n            break;\n        }\n        case OT_GENERATOR:\n        {\n            SQGenerator *gen = _generator(o);\n            SQObjectPtr nameObj = _closure(gen->_closure)->_function->_name;\n            const char* funcName = sq_isstring(nameObj) ? _stringval(nameObj) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)gen, funcName);\n            break;\n        }\n        default: streamprintf(stream, \"%s(0x%p)\", GetTypeName(o), (void*)_rawval(o)); break;\n    }\n}\n\nstatic uint64_t GetUInt64FromPtr(const void *ptr)\n{\n    uint64_t res = 0;\n    for (int i = 0; i < 8; i++)\n        res += uint64_t(((const uint8_t *)ptr)[i]) << (i * 8);\n    return res;\n}\n\nvoid DumpInstructions(OutputStream *stream, SQLineInfosHeader *lineinfos, int nlineinfos, const SQInstruction *ii, SQInt32 i_count,\n    const SQObjectPtr *_literals, SQInt32 _nliterals, const SQObjectPtr *_functions, SQInt32 _nfunctions, int instruction_index)\n{\n    SQInt32 n = 0;\n    int lineHint = 0;\n    for (int i = 0; i < i_count; i++) {\n        const SQInstruction &inst = ii[i];\n        bool isStepPoint = false;\n        char curInstr = instruction_index == i ? '>' : ' ';\n        SQInteger line = SQFunctionProto::GetLine(lineinfos, nlineinfos, i, &lineHint, &isStepPoint);\n        if (inst.op == _OP_LOAD || inst.op == _OP_DLOAD || inst.op == _OP_PREPCALLK || inst.op == _OP_GETK) {\n            SQInteger lidx = inst._arg1;\n            streamprintf(stream, \"[line%c%03d]%c[op %03d] %15s %d \", isStepPoint ? '-' : ' ', (SQInt32)line, curInstr, (SQInt32)n,\n                g_InstrDesc[inst.op].name, inst._arg0);\n            if (lidx >= 0xFFFFFFFF) //-V547\n                streamprintf(stream, \"null\");\n            else {\n                assert(lidx < _nliterals);\n                SQObjectPtr key = _literals[lidx];\n                DumpLiteral(stream, key);\n            }\n            if (inst.op != _OP_DLOAD) {\n                streamprintf(stream, \" %d %d\", inst._arg2, inst._arg3);\n            }\n            else {\n                streamprintf(stream, \" %d \", inst._arg2);\n                lidx = inst._arg3;\n                if (lidx >= 0xFFFFFFFF) //-V547\n                    streamprintf(stream, \"null\");\n                else {\n                    assert(lidx < _nliterals);\n                    SQObjectPtr key = _literals[lidx];\n                    DumpLiteral(stream, key);\n                }\n            }\n        }\n        /*  else if(inst.op==_OP_ARITH){\n                printf(\"[%03d] %15s %d %d %d %c\\n\",n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);\n            }*/\n        else {\n            int jumpLabel = 0x7FFFFFFF;\n            switch (inst.op) {\n            case _OP_JMP:\n                jumpLabel = i + inst._arg1 + 1;\n                break;\n            default:\n                break;\n            }\n            bool arg1F = inst.op == _OP_JCMPF || inst.op == _OP_LOADFLOAT;\n            if (arg1F)\n                streamprintf(stream, \"[line%c%03d]%c[op %03d] %15s %d %1.9g %d %d\", isStepPoint ? '-' : ' ', (SQInt32)line, curInstr, (SQInt32)n,\n                    g_InstrDesc[inst.op].name, inst._arg0, inst._farg1, inst._arg2, inst._arg3);\n            else\n            {\n                if (i > 0 && (ii[i - 1].op == _OP_SET_LITERAL || ii[i - 1].op == _OP_GET_LITERAL))\n                    streamprintf(stream, \"[line%c%03d]%c[op %03d] HINT (0x%\" PRIx64 \")\", isStepPoint ? '-' : ' ', (SQInt32)line, curInstr, (SQInt32)n,\n                        GetUInt64FromPtr(ii + i));\n                else if (inst.op < sizeof(g_InstrDesc) / sizeof(g_InstrDesc[0]))\n                    streamprintf(stream, \"[line%c%03d]%c[op %03d] %15s %d %d %d %d\", isStepPoint ? '-' : ' ', (SQInt32)line, curInstr, (SQInt32)n,\n                        g_InstrDesc[inst.op].name, inst._arg0, inst._arg1, inst._arg2, inst._arg3);\n                else\n                    streamprintf(stream, \"[line%c%03d]%c[op %03d] INVALID INSTRUNCTION (%d)\", isStepPoint ? '-' : ' ', (SQInt32)line, curInstr, (SQInt32)n,\n                        int(inst.op));\n            }\n            if (jumpLabel != 0x7FFFFFFF)\n                streamprintf(stream, \"  // jump to %d\", jumpLabel);\n        }\n\n        // comments\n        switch (inst.op) {\n            case _OP_LOAD:\n            case _OP_LOADFLOAT:\n            case _OP_LOADINT:\n            case _OP_LOADBOOL:\n            case _OP_LOADROOT:\n            case _OP_LOADCALLEE:\n                streamprintf(stream, \"  // -> r%d\", int(inst._arg0));\n                break;\n\n            case _OP_LOADNULLS:\n                streamprintf(stream, \"  // null -> [r%d .. r%d]\", int(inst._arg0), int(inst._arg0 + inst._arg1 - 1));\n                break;\n\n            case _OP_DLOAD: {\n                streamprintf(stream, \"  //\");\n                if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg1];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \" -> r%d, \", int(inst._arg0));\n                if (unsigned(inst._arg3) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg3];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \" -> r%d\", int(inst._arg2));\n                break;\n            }\n\n            case _OP_DATA_NOP: {\n                    int saveInstr = i + ((inst._arg2 << 8) + inst._arg3);\n                    if ((inst._arg0 || inst._arg1 || inst._arg2 || inst._arg3) && saveInstr > 0 && saveInstr < i_count &&\n                        ii[saveInstr].op == _OP_SAVE_STATIC_MEMO)\n                    {\n                        int loadInstr = saveInstr + 1 - ((ii[saveInstr]._arg2 << 8) + ii[saveInstr]._arg3);\n                        if (loadInstr == i) {\n                            streamprintf(stream, \"  // LOAD_STATIC_MEMO: staticmemo[%d] -> r%d, jump to %d%s\",\n                                int(inst._arg1 & STATIC_MEMO_IDX_MASK), int(inst._arg0), saveInstr + 1,\n                                (inst._arg1 & STATIC_MEMO_AUTO_FLAG) ? \" (auto)\" : \"\");\n                        }\n                    }\n                }\n                break;\n\n            case _OP_SAVE_STATIC_MEMO: {\n                    int loadInstr = i + 1 - ((inst._arg2 << 8) + inst._arg3);\n                    streamprintf(stream, \"  // r%d -> staticmemo[%d], r%d -> r%d, modify instr at %d%s\",\n                        int(inst._arg0), int(inst._arg1 & STATIC_MEMO_IDX_MASK), int(inst._arg0), int(ii[loadInstr]._arg0), loadInstr,\n                        (inst._arg1 & STATIC_MEMO_AUTO_FLAG) ? \" (auto)\" : \"\");\n                }\n                break;\n\n            case _OP_CALL:\n                streamprintf(stream, \"  // (call r%d) -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_NULLCALL:\n                streamprintf(stream, \"  // (if r%d then call r%d) -> r%d\", int(inst._arg1), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_MOVE:\n                streamprintf(stream, \"  // r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_GET:\n                streamprintf(stream, \"  // r%d[r%d] -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_NEWOBJ: {\n                const char *objType = inst._arg3 == NEWOBJ_TABLE ? \"table\" : (inst._arg3 == NEWOBJ_ARRAY ? \"array\" :\n                    (inst._arg3 == NEWOBJ_CLASS ? \"class\" : \"unknown\"));\n                streamprintf(stream, \"  // new %s -> r%d\", objType, int(inst._arg0));\n                break;\n            }\n\n            case _OP_CLOSURE: {\n                streamprintf(stream, \"  // closure \");\n                if (unsigned(inst._arg1) < unsigned(_nfunctions) && sq_isfunction(_functions[inst._arg1])) {\n                    SQFunctionProto *fp = _funcproto(_functions[inst._arg1]);\n                    if (sq_type(fp->_name) == OT_STRING)\n                        streamprintf(stream, \"%s\", _stringval(fp->_name));\n                }\n                streamprintf(stream, \" -> r%d\", int(inst._arg0));\n                break;\n            }\n\n            case _OP_APPENDARRAY: {\n                streamprintf(stream, \"  // r%d.append(\", int(inst._arg0));\n                switch (inst._arg2) {\n                    case AAT_STACK:\n                        streamprintf(stream, \"r%d\", int(inst._arg1));\n                        break;\n                    case AAT_LITERAL:\n                        if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                            const SQObjectPtr &key = _literals[inst._arg1];\n                            DumpLiteral(stream, key);\n                        }\n                        else {\n                            streamprintf(stream, \"?\");\n                        }\n                        break;\n                    case AAT_INT:\n                        streamprintf(stream, \"%d\", int(inst._arg1));\n                        break;\n                    case AAT_FLOAT:\n                        streamprintf(stream, \"%1.9g\", *((const SQFloat *)&inst._arg1));\n                        break;\n                    case AAT_BOOL:\n                        streamprintf(stream, \"%s\", inst._arg1 ? \"true\" : \"false\");\n                        break;\n                    default:\n                        streamprintf(stream, \"unknown\");\n                        break;\n                }\n\n                streamprintf(stream, \")\");\n                break;\n            }\n\n            case _OP_GETK:\n            case _OP_GET_LITERAL: {\n                streamprintf(stream, \"  // r%d.[\", int(inst._arg2));\n                if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg1];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \"] -> r%d\", int(inst._arg0));\n                break;\n            }\n\n            case _OP_SET:\n                if (inst._arg0 != 0xFF)\n                    streamprintf(stream, \"  // r%d[r%d] = r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg3), int(inst._arg0));\n                else\n                    streamprintf(stream, \"  // r%d[r%d] = r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg3));\n                break;\n\n            case _OP_SETK:\n            case _OP_SET_LITERAL: {\n                streamprintf(stream, \"  // r%d[\", int(inst._arg2));\n                if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg1];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                if (inst._arg0 != 0xFF)\n                    streamprintf(stream, \"] = r%d -> r%d\", int(inst._arg3), int(inst._arg0));\n                else\n                    streamprintf(stream, \"] = r%d\", int(inst._arg3));\n                break;\n            }\n\n            case _OP_SETI:\n                if (inst._arg0 != 0xFF)\n                    streamprintf(stream, \"  // r%d[%d] = r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg3), int(inst._arg0));\n                else\n                    streamprintf(stream, \"  // r%d[%d] = r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg3));\n                break;\n\n            case _OP_NEWSLOT:\n                streamprintf(stream, \"  // r%d[r%d] <- r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg3));\n                break;\n\n            case _OP_NEWSLOTK: {\n                streamprintf(stream, \"  // r%d[\", int(inst._arg2));\n                if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg1];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \"] <- r%d\", int(inst._arg3));\n                break;\n            }\n\n            case _OP_NEWSLOTA:\n                streamprintf(stream, \"  // r%d[r%d] <- r%d %s\", int(inst._arg1), int(inst._arg2), int(inst._arg3),\n                    (inst._arg0 & NEW_SLOT_STATIC_FLAG) ? \" static\" : \"\");\n                break;\n\n            case _OP_DELETE:\n                streamprintf(stream, \"  // delete r%d[r%d] -> r%d\", int(inst._arg1), int(inst._arg2), int(inst._arg0));\n                break;\n\n            case _OP_PREPCALL:\n                streamprintf(stream, \"  // r%d[r%d] -> func=r%d, this=r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0), int(inst._arg3));\n                break;\n\n            case _OP_PREPCALLK: {\n                streamprintf(stream, \"  // r%d[\", int(inst._arg2));\n                if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg1];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \"] -> func=r%d, this=r%d\", int(inst._arg0), int(inst._arg3));\n                break;\n            }\n\n            case _OP_TAILCALL:\n                streamprintf(stream, \"  // tailcall r%d(%d args) -> r%d\", int(inst._arg1), int(inst._arg3), int(inst._arg0));\n                break;\n\n            case _OP_DMOVE:\n                streamprintf(stream, \"  // r%d -> r%d, r%d -> r%d\", int(inst._arg1), int(inst._arg0), int(inst._arg3), int(inst._arg2));\n                break;\n\n            case _OP_RETURN:\n                if (inst._arg0 != 0xFF)\n                    streamprintf(stream, \"  // return r%d\", int(inst._arg1));\n                else\n                    streamprintf(stream, \"  // return null\");\n                break;\n\n            case _OP_EQ:\n            case _OP_NE: {\n                const char *op = inst.op == _OP_EQ ? \"==\" : \"!=\";\n                if (inst._arg3) {\n                    streamprintf(stream, \"  // r%d %s \", int(inst._arg2), op);\n                    if (unsigned(inst._arg1) < unsigned(_nliterals)) {\n                        const SQObjectPtr &key = _literals[inst._arg1];\n                        DumpLiteral(stream, key);\n                    }\n                    else {\n                        streamprintf(stream, \"?\");\n                    }\n                    streamprintf(stream, \" -> r%d\", int(inst._arg0));\n                }\n                else\n                    streamprintf(stream, \"  // r%d %s r%d -> r%d\", int(inst._arg2), op, int(inst._arg1), int(inst._arg0));\n                break;\n            }\n\n            case _OP_ADD:\n                streamprintf(stream, \"  // r%d + r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_SUB:\n                streamprintf(stream, \"  // r%d - r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_MUL:\n                streamprintf(stream, \"  // r%d * r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_DIV:\n                streamprintf(stream, \"  // r%d / r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_MOD:\n                streamprintf(stream, \"  // r%d %% r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_ADDI:\n                streamprintf(stream, \"  // r%d + %d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_BITW: {\n                const char *bwop = \"?\";\n                switch (inst._arg3) {\n                    case BW_AND: bwop = \"&\"; break;\n                    case BW_OR: bwop = \"|\"; break;\n                    case BW_XOR: bwop = \"^\"; break;\n                    case BW_SHIFTL: bwop = \"<<\"; break;\n                    case BW_SHIFTR: bwop = \">>\"; break;\n                    case BW_USHIFTR: bwop = \">>>\"; break;\n                }\n                streamprintf(stream, \"  // r%d %s r%d -> r%d\", int(inst._arg2), bwop, int(inst._arg1), int(inst._arg0));\n                break;\n            }\n\n            case _OP_NEG:\n                streamprintf(stream, \"  // -r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_NOT:\n                streamprintf(stream, \"  // !r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_BWNOT:\n                streamprintf(stream, \"  // ~r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_CMP: {\n                const char *cmpop = \"?\";\n                switch (inst._arg3) {\n                    case CMP_G: cmpop = \">\"; break;\n                    case CMP_GE: cmpop = \">=\"; break;\n                    case CMP_L: cmpop = \"<\"; break;\n                    case CMP_LE: cmpop = \"<=\"; break;\n                    case CMP_3W: cmpop = \"<=>\"; break;\n                }\n                streamprintf(stream, \"  // r%d %s r%d -> r%d\", int(inst._arg2), cmpop, int(inst._arg1), int(inst._arg0));\n                break;\n            }\n\n            case _OP_EXISTS:\n                streamprintf(stream, \"  // r%d in r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_INSTANCEOF:\n                streamprintf(stream, \"  // r%d instanceof r%d -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_AND:\n                streamprintf(stream, \"  // if r%d is false: r%d -> r%d, jump to %d\", int(inst._arg2), int(inst._arg2), int(inst._arg0), i + inst._arg1 + 1);\n                break;\n\n            case _OP_OR:\n                streamprintf(stream, \"  // if r%d is true: r%d -> r%d, jump to %d\", int(inst._arg2), int(inst._arg2), int(inst._arg0), i + inst._arg1 + 1);\n                break;\n\n            case _OP_NULLCOALESCE:\n                streamprintf(stream, \"  // if r%d != null: r%d -> r%d, jump to %d\", int(inst._arg2), int(inst._arg2), int(inst._arg0), i + inst._arg1);\n                break;\n\n            case _OP_GETOUTER:\n                streamprintf(stream, \"  // outer[%d] -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_SETOUTER:\n                if (inst._arg0 != 0xFF)\n                    streamprintf(stream, \"  // r%d -> outer[%d] -> r%d\", int(inst._arg2), int(inst._arg1), int(inst._arg0));\n                else\n                    streamprintf(stream, \"  // r%d -> outer[%d]\", int(inst._arg2), int(inst._arg1));\n                break;\n\n            case _OP_INC:\n                streamprintf(stream, \"  // r%d[r%d] += %d -> r%d\", int(inst._arg1), int(inst._arg2), int(inst._sarg3()), int(inst._arg0));\n                break;\n\n            case _OP_INCL:\n                streamprintf(stream, \"  // r%d += %d\", int(inst._arg1), int(inst._sarg3()));\n                break;\n\n            case _OP_PINC:\n                streamprintf(stream, \"  // r%d[r%d] (old -> r%d) += %d\", int(inst._arg1), int(inst._arg2), int(inst._arg0), int(inst._sarg3()));\n                break;\n\n            case _OP_PINCL:\n                streamprintf(stream, \"  // r%d (old -> r%d) += %d\", int(inst._arg1), int(inst._arg0), int(inst._sarg3()));\n                break;\n\n            case _OP_COMPARITH: {\n                int selfidx = (unsigned(inst._arg1) >> 16) & 0xFFFF;\n                int validx = unsigned(inst._arg1) & 0xFFFF;\n                streamprintf(stream, \"  // r%d[r%d] %c= r%d -> r%d\", selfidx, int(inst._arg2),\n                    char(inst._arg3), validx, int(inst._arg0));\n                break;\n            }\n\n            case _OP_COMPARITH_K: {\n                int selfidx = (unsigned(inst._arg1) >> 16) & 0xFFFF;\n                int validx = unsigned(inst._arg1) & 0xFFFF;\n                streamprintf(stream, \"  // r%d.[\", selfidx);\n                if (unsigned(inst._arg2) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg2];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \"] %c= r%d -> r%d\", char(inst._arg3), validx, int(inst._arg0));\n                break;\n            }\n\n            case _OP_YIELD:\n                if (inst._arg1 != 0xFF)\n                    streamprintf(stream, \"  // yield r%d\", int(inst._arg1));\n                else\n                    streamprintf(stream, \"  // yield null\");\n                break;\n\n            case _OP_RESUME:\n                streamprintf(stream, \"  // resume r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_CLONE:\n                streamprintf(stream, \"  // clone r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_TYPEOF:\n                streamprintf(stream, \"  // typeof r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_THROW:\n                streamprintf(stream, \"  // throw r%d\", int(inst._arg0));\n                break;\n\n            case _OP_GETBASE:\n                streamprintf(stream, \"  // base -> r%d\", int(inst._arg0));\n                break;\n\n            case _OP_CLOSE:\n                streamprintf(stream, \"  // close outers from r%d\", int(inst._arg1));\n                break;\n\n            case _OP_PREFOREACH:\n                streamprintf(stream, \"  // init iter r%d -> [r%d..r%d], if empty jump to %d\", int(inst._arg0), int(inst._arg2), int(inst._arg2 + 2), i + inst._arg1 + 1);\n                break;\n\n            case _OP_FOREACH:\n                streamprintf(stream, \"  // iter r%d next -> key=r%d, val=r%d, jump to %d\", int(inst._arg0), int(inst._arg2), int(inst._arg2 + 1), i + inst._arg1 + 1);\n                break;\n\n            case _OP_POSTFOREACH:\n                streamprintf(stream, \"  // if iter r%d dead jump to %d\", int(inst._arg0), i + inst._arg1 + 1);\n                break;\n\n            case _OP_FREEZE:\n                streamprintf(stream, \"  // freeze r%d -> r%d\", int(inst._arg1), int(inst._arg0));\n                break;\n\n            case _OP_CHECK_TYPE:\n                streamprintf(stream, \"  // check r%d type mask=0x%X\", int(inst._arg0), int(inst._arg1));\n                break;\n\n            case _OP_JZ:\n                if (inst._arg2)\n                    streamprintf(stream, \"  // if r%d jump to %d\", int(inst._arg0), i + inst._arg1 + 1);\n                else\n                    streamprintf(stream, \"  // if not r%d jump to %d\", int(inst._arg0), i + inst._arg1 + 1);\n                break;\n\n            case _OP_JCMP: {\n                const char *cmpop = \"?\";\n                bool negate = !(inst._arg3 >> 3);\n                switch (inst._arg3 & 0x7) {\n                    case CMP_G: cmpop = negate ? \"<=\" : \">\"; break;\n                    case CMP_GE: cmpop = negate ? \"<\" : \">=\"; break;\n                    case CMP_L: cmpop = negate ? \">=\" : \"<\"; break;\n                    case CMP_LE: cmpop = negate ? \">\" : \"<=\"; break;\n                    case CMP_3W: cmpop = \"<=>\"; break;\n                }\n                streamprintf(stream, \"  // if r%d %s r%d jump to %d\", int(inst._arg2), cmpop, int(inst._arg0), i + inst._arg1 + 1);\n                break;\n            }\n\n            case _OP_JCMPK: {\n                const char *cmpop = \"?\";\n                bool negate = !(inst._arg3 >> 3);\n                switch (inst._arg3 & 0x7) {\n                    case CMP_G: cmpop = negate ? \"<=\" : \">\"; break;\n                    case CMP_GE: cmpop = negate ? \"<\" : \">=\"; break;\n                    case CMP_L: cmpop = negate ? \">=\" : \"<\"; break;\n                    case CMP_LE: cmpop = negate ? \">\" : \"<=\"; break;\n                    case CMP_3W: cmpop = \"<=>\"; break;\n                }\n                streamprintf(stream, \"  // if r%d %s \", int(inst._arg2), cmpop);\n                if (unsigned(inst._arg0) < unsigned(_nliterals)) {\n                    const SQObjectPtr &key = _literals[inst._arg0];\n                    DumpLiteral(stream, key);\n                }\n                else {\n                    streamprintf(stream, \"?\");\n                }\n                streamprintf(stream, \" jump to %d\", i + inst._arg1 + 1);\n                break;\n            }\n\n            case _OP_JCMPI: {\n                const char *cmpop = \"?\";\n                bool negate = !(inst._arg3 >> 3);\n                switch (inst._arg3 & 0x7) {\n                    case CMP_G: cmpop = negate ? \"<=\" : \">\"; break;\n                    case CMP_GE: cmpop = negate ? \"<\" : \">=\"; break;\n                    case CMP_L: cmpop = negate ? \">=\" : \"<\"; break;\n                    case CMP_LE: cmpop = negate ? \">\" : \"<=\"; break;\n                    case CMP_3W: cmpop = \"<=>\"; break;\n                }\n                streamprintf(stream, \"  // if r%d %s %d jump to %d\", int(inst._arg2), cmpop, int(inst._arg1), i + inst._sarg0() + 1);\n                break;\n            }\n\n            case _OP_JCMPF: {\n                const char *cmpop = \"?\";\n                bool negate = !(inst._arg3 >> 3);\n                switch (inst._arg3 & 0x7) {\n                    case CMP_G: cmpop = negate ? \"<=\" : \">\"; break;\n                    case CMP_GE: cmpop = negate ? \"<\" : \">=\"; break;\n                    case CMP_L: cmpop = negate ? \">=\" : \"<\"; break;\n                    case CMP_LE: cmpop = negate ? \">\" : \"<=\"; break;\n                    case CMP_3W: cmpop = \"<=>\"; break;\n                }\n                streamprintf(stream, \"  // if r%d %s %g jump to %d\", int(inst._arg2), cmpop, inst._farg1, i + inst._sarg0() + 1);\n                break;\n            }\n\n            case _OP_LOAD_STATIC_MEMO:\n                streamprintf(stream, \"  // staticmemo[%d] -> r%d, jump to %d\", int(inst._arg1), int(inst._arg0), i + (inst._arg2 << 8) + inst._arg3 + 1);\n                break;\n\n            case _OP_PUSHTRAP:\n                streamprintf(stream, \"  // catch -> r%d, jump to %d\", int(inst._arg0), i + inst._arg1 + 1);\n                break;\n\n            case _OP_POPTRAP:\n                streamprintf(stream, \"  // pop %d trap(s)\", int(inst._arg0));\n                break;\n\n            case _OP_PATCH_DOCOBJ:\n                streamprintf(stream, \"  // patch docobj r%d\", int(inst._arg0));\n                break;\n\n            default:\n                break;\n        }\n        streamprintf(stream, \"\\n\");\n        n++;\n    }\n}\n\nstatic void DumpLiterals(OutputStream *stream, const SQObjectPtr *_literals, SQInt32 _nliterals)\n{\n    streamprintf(stream, \"-----LITERALS\\n\");\n    for (SQInt32 i = 0; i < _nliterals; ++i) {\n        streamprintf(stream, \"[%d] \", (SQInt32)i);\n        DumpLiteral(stream, _literals[i]);\n        streamprintf(stream, \"\\n\");\n    }\n}\n\nstatic void DumpStaticMemos(OutputStream *stream, const SQObjectPtr *_staticmemos, SQInt32 _nstaticmemos)\n{\n    streamprintf(stream, \"-----STATIC MEMOS\\n\");\n    for (SQInt32 i = 0; i < _nstaticmemos; ++i) {\n        streamprintf(stream, \"[%d] \", (SQInt32)i);\n        DumpLiteral(stream, _staticmemos[i]);\n        streamprintf(stream, \"\\n\");\n    }\n}\n\nstatic void DumpLocals(OutputStream *stream, const SQLocalVarInfo *_localvarinfos, SQInt32 _nlocalvarinfos)\n{\n    streamprintf(stream, \"-----LOCALS\\n\");\n    for (SQInt32 si = 0; si < _nlocalvarinfos; si++) {\n        SQLocalVarInfo lvi = _localvarinfos[si];\n        streamprintf(stream, \"[%d] %s \\t%d %d\\n\", (SQInt32)lvi._pos, _stringval(lvi._name), (SQInt32)lvi._start_op, (SQInt32)lvi._end_op);\n    }\n}\n\nstatic void DumpLineInfo(OutputStream *stream, const SQLineInfosHeader *_lineinfos, SQInt32 _nlineinfos)\n{\n    streamprintf(stream, \"-----LINE INFO\\n\");\n    for (SQInt32 i = 0; i < _nlineinfos; i++) {\n        int op = 0;\n        int line = 0;\n        bool isDbgStepPoint = false;\n        if (_lineinfos->_is_compressed) {\n            SQCompressedLineInfo li = ((SQCompressedLineInfo *)(void *)(_lineinfos + 1))[i];\n            op = li._op;\n            line = _lineinfos->_first_line + li._line_offset;\n            isDbgStepPoint = li._is_dbg_step_point;\n        } else {\n            SQFullLineInfo li = ((SQFullLineInfo *)(void *)(_lineinfos + 1))[i];\n            op = li._op;\n            line = _lineinfos->_first_line + li._line_offset;\n            isDbgStepPoint = li._is_dbg_step_point;\n        }\n        streamprintf(stream, \"op [%d] line [%d]%s\\n\", op, line, isDbgStepPoint ? \" dbgstep\" : \"\");\n    }\n}\n\nvoid Dump(OutputStream *stream, SQFunctionProto *func, bool deep, int instruction_index)\n{\n\n    //if (!dump_enable) return ;\n    SQUnsignedInteger n = 0, i;\n    if (deep) {\n        for (i = 0; i < func->_nfunctions; ++i) {\n            SQObjectPtr &f = func->_functions[i];\n            assert(sq_isfunction(f));\n            Dump(stream, _funcproto(f), deep, -1);\n        }\n    }\n    streamprintf(stream, \"SQInstruction sizeof %d\\n\", (SQInt32)sizeof(SQInstruction));\n    streamprintf(stream, \"SQObject sizeof %d\\n\", (SQInt32)sizeof(SQObject));\n    streamprintf(stream, \"--------------------------------------------------------------------\\n\");\n    streamprintf(stream, \"*****FUNCTION [%s]\\n\", sq_type(func->_name) == OT_STRING ? _stringval(func->_name) : \"unknown\");\n    DumpLiterals(stream, func->_literals, func->_nliterals);\n    DumpStaticMemos(stream, func->_staticmemos, func->_nstaticmemos);\n    streamprintf(stream, \"-----RESULT TYPE MASK = 0x%X\\n\", func->_result_type_mask);\n    streamprintf(stream, \"-----PARAMS\\n\");\n    if (func->_varparams)\n        streamprintf(stream, \"<<VARPARAMS>>\\n\");\n    n = 0;\n    for (i = 0; i < func->_nparameters; i++) {\n        streamprintf(stream, \"[%d] \", (SQInt32)n);\n        DumpLiteral(stream, func->_parameters[i]);\n        streamprintf(stream, \", type mask = 0x%X\\n\", func->_param_type_masks[i]);\n        n++;\n    }\n    DumpLocals(stream, func->_localvarinfos, func->_nlocalvarinfos);\n    DumpLineInfo(stream, func->_lineinfos, func->_nlineinfos);\n    streamprintf(stream, \"-----dump\\n\");\n    DumpInstructions(stream, func->_lineinfos, func->_nlineinfos,\n        func->_instructions, func->_ninstructions, func->_literals, func->_nliterals,\n        func->_functions, func->_nfunctions, instruction_index);\n    streamprintf(stream, \"-----\\n\");\n    streamprintf(stream, \"stack size[%d]\\n\", (SQInt32)func->_stacksize);\n    streamprintf(stream, \"--------------------------------------------------------------------\\n\\n\");\n}\n\nvoid Dump(SQFunctionProto *func, int instruction_index) {\n    FileOutputStream fos(stdout);\n    Dump(&fos, func, false, instruction_index);\n}\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/sqfuncstate.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqtable.h\"\n#include \"opcodes.h\"\n#include \"sqfuncstate.h\"\n#include \"sqio.h\"\n#include \"sqclosure.h\"\n#include \"sqarray.h\"\n\n#include <stdarg.h>\n\n\nstatic void streamprintf(OutputStream *stream, const char *fmt, ...) {\n    static char buffer[4096] = { 0 };\n    va_list vl;\n    va_start(vl, fmt);\n    vsnprintf(buffer, 4096, fmt, vl);\n    va_end(vl);\n    stream->writeString(buffer);\n}\n\nstatic void DumpLiteral(OutputStream *stream, const SQObjectPtr &o)\n{\n    switch (sq_type(o)) {\n        case OT_NULL: streamprintf(stream, \"null\"); break;\n        case OT_STRING: streamprintf(stream, \"string(\\\"%s\\\")\", _stringval(o)); break;\n        case OT_FLOAT: streamprintf(stream, \"float(%1.9g)\", _float(o)); break;\n        case OT_INTEGER: streamprintf(stream, \"int(\" _PRINT_INT_FMT \")\", _integer(o)); break;\n        case OT_BOOL: streamprintf(stream, \"%s\", _integer(o) ? \"bool(true)\" : \"bool(false)\"); break;\n        case OT_ARRAY: streamprintf(stream, \"array(0x%p size=%d)\", (void*)_rawval(o), int(_array(o)->Size())); break;\n        case OT_TABLE: streamprintf(stream, \"table(0x%p size=%d)\", (void*)_rawval(o), int(_table(o)->CountUsed())); break;\n        case OT_CLOSURE:\n        {\n            SQFunctionProto *func = _closure(o)->_function;\n            const char *funcName = sq_isstring(func->_name) ? _stringval(func->_name) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)func, funcName);\n            break;\n        }\n        case OT_NATIVECLOSURE:\n        {\n            SQNativeClosure *nc = _nativeclosure(o);\n            const char* funcName = sq_isstring(nc->_name) ? _stringval(nc->_name) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)nc, funcName);\n            break;\n        }\n        case OT_FUNCPROTO:\n        {\n            SQFunctionProto *func = _funcproto(o);\n            const char* funcName = sq_isstring(func->_name) ? _stringval(func->_name) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)func, funcName);\n            break;\n        }\n        case OT_GENERATOR:\n        {\n            SQGenerator *gen = _generator(o);\n            SQObjectPtr nameObj = _closure(gen->_closure)->_function->_name;\n            const char* funcName = sq_isstring(nameObj) ? _stringval(nameObj) : \"<null-name>\";\n            streamprintf(stream, \"%s(0x%p \\\"%s\\\")\", GetTypeName(o), (void*)gen, funcName);\n            break;\n        }\n        default: streamprintf(stream, \"%s(0x%p)\", GetTypeName(o), (void*)_rawval(o)); break;\n    }\n}\n\nSQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,SQCompilationContext &ctx) :\n    _vlocals(ss->_alloc_ctx),\n    _vlocals_info(ss->_alloc_ctx),\n    _targetstack(ss->_alloc_ctx),\n    _unresolvedbreaks(ss->_alloc_ctx),\n    _unresolvedcontinues(ss->_alloc_ctx),\n    _expr_block_results(ss->_alloc_ctx),\n    _functions(ss->_alloc_ctx),\n    _parameters(ss->_alloc_ctx),\n    _param_type_masks(ss->_alloc_ctx),\n    _outervalues(ss->_alloc_ctx),\n    _outervalues_info(ss->_alloc_ctx),\n    _instructions(ss->_alloc_ctx),\n    _localvarinfos(ss->_alloc_ctx),\n    _full_line_infos(ss->_alloc_ctx),\n    _breaktargets(ss->_alloc_ctx),\n    _continuetargets(ss->_alloc_ctx),\n    _blockstacksizes(ss->_alloc_ctx),\n    _defaultparams(ss->_alloc_ctx),\n    _childstates(ss->_alloc_ctx),\n    _ctx(ctx)\n{\n        _nliterals = 0;\n        _literals = SQTable::Create(ss,0);\n        _sharedstate = ss;\n        _lastline = 0;\n        _optimization = true;\n        _parent = parent;\n        _stacksize = 0;\n        _traps = 0;\n        _returnexp = 0;\n        _varparams = false;\n        _bgenerator = false;\n        _purefunction = false;\n        _nodiscard = false;\n        _outers = 0;\n        _hoistLevel = 0;\n        _staticmemos_count = 0;\n        _ss = ss;\n        _result_type_mask = ~0u;\n        lang_features = parent ? parent->lang_features : ss->defaultLangFeatures;\n}\n\nvoid ResetStaticMemos(SQFunctionProto *func, SQSharedState *ss)\n{\n    for (int i = 0; i < func->_nfunctions; i++) {\n        SQObjectPtr &f = func->_functions[i];\n        assert(sq_isfunction(f));\n        ResetStaticMemos(_funcproto(f), ss);\n    }\n\n    if (func->_nstaticmemos) {\n        SQInstruction* instr = func->_instructions;\n        int count = func->_ninstructions;\n\n        for (int i = 0; i < count; i += sq_opcode_length(instr[i].op)) {\n            if (instr[i].op == _OP_LOAD_STATIC_MEMO) {\n                SQInteger staticIdx = instr[i]._arg1;\n                assert(unsigned(staticIdx) < func->_nstaticmemos);\n                SQObjectPtr& storedStatic = func->_staticmemos[staticIdx];\n\n                if (ISREFCOUNTED(sq_type(storedStatic))) {\n                #ifdef NO_GARBAGE_COLLECTOR\n                    assert(storedStatic._unVal.pRefCounted->_uiRef > 1);\n                    __Release(storedStatic._type, storedStatic._unVal);\n                #else\n                    ss->_refs_table.Release(storedStatic);\n                #endif\n                }\n\n                func->_staticmemos[staticIdx].Null();\n                instr[i].op = _OP_DATA_NOP;\n            }\n        }\n    }\n}\n\n\nSQInteger SQFuncState::GetNumericConstant(const SQInteger cons)\n{\n    return GetConstant(SQObjectPtr(cons));\n}\n\nSQInteger SQFuncState::GetNumericConstant(const SQFloat cons)\n{\n    return GetConstant(SQObjectPtr(cons));\n}\n\nSQInteger SQFuncState::GetConstant(const SQObjectPtr &cons, int max_const_no)\n{\n    SQObjectPtr val;\n    max_const_no = max_const_no < MAX_LITERALS ? max_const_no : MAX_LITERALS;\n    if(!_table(_literals)->Get(cons,val))\n    {\n        if(_nliterals >= max_const_no) {\n            if (max_const_no == MAX_LITERALS)\n            {\n                val.Null();\n                _ctx.reportDiagnostic(DiagnosticsId::DI_TOO_MANY_SYMBOLS, -1, -1, 0, \"literals\");\n            } else\n                return -1;\n        }\n        val = _nliterals;\n        _table(_literals)->NewSlot(cons,val);\n        _nliterals++;\n    }\n    int iv = _integer(val);\n    return iv <= max_const_no ? iv : -1;\n}\n\nvoid SQFuncState::SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)\n{\n    _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);\n    _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);\n    _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);\n    _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);\n}\n\nvoid SQFuncState::SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val)\n{\n    switch(arg){\n        case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;\n        case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;\n        case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;\n        case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;\n    };\n}\n\nSQInteger SQFuncState::AllocStackPos()\n{\n    SQInteger npos=_vlocals.size();\n    if(npos >= MAX_FUNC_STACKSIZE)\n        _ctx.reportDiagnostic(DiagnosticsId::DI_TOO_MANY_SYMBOLS, -1, -1, 0, \"locals\");\n    _vlocals.push_back(SQLocalVarInfo());\n    _vlocals_info.push_back(SQCompiletimeVarInfo{});\n    if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {\n        _stacksize=_vlocals.size();\n    }\n    return npos;\n}\n\nSQInteger SQFuncState::PushTarget(SQInteger n)\n{\n    if(n!=-1){\n        _targetstack.push_back(n);\n        return n;\n    }\n    n=AllocStackPos();\n    _targetstack.push_back(n);\n    return n;\n}\n\nSQInteger SQFuncState::GetUpTarget(SQInteger n){\n    return _targetstack[((_targetstack.size()-1)-n)];\n}\n\nSQInteger SQFuncState::TopTarget(){\n    return _targetstack.back();\n}\nSQInteger SQFuncState::PopTarget()\n{\n    SQUnsignedInteger npos=_targetstack.back();\n    assert(npos < _vlocals.size());\n    SQLocalVarInfo &t = _vlocals[npos];\n    if(sq_type(t._name)==OT_NULL){\n        _vlocals.pop_back();\n        _vlocals_info.pop_back();\n    }\n    _targetstack.pop_back();\n    return npos;\n}\n\nSQInteger SQFuncState::GetStackSize()\n{\n    return _vlocals.size();\n}\n\nSQInteger SQFuncState::CountOuters(SQInteger stacksize)\n{\n    SQInteger outers = 0;\n    SQInteger k = _vlocals.size() - 1;\n    while(k >= stacksize) {\n        SQLocalVarInfo &lvi = _vlocals[k];\n        k--;\n        if(lvi._end_op == UINT32_MINUS_ONE) { //this means is an outer\n            outers++;\n        }\n    }\n    return outers;\n}\n\nvoid SQFuncState::SetStackSize(SQInteger n)\n{\n    SQInteger size=_vlocals.size();\n    while(size>n){\n        size--;\n        SQLocalVarInfo lvi = _vlocals.back();\n        if(sq_type(lvi._name)!=OT_NULL){\n            if(lvi._end_op == UINT32_MINUS_ONE) { //this means is an outer\n                _outers--;\n            }\n            lvi._end_op = GetCurrentPos();\n            _localvarinfos.push_back(lvi);\n        }\n        _vlocals.pop_back();\n        _vlocals_info.pop_back();\n    }\n}\n\n\nbool SQFuncState::IsLocal(SQUnsignedInteger stkpos)\n{\n    if(stkpos>=_vlocals.size())return false;\n    else if(sq_type(_vlocals[stkpos]._name)!=OT_NULL)return true;\n    return false;\n}\n\nSQInteger SQFuncState::PushLocalVariable(const SQObject &name, const SQCompiletimeVarInfo& ct_var_info)\n{\n    SQInteger pos=_vlocals.size();\n    SQLocalVarInfo lvi;\n    lvi._name=name;\n    lvi._start_op=GetCurrentPos()+1;\n    lvi._pos=_vlocals.size();\n    lvi._varFlags=ct_var_info.var_flags;\n    _vlocals.push_back(lvi);\n    _vlocals_info.push_back(ct_var_info);\n    if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();\n    return pos;\n}\n\n\n\nSQInteger SQFuncState::GetLocalVariable(const SQObject &name, SQCompiletimeVarInfo& ct_var_info)\n{\n    SQInteger locals=_vlocals.size();\n    while(locals>=1){\n        SQLocalVarInfo &lvi = _vlocals[locals-1];\n        if(sq_type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){\n            ct_var_info = _vlocals_info[locals-1];\n            return locals-1;\n        }\n        locals--;\n    }\n    return -1;\n}\n\nvoid SQFuncState::MarkLocalAsOuter(SQInteger pos)\n{\n    SQLocalVarInfo &lvi = _vlocals[pos];\n    lvi._end_op = UINT32_MINUS_ONE;\n    _outers++;\n}\n\n\nSQInteger SQFuncState::GetOuterVariable(const SQObject &name, SQCompiletimeVarInfo &varInfo)\n{\n    SQInteger outers = _outervalues.size();\n    for(SQInteger i = 0; i<outers; i++) {\n        if(_string(_outervalues[i]._name) == _string(name)) {\n            varInfo = _outervalues_info[i];\n            return i;\n        }\n    }\n    SQInteger pos=-1;\n    if(_parent) {\n        pos = _parent->GetLocalVariable(name, varInfo);\n        if(pos == -1) {\n            pos = _parent->GetOuterVariable(name, varInfo);\n            if(pos != -1) {\n                _outervalues.push_back(SQOuterVar(SQObjectPtr(name), SQObjectPtr(SQInteger(pos)), otOUTER, varInfo.var_flags)); //local\n                _outervalues_info.push_back(varInfo);\n                return _outervalues.size() - 1;\n            }\n        }\n        else {\n            _parent->MarkLocalAsOuter(pos);\n            _outervalues.push_back(SQOuterVar(SQObjectPtr(name), SQObjectPtr(SQInteger(pos)), otLOCAL, varInfo.var_flags)); //local\n            _outervalues_info.push_back(varInfo);\n            return _outervalues.size() - 1;\n        }\n    }\n    return -1;\n}\n\nvoid SQFuncState::AddParameter(const SQObject &name, SQUnsignedInteger32 type_mask) // TODO: initializer node\n{\n    PushLocalVariable(name, SQCompiletimeVarInfo{VF_PARAM | VF_ASSIGNABLE, type_mask, nullptr});\n    _parameters.push_back(SQObjectPtr(name));\n    _param_type_masks.push_back(type_mask);\n}\n\nvoid SQFuncState::AddLineInfos(SQInteger line, bool is_dbg_step_point, bool force)\n{\n    if(_lastline!=line || force){\n        if(_lastline!=line) {\n            SQFullLineInfo li;\n            li._op = (GetCurrentPos()+1);\n            li._line_offset = line;\n            li._is_dbg_step_point = is_dbg_step_point;\n            _full_line_infos.push_back(li);\n            if (is_dbg_step_point && _ctx.getVm()->_compile_line_hook)\n                _ctx.getVm()->_compile_line_hook(_ctx.getVm(), _ctx.sourceName(), line);\n        }\n        _lastline=line;\n    }\n}\n\nvoid SQFuncState::DiscardTarget()\n{\n    SQInteger discardedtarget = PopTarget();\n    SQInteger size = _instructions.size();\n    if(size > 0 && _optimization){\n        SQInstruction &pi = _instructions[size-1];//previous instruction\n        switch(pi.op) {\n        case _OP_SETI:case _OP_SETK:case _OP_SET:case _OP_NEWSLOTK:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL:case _OP_NULLCALL:\n            if(pi._arg0 == discardedtarget) {\n                pi._arg0 = 0xFF;\n            }\n        }\n    }\n}\n\nvoid SQFuncState::AddInstruction(SQInstruction &i)\n{\n    SQInteger size = _instructions.size();\n    if (size > 0 && _optimization && !(lang_features & LF_DISABLE_OPTIMIZER)){ //simple optimizer\n        SQInstruction &pi = _instructions[size-1];//previous instruction\n        switch(i.op) {\n        case _OP_JZ:\n            if( pi.op == _OP_CMP && pi._arg1 < 0xFF) {\n                pi.op = _OP_JCMP;\n                pi._arg0 = (unsigned char)pi._arg1;\n                pi._arg3 |= (uint8_t(i._arg2 ? 1 : 0)<<3);\n                pi._arg1 = i._arg1;\n                return;\n            }\n            break;\n        case _OP_SET:\n            if(i._arg0 == i._arg3) {\n                i._arg0 = 0xFF;\n            }\n            if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                // arg1 is size of int\n                pi._arg2 = i._arg2;\n                pi.op = _OP_SETK;\n                pi._arg0 = i._arg0;\n                pi._arg3 = i._arg3;\n                return;\n            }\n            if( pi.op == _OP_LOADINT && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                pi._arg2 = i._arg2;\n                pi.op = _OP_SETI;\n                // arg1 is size of int\n                pi._arg0 = i._arg0;\n                pi._arg3 = i._arg3;\n                return;\n            }\n            break;\n        case _OP_NEWSLOT:\n            if(i._arg0 == i._arg3) {\n                i._arg0 = 0xFF;\n            }\n            if( (pi.op == _OP_LOADINT || pi.op == _OP_LOAD) && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                // arg1 is size of int\n                pi._arg1 = pi.op == _OP_LOADINT ? GetNumericConstant((SQInteger)pi._arg1) : pi._arg1;\n                pi._arg0 = i._arg0;\n                pi._arg3 = i._arg3;\n                pi._arg2 = i._arg2;\n                pi.op = _OP_NEWSLOTK;\n                return;\n            }\n            break;\n        case _OP_SETI:\n        case _OP_SETK:\n        case _OP_NEWSLOTK:\n            if(i._arg0 == i._arg3) {\n                i._arg0 = 0xFF;\n            }\n            break;\n        case _OP_SETOUTER:\n            if(i._arg0 == i._arg2) {\n                i._arg0 = 0xFF;\n            }\n            break;\n        case _OP_RETURN:\n            if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {\n                pi.op = _OP_TAILCALL;\n            } else if(pi.op == _OP_CLOSE){\n                pi = i;\n                return;\n            }\n        break;\n        case _OP_GET:\n            if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                // arg1 is size of int\n                pi._arg2 = i._arg2;\n                pi.op = _OP_GETK;\n                pi._arg0 = i._arg0;\n                pi._arg3 = i._arg3;\n                return;\n            }\n            if( pi.op == _OP_LOADINT && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                // arg1 is size of int\n                // if (GetNumericConstant((SQInteger)pi._arg1) < 256)\n                pi._arg2 = i._arg2;\n                pi._arg1 = GetNumericConstant((SQInteger)pi._arg1);\n                pi.op = _OP_GETK;\n                pi._arg0 = i._arg0;\n                pi._arg3 = i._arg3;\n                return;\n            }\n        break;\n        case _OP_PREPCALL:\n            if( pi.op == _OP_LOAD  && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                pi.op = _OP_PREPCALLK;\n                pi._arg0 = i._arg0;\n                pi._arg2 = i._arg2;\n                pi._arg3 = i._arg3;\n                return;\n            }\n            break;\n        case _OP_APPENDARRAY: {\n            SQInteger aat = -1;\n            switch(pi.op) {\n            case _OP_LOAD: aat = AAT_LITERAL; break;\n            case _OP_LOADINT: aat = AAT_INT; break;\n            case _OP_LOADBOOL: aat = AAT_BOOL; break;\n            case _OP_LOADFLOAT: aat = AAT_FLOAT; break;\n            default: break;\n            }\n            if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){\n                pi.op = _OP_APPENDARRAY;\n                pi._arg0 = i._arg0;\n                pi._arg2 = (unsigned char)aat;\n                pi._arg3 = MAX_FUNC_STACKSIZE;\n                return;\n            }\n                              }\n            break;\n        case _OP_MOVE:\n            switch(pi.op) {\n            case _OP_GET: case _OP_GETK:\n            case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW:\n            case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD:\n            case _OP_NEG: case _OP_NOT: case _OP_BWNOT:\n            case _OP_ADDI:\n            case _OP_CMP:\n            case _OP_TYPEOF:\n            case _OP_CLONE:\n\n                if(pi._arg0 == i._arg1 && !IsLocal(pi._arg0))\n                {\n                    pi._arg0 = i._arg0;\n                    _optimization = false;\n                    return;\n                }\n            }\n\n            if(pi.op == _OP_GETOUTER && i._arg1 < 256 && i._arg0 && !pi._arg2)\n            {\n                pi._arg2 = i._arg0;\n                pi._arg3 = (unsigned char)i._arg1;\n                return;\n            }\n\n            if(pi.op == _OP_LOADCALLEE && i._arg1 < 256 && i._arg0 && !pi._arg2)\n            {\n                pi._arg2 = i._arg0;\n                pi._arg3 = (unsigned char)i._arg1;\n                return;\n            }\n\n            if(pi.op == _OP_MOVE && i._arg1 < 256)\n            {\n                pi.op = _OP_DMOVE;\n                pi._arg2 = i._arg0;\n                pi._arg3 = (unsigned char)i._arg1;\n                return;\n            }\n            break;\n        case _OP_LOAD:\n            if(pi.op == _OP_LOAD && i._arg1 < 256) {\n                pi.op = _OP_DLOAD;\n                pi._arg2 = i._arg0;\n                pi._arg3 = (unsigned char)i._arg1;\n                return;\n            }\n            break;\n        case _OP_EQ:case _OP_NE:\n            if((pi.op == _OP_LOAD || pi.op == _OP_LOADINT || pi.op == _OP_LOADFLOAT || pi.op == _OP_LOADBOOL) && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))\n            {\n                if (pi.op != _OP_LOAD)\n                {\n                    pi._arg1 = pi.op == _OP_LOADINT ? GetNumericConstant((SQInteger)pi._arg1) : pi.op == _OP_LOADFLOAT ? GetNumericConstant(pi._farg1) : GetConstant(SQObjectPtr(bool(pi._arg1)));\n                }\n                pi.op = i.op;\n                pi._arg0 = i._arg0;\n                pi._arg2 = i._arg2;\n                pi._arg3 = 1;\n                return;\n            }\n            break;\n        case _OP_LOADNULLS:\n            if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {\n\n                pi._arg1 = pi._arg1 + 1;\n                pi.op = _OP_LOADNULLS; //-V1048\n                return;\n            }\n            break;\n        }\n    }\n    _optimization = true;\n    _instructions.push_back(i);\n}\n\nSQObjectPtr SQFuncState::CreateString(const char *s,SQInteger len)\n{\n    return SQObjectPtr(SQString::Create(_sharedstate,s,len));\n}\n\nvoid SQFuncState::CheckForPurity()\n{\n    // Only set pure flag to true.\n    // Don't reset it to false, don't assume that non-pure operations make the function impure.\n    // Allow calls, arithmetics and other operations.\n    int count = _instructions.size();\n    for (int i = 0; i < count; i += sq_opcode_length(_instructions[i].op)) {\n        if (!sq_is_pure_op(_instructions[i].op)) {\n            return;\n        }\n    }\n\n    _purefunction = true;\n}\n\nSQFunctionProto *SQFuncState::BuildProto()\n{\n    bool useCompressedLineInfos = true;\n    int firstLine = INT_MAX;\n    int lastLine = 0;\n\n    for (SQUnsignedInteger ni = 0; ni < _full_line_infos.size(); ni++) {\n        int line = _full_line_infos[ni]._line_offset;\n        if (line < firstLine)\n            firstLine = line;\n        if (line > lastLine)\n            lastLine = line;\n        if (_full_line_infos[ni]._op > 255)\n            useCompressedLineInfos = false;\n    }\n\n    if (lastLine - firstLine > 127)\n        useCompressedLineInfos = false;\n\n    SQFunctionProto *f=SQFunctionProto::Create(_ss,lang_features,_instructions.size(),\n        _nliterals,_parameters.size(),_functions.size(),_outervalues.size(),\n        _full_line_infos.size(),useCompressedLineInfos,_localvarinfos.size(),_defaultparams.size(),\n        _staticmemos_count);\n\n    SQObjectPtr refidx,key,val;\n    SQInteger idx;\n\n    f->_stacksize = _stacksize;\n    f->_sourcename = _sourcename;\n    f->_bgenerator = _bgenerator;\n    f->_purefunction = _purefunction;\n    f->_nodiscard = _nodiscard;\n    f->_name = _name;\n    f->_inside_hoisted_scope = _hoistLevel > 0;\n    f->_result_type_mask = _result_type_mask;\n\n    while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {\n        f->_literals[_integer(val)]=key;\n        refidx=idx;\n    }\n\n    for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf];\n    for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no];\n    for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl];\n\n    for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) {\n        f->_parameters[np] = _parameters[np];\n        f->_param_type_masks[np] = _param_type_masks[np];\n    }\n\n    f->_lineinfos->_is_compressed = useCompressedLineInfos;\n    f->_lineinfos->_first_line = firstLine;\n    if (useCompressedLineInfos) {\n        for(SQUnsignedInteger ni = 0; ni < _full_line_infos.size(); ni++) {\n            SQCompressedLineInfo *li = (SQCompressedLineInfo *)(void *)(f->_lineinfos + 1) + ni;\n            li->_op = _full_line_infos[ni]._op;\n            li->_line_offset = _full_line_infos[ni]._line_offset - (unsigned)firstLine;\n            li->_is_dbg_step_point = _full_line_infos[ni]._is_dbg_step_point;\n        }\n    } else {\n        for(SQUnsignedInteger ni = 0; ni < _full_line_infos.size(); ni++) {\n            SQFullLineInfo *li = (SQFullLineInfo *)(void *)(f->_lineinfos + 1) + ni;\n            *li = _full_line_infos[ni];\n            li->_line_offset -= firstLine;\n        }\n    }\n\n    for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd];\n\n    memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction));\n\n    f->_varparams = _varparams;\n\n    return f;\n}\n\nSQFuncState *SQFuncState::PushChildState(SQSharedState *ss)\n{\n    SQFuncState *child = (SQFuncState *)sq_malloc(ss->_alloc_ctx, sizeof(SQFuncState));\n    new (child) SQFuncState(ss,this,_ctx);\n    _childstates.push_back(child);\n    return child;\n}\n\nvoid SQFuncState::PopChildState()\n{\n    SQFuncState *child = _childstates.back();\n    SQAllocContext ctx = _ss->_alloc_ctx;\n    sq_delete(ctx, child,SQFuncState);\n    _childstates.pop_back();\n}\n\nSQFuncState::~SQFuncState()\n{\n    while(_childstates.size() > 0)\n    {\n        PopChildState();\n    }\n}\n\n#endif\n"
  },
  {
    "path": "squirrel/compiler/sqfuncstate.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQFUNCSTATE_H_\n#define _SQFUNCSTATE_H_\n///////////////////////////////////\n#include \"squtils.h\"\n#include \"compilationcontext.h\"\n\nnamespace SQCompilation { class Expr; }\n\nusing namespace SQCompilation;\n\nstruct SQCompiletimeVarInfo\n{\n    char var_flags;\n    SQUnsignedInteger32 type_mask;\n    Expr *initializer;\n\n    SQCompiletimeVarInfo() { var_flags = 0; type_mask = ~0u; initializer = nullptr; }\n\n    SQCompiletimeVarInfo(char var_flags, SQUnsignedInteger32 type_mask, Expr *initializer) :\n        var_flags(var_flags), type_mask(type_mask), initializer(initializer) {}\n};\n\nstruct SQFuncState\n{\n    SQFuncState(SQSharedState *ss,SQFuncState *parent,SQCompilationContext &ctx);\n    ~SQFuncState();\n\n    SQFuncState *PushChildState(SQSharedState *ss);\n    void PopChildState();\n    void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);}\n    void AddInstruction(SQInstruction &i);\n    void SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0);\n    void SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val);\n    SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];}\n    void PopInstructions(SQInteger size){for(SQInteger i=0;i<size;i++)_instructions.pop_back();}\n    void SetStackSize(SQInteger n);\n    SQInteger CountOuters(SQInteger stacksize);\n    void SnoozeOpt(){_optimization=false;}\n    void RestoreOpt(){_optimization=true;}\n    void AddDefaultParam(SQInteger trg) { _defaultparams.push_back(trg); }\n    SQInteger GetDefaultParamCount() { return _defaultparams.size(); }\n    SQInteger GetCurrentPos(){return _instructions.size()-1;}\n    SQInteger GetNumericConstant(const SQInteger cons);\n    SQInteger GetNumericConstant(const SQFloat cons);\n    SQInteger PushLocalVariable(const SQObject &name, const SQCompiletimeVarInfo &ct_var_info);\n    void AddParameter(const SQObject &name, SQUnsignedInteger32 type_mask);\n    SQInteger GetLocalVariable(const SQObject &name, SQCompiletimeVarInfo &ct_var_info);\n    void MarkLocalAsOuter(SQInteger pos);\n    SQInteger GetOuterVariable(const SQObject &name, SQCompiletimeVarInfo &ct_var_info);\n    SQInteger GetStackSize();\n    void AddLineInfos(SQInteger line, bool is_dbg_step_point, bool force);\n    SQFunctionProto *BuildProto();\n    SQInteger AllocStackPos();\n    SQInteger PushTarget(SQInteger n=-1);\n    SQInteger PopTarget();\n    SQInteger TopTarget();\n    SQInteger GetUpTarget(SQInteger n);\n    void DiscardTarget();\n    bool IsLocal(SQUnsignedInteger stkpos);\n    SQObjectPtr CreateString(const char *s,SQInteger len = -1);\n    void CheckForPurity();\n    SQUnsignedInteger lang_features;\n    SQInteger _returnexp;\n    SQLocalVarInfoVec _vlocals;\n    sqvector<SQCompiletimeVarInfo> _vlocals_info; // compile time only\n    SQIntVec _targetstack;\n    SQInteger _stacksize;\n    bool _varparams;\n    bool _bgenerator;\n    bool _purefunction;\n    bool _nodiscard;\n    SQIntVec _unresolvedbreaks;\n    SQIntVec _unresolvedcontinues;\n    SQIntVec _expr_block_results;\n    SQObjectPtrVec _functions;\n    SQObjectPtrVec _parameters;\n    sqvector<SQUnsignedInteger32> _param_type_masks;\n    SQUnsignedInteger32 _result_type_mask;\n    SQOuterVarVec _outervalues;\n    sqvector<SQCompiletimeVarInfo> _outervalues_info; // compile time only\n    SQInstructionVec _instructions;\n    SQLocalVarInfoVec _localvarinfos;\n    SQObjectPtr _literals;\n    SQObjectPtr _name;\n    SQObjectPtr _sourcename;\n    SQInteger _nliterals;\n    SQFullLineInfoVec _full_line_infos;\n    SQFuncState *_parent;\n    SQIntVec _breaktargets;\n    SQIntVec _continuetargets;\n    SQIntVec _blockstacksizes;\n    SQIntVec _defaultparams;\n    SQInteger _lastline;\n    SQInteger _traps; //contains number of nested exception traps\n    SQInteger _outers;\n    SQInteger _hoistLevel;\n    SQInteger _staticmemos_count;\n    bool _optimization;\n    SQSharedState *_sharedstate;\n    sqvector<SQFuncState*> _childstates;\n    SQInteger GetConstant(const SQObjectPtr &cons, int max_const_no = 0x7FFFFFFF);//will return value <= max_const_no, or -1\nprivate:\n    SQCompilationContext &_ctx;\n    SQSharedState *_ss;\n};\n\n\n#endif //_SQFUNCSTATE_H_\n\n"
  },
  {
    "path": "squirrel/compiler/sqio.cpp",
    "content": "#include \"sqio.h\"\n#include <stdarg.h>\n#include <assert.h>\n#include <cstring>\n\ntypedef union {\n  uint64_t v;\n  uint8_t b[sizeof(uint64_t)];\n} U64Conv;\n\nuint64_t InputStream::readVaruint() {\n  uint64_t v = 0;\n  uint8_t t = 0;\n\n  uint8_t s = 0;\n\n  do {\n    t = readByte();\n    v |= uint64_t(t & 0x7F) << s;\n    s += 7;\n  } while (t & 0x80);\n\n  return v;\n}\n\nint64_t InputStream::readVarint() {\n  union {\n    int64_t i;\n    uint64_t u;\n  } conv;\n\n  conv.u = readVaruint();\n\n  return conv.i;\n}\n\nint8_t InputStream::readInt8() {\n\n  union {\n    int8_t i;\n    uint8_t u;\n  } conv;\n\n  conv.u = readByte();\n  return conv.i;\n}\n\nint16_t InputStream::readInt16() {\n  return (int16_t)readVarint();\n}\n\nint32_t InputStream::readInt32() {\n  return (int32_t)readVarint();\n}\n\nint64_t InputStream::readInt64() {\n  return (int64_t)readVarint();\n}\n\nintptr_t InputStream::readIntptr() {\n  return readInt64();\n}\n\nuint8_t InputStream::readUInt8() {\n  return readByte();\n}\n\nuint16_t InputStream::readUInt16() {\n  return (uint16_t)readVaruint();\n}\n\nuint32_t InputStream::readUInt32() {\n  return (uint32_t)readVaruint();\n}\n\nuint64_t InputStream::readUInt64() {\n  return readVaruint();\n}\n\nuintptr_t InputStream::readUIntptr() {\n  return readUInt64();\n}\n\nuint64_t InputStream::readRawUInt64() {\n  U64Conv conv;\n\n  for (int i = 0; i < sizeof conv.b; ++i) {\n    conv.b[i] = readByte();\n  }\n\n  return conv.v;\n}\n\n// ---------------------------------------------\n\nvoid OutputStream::writeVaruint(uint64_t v) {\n\n  while (v > 0x7F) {\n    writeByte(0x80 | uint8_t(v & 0x7F));\n    v >>= 7;\n  }\n\n  writeByte(uint8_t(v));\n}\n\nvoid OutputStream::writeVarint(int64_t v) {\n  union {\n    int64_t i;\n    uint64_t u;\n  } conv;\n\n  conv.i = v;\n\n  writeVaruint(conv.u);\n}\n\nvoid OutputStream::writeInt8(int8_t v) {\n  union {\n    uint8_t u;\n    int8_t i;\n  } conv;\n\n  conv.i = v;\n\n  writeByte(conv.u);\n}\n\nvoid OutputStream::writeInt16(int16_t v) {\n  writeVarint(v);\n}\n\nvoid OutputStream::writeInt32(int32_t v) {\n  writeVarint(v);\n}\n\nvoid OutputStream::writeInt64(int64_t v) {\n  writeVarint(v);\n}\n\nvoid OutputStream::writeIntptr(intptr_t v) {\n  writeInt64(v);\n}\n\nvoid OutputStream::writeUInt8(uint8_t v) {\n  writeByte(v);\n}\n\nvoid OutputStream::writeUInt16(uint16_t v) {\n  writeVaruint(v);\n}\n\nvoid OutputStream::writeUInt32(uint32_t v) {\n  writeVaruint(v);\n}\n\nvoid OutputStream::writeUInt64(uint64_t v) {\n  writeVaruint(v);\n}\n\nvoid OutputStream::writeUIntptr(uintptr_t v) {\n  writeUInt64(v);\n}\n\nvoid OutputStream::writeString(const char *s) {\n  while (*s) {\n    writeByte(*s++);\n  }\n}\n\nvoid OutputStream::writeChar(char c) {\n  writeInt8(c);\n}\n\nvoid OutputStream::writeRawUInt64(uint64_t v) {\n  U64Conv conv;\n\n  conv.v = v;\n\n  for (int i = 0; i < sizeof conv.b; ++i) {\n    writeByte(conv.b[i]);\n  }\n}\n\n//-------------------------------------------------------\n\nuint8_t StdInputStream::readByte() {\n  int v = i.get();\n  assert(v != EOF);\n  return static_cast<uint8_t>(v);\n}\n\nsize_t StdInputStream::pos() {\n  return static_cast<size_t>(i.tellg());\n}\n\nvoid StdInputStream::seek(size_t p) {\n  i.seekg(static_cast<std::streampos>(p));\n}\n\nFileInputStream::FileInputStream(const char *fileName) {\n  file = fopen(fileName, \"rb\");\n}\n\nFileInputStream::~FileInputStream() {\n  fclose(file);\n}\n\nuint8_t FileInputStream::readByte() {\n  int v = fgetc(file);\n  assert(v != EOF);\n  return static_cast<uint8_t>(v);\n}\n\nsize_t FileInputStream::pos() {\n  return static_cast<size_t>(ftell(file));\n}\n\nvoid FileInputStream::seek(size_t p) {\n  fseek(file, p, SEEK_SET);\n}\n\nuint8_t MemoryInputStream::readByte() {\n  assert(ptr < size);\n  return buffer[ptr++];\n}\n\nsize_t MemoryInputStream::pos() {\n  return ptr;\n}\n\nvoid MemoryInputStream::seek(size_t p) {\n  assert(p <= size);\n  ptr = p;\n}\n\n//-----------------------------------------------------------\n\nvoid StdOutputStream::writeByte(uint8_t v) {\n  o.put(v);\n}\n\nsize_t StdOutputStream::pos() {\n  return static_cast<size_t>(o.tellp());\n}\n\nvoid StdOutputStream::seek(size_t p) {\n  o.seekp(static_cast<std::streampos>(p));\n}\n\nFileOutputStream::FileOutputStream(const char *fileName) {\n  file = fopen(fileName, \"wb\");\n  close = true;\n}\n\nFileOutputStream::~FileOutputStream() {\n  if (close) {\n    fclose(file);\n  }\n}\n\nvoid FileOutputStream::writeByte(uint8_t v) {\n  fputc(v & 0xFF, file);\n}\n\nsize_t FileOutputStream::pos() {\n  return static_cast<size_t>(ftell(file));\n}\n\nvoid FileOutputStream::seek(size_t p) {\n  fseek(file, p, SEEK_SET);\n}\n\nMemoryOutputStream::~MemoryOutputStream() {\n  if (_buffer)\n    free(_buffer);\n}\n\nvoid MemoryOutputStream::resize(size_t n) {\n  if (n < _size) return;\n\n  uint8_t *newBuffer = (uint8_t*)malloc(n);\n  assert(newBuffer);\n\n  if (_buffer) {\n    memcpy(newBuffer, _buffer, _size * sizeof(uint8_t)); //-V575\n  }\n\n  free(_buffer);\n  _buffer = newBuffer;\n  _size = n;\n}\n\nvoid MemoryOutputStream::writeByte(uint8_t v) {\n  if (ptr >= _size) {\n    resize((_size + 512) << 2);\n  }\n\n  _buffer[ptr++] = v;\n}\n\nsize_t MemoryOutputStream::pos() {\n  return ptr;\n}\n\nvoid MemoryOutputStream::seek(size_t p) {\n  assert(p <= _size);\n  ptr = p;\n}"
  },
  {
    "path": "squirrel/compiler/sqtypeparser.cpp",
    "content": "#include \"sqtypeparser.h\"\n#include <sq_char_class.h>\n\n\nstruct SQRawTypeDecl\n{\n    const char * names[3]; // only [0] is valid, the rest are synonyms\n    SQUnsignedInteger32 typeMask;\n};\n\nstatic SQRawTypeDecl rawTypeDecls[] = {\n    { { \"bool\", \"boolean\", NULL }, _RT_BOOL },\n    { { \"number\", \"num\", NULL }, (_RT_FLOAT | _RT_INTEGER) },\n    { { \"int\", \"integer\", NULL }, _RT_INTEGER },\n    { { \"float\", \"double\", \"real\" }, _RT_FLOAT },\n    { { \"string\", \"str\", NULL }, _RT_STRING },\n    { { \"table\", \"dict\", \"map\" }, _RT_TABLE },\n    { { \"array\", \"list\", \"vector\" }, _RT_ARRAY },\n    { { \"userdata\", \"user\", \"object\" }, _RT_USERDATA },\n    { { \"function\", \"func\", \"closure\" }, (_RT_CLOSURE | _RT_NATIVECLOSURE) },\n    { { \"generator\", \"gen\", \"yield\" }, _RT_GENERATOR },\n    { { \"userpointer\", \"ptr\", \"pointer\" }, _RT_USERPOINTER },\n    { { \"thread\", \"coroutine\", \"fiber\" }, _RT_THREAD },\n    { { \"instance\", \"inst\", \"object\" }, _RT_INSTANCE },\n    { { \"class\", NULL, NULL }, _RT_CLASS },\n    { { \"weakref\", \"reference\", \"ref\" }, _RT_WEAKREF },\n    { { \"null\", \"nil\", \"none\" }, _RT_NULL },\n    { { \"any\", NULL, NULL }, ~0u },\n    { { NULL, NULL, NULL }, 0 }\n};\n\nstatic const char* skip_spaces(const char* s)\n{\n    while (*s && sq_isspace(*s))\n        s++;\n    return s;\n}\n\nstatic bool is_str_equal_ignore_case(const char* str1, const char* str2)\n{\n    while (*str1 && *str2 && sq_tolower(*str1) == sq_tolower(*str2))\n    {\n        str1++;\n        str2++;\n    }\n    return *str1 == *str2;\n}\n\nstatic bool parse_identifier(SQVM* vm, const char*& s, SQObjectPtr& res)\n{\n    const char* p = s;\n    if (!sq_isalpha(*p) && *p != '_')\n        return false;\n    p++;\n    while (sq_isalnum(*p) || *p == '_')\n        p++;\n    res = SQString::Create(_ss(vm), s, p - s);\n    s = p;\n    return true;\n}\n\nbool sq_type_string_to_mask(const char* type_name, SQUnsignedInteger32& mask, const char*& suggestion)\n{\n    bool found = false;\n    mask = 0;\n    suggestion = nullptr;\n    for (SQRawTypeDecl* decl = rawTypeDecls; decl->names[0]; decl++)\n    {\n        if (!strcmp(type_name, decl->names[0]))\n        {\n            mask |= decl->typeMask;\n            found = true;\n            break;\n        }\n\n        for (int syn = 0; syn < 3; syn++)\n            if (decl->names[syn] && is_str_equal_ignore_case(type_name, decl->names[syn]))\n                suggestion = decl->names[0];\n    }\n    return found;\n}\n\nstatic bool parse_type_mask(SQVM* vm, const char*& s, SQUnsignedInteger32& mask, SQInteger& error_pos, SQObjectPtr& error_string)\n{\n    mask = 0;\n    const char* p = skip_spaces(s);\n    bool hasBrackets = false;\n\n    if (*p == '(')\n    {\n        hasBrackets = true;\n        p++;\n        p = skip_spaces(p);\n    }\n\n    for (;;)\n    {\n        SQObjectPtr typeName;\n        if (!parse_identifier(vm, p, typeName))\n        {\n            error_pos = p - s;\n            error_string = SQString::Create(_ss(vm), \"Expected type name\");\n            return false;\n        }\n\n        const char* suggestion = nullptr;\n        SQUnsignedInteger32 currentTypeMask = 0;\n\n        bool found = sq_type_string_to_mask(_stringval(typeName), currentTypeMask, suggestion);\n\n        if (!found)\n        {\n            error_pos = p - s;\n            char buf[256];\n            if (suggestion)\n                scsprintf(buf, 256, \"Invalid type name '%s', did you mean '%s'?\", _stringval(typeName), suggestion);\n            else\n                scsprintf(buf, 256, \"Invalid type name '%s'\", _stringval(typeName));\n            error_string = SQString::Create(_ss(vm), buf);\n            return false;\n        }\n\n        mask |= currentTypeMask;\n\n        p = skip_spaces(p);\n        if (*p == '|')\n        {\n            p++;\n            p = skip_spaces(p);\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (hasBrackets)\n    {\n        if (*p != ')')\n        {\n            error_pos = p - s;\n            error_string = SQString::Create(_ss(vm), \"Expected ')' after type list\");\n            return false;\n        }\n        p++;\n        p = skip_spaces(p);\n    }\n\n    s = p;\n    return true;\n}\n\nbool sq_parse_function_type_string(SQVM* vm, const char* s, SQFunctionType& res, SQInteger& error_pos, SQObjectPtr& error_string)\n{\n    if (!s || !*s)\n    {\n        error_pos = 1;\n        error_string = SQString::Create(_ss(vm), \"Empty function type string\");\n        return false;\n    }\n\n    const char* p = skip_spaces(s);\n    res.objectTypeMask = ~0u;\n    res.returnTypeMask = _RT_NULL;\n    res.requiredArgs = 0;\n    res.ellipsisArgTypeMask = 0;\n    res.argNames.clear();\n    res.argTypeMask.clear();\n\n    for (;;)\n    {\n        if (strncmp(p, \"pure \", 5) == 0)\n        {\n            res.pure = true;\n            p = skip_spaces(p + 5);\n        }\n        else if (strncmp(p, \"nodiscard \", 10) == 0)\n        {\n            res.nodiscard = true;\n            p = skip_spaces(p + 10);\n        }\n        else\n            break;\n    }\n\n    if (*p == '(')\n    {\n        if (!parse_type_mask(vm, p, res.objectTypeMask, error_pos, error_string))\n        {\n            error_pos += p - s + 1;\n            return false;\n        }\n        p = skip_spaces(p);\n        if (*p != '.')\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Expected '.' after object type\");\n            return false;\n        }\n        p++;\n        p = skip_spaces(p);\n        if (!parse_identifier(vm, p, res.functionName))\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Expected function name after '.'\");\n            return false;\n        }\n    }\n    else\n    {\n        SQObjectPtr identifier1;\n        const char* p_initial = p;\n        if (!parse_identifier(vm, p, identifier1))\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Expected function name\");\n            return false;\n        }\n\n        if (*p == '.')\n        {\n            p++;\n            p = skip_spaces(p);\n            if (!parse_identifier(vm, p, res.functionName))\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Expected function name after '.'\");\n                return false;\n            }\n\n            const char* typeStr = _stringval(identifier1);\n            const char* typeStrPtr = typeStr;\n            SQUnsignedInteger32 objectTypeMask;\n            SQInteger error_pos_local;\n            SQObjectPtr error_string_local;\n\n            if (!parse_type_mask(vm, typeStrPtr, objectTypeMask, error_pos_local, error_string_local))\n            {\n                error_pos = (p_initial - s) + error_pos_local;\n                error_string = error_string_local;\n                return false;\n            }\n\n            if (*typeStrPtr != '\\0')\n            {\n                error_pos = (p_initial - s) + (typeStrPtr - typeStr);\n                error_string = SQString::Create(_ss(vm), \"Invalid object type\");\n                return false;\n            }\n\n            res.objectTypeMask = objectTypeMask;\n        }\n        else\n        {\n            res.functionName = identifier1;\n        }\n    }\n\n    p = skip_spaces(p);\n\n    if (*p != '(')\n    {\n        error_pos = p - s + 1;\n        error_string = SQString::Create(_ss(vm), \"Expected '(' after function name\");\n        return false;\n    }\n\n    p++;\n    p = skip_spaces(p);\n\n    bool insideString = false;\n    bool insideOptional = false;\n    bool optionalBlockFinished = false;\n    bool argumentProcessed = false;\n    while (*p != ')')\n    {\n        p = skip_spaces(p);\n        if (*p == '\\0')\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Unterminated argument list\");\n            return false;\n        }\n\n        if (*p == '[')\n        {\n            if (insideOptional)\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Nested optional blocks are not allowed\");\n                return false;\n            }\n            if (optionalBlockFinished)\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Optional block must be the last argument\");\n                return false;\n            }\n            insideOptional = true;\n            p++;\n            p = skip_spaces(p);\n            continue;\n        }\n\n        if (*p == ']')\n        {\n            if (!insideOptional)\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Unmatched ']'\");\n                return false;\n            }\n            insideOptional = false;\n            optionalBlockFinished = true;\n            p++;\n            p = skip_spaces(p);\n            continue;\n        }\n\n        if (*p == ',')\n        {\n            if (!argumentProcessed)\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Argument expected before ','\");\n                return false;\n            }\n            p++;\n            p = skip_spaces(p);\n            argumentProcessed = false;\n            continue;\n        }\n\n        if (strncmp(p, \"...\", 3) == 0)\n        {\n            argumentProcessed = true;\n\n            if (res.ellipsisArgTypeMask != 0)\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Multiple ellipsis arguments\");\n                return false;\n            }\n\n            p += 3;\n            p = skip_spaces(p);\n\n            if (*p == ':')\n            {\n                p++;\n                p = skip_spaces(p);\n                if (!parse_type_mask(vm, p, res.ellipsisArgTypeMask, error_pos, error_string))\n                {\n                    error_pos += p - s + 1;\n                    return false;\n                }\n            }\n            else\n            {\n                res.ellipsisArgTypeMask = ~0u;\n            }\n\n            p = skip_spaces(p);\n\n            if (*p != ')' && *p != ']')\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Expected ')' after ellipsis argument\");\n                return false;\n            }\n\n            continue;\n        }\n\n        if (optionalBlockFinished)\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Argument after optional block\");\n            return false;\n        }\n\n        SQObjectPtr argName;\n        if (!parse_identifier(vm, p, argName))\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Expected argument name\");\n            return false;\n        }\n\n        argumentProcessed = true;\n\n        SQUnsignedInteger32 argTypeMask = ~0u;\n        p = skip_spaces(p);\n        if (*p == ':')\n        {\n            p++;\n            p = skip_spaces(p);\n            if (!parse_type_mask(vm, p, argTypeMask, error_pos, error_string))\n            {\n                error_pos += p - s + 1;\n                return false;\n            }\n        }\n        else if (*p != ',' && *p != ')' && *p != ']' && *p != '[' && *p != '=')\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Expected ':' after argument name\");\n            return false;\n        }\n\n        SQObjectPtr defaultValue;\n        char stringOpener = '\\0';\n\n        if (*p == '=')\n        {\n            p++;\n            p = skip_spaces(p);\n\n            char stack[40];\n            int stackIndex = 0;\n\n            const char * startDefaultValue = p;\n            while (*p != '\\0')\n            {\n                if (insideString)\n                {\n                    if (*p == stringOpener)\n                    {\n                        insideString = false;\n                        p++;\n                        continue;\n                    }\n                    else if (*p == '\\\\')\n                    {\n                        p++;\n                        if (*p == '\\0')\n                        {\n                            error_pos = p - s + 1;\n                            error_string = SQString::Create(_ss(vm), \"Unterminated string in default value\");\n                            return false;\n                        }\n                    }\n\n                    p++;\n                    continue;\n                }\n                else if (*p == '\"' || *p == '\\'')\n                {\n                    insideString = true;\n                    stringOpener = *p;\n                    p++;\n                    continue;\n                }\n\n                if (stackIndex >= sizeof(stack) - 1)\n                {\n                    error_pos = p - s + 1;\n                    error_string = SQString::Create(_ss(vm), \"Default value too complex. Too many nested structures\");\n                    return false;\n                }\n\n                if (*p == '(')\n                    stack[stackIndex++] = '(';\n                else if (*p == ')')\n                {\n                    if (stackIndex == 0)\n                        break; // end of default value\n\n                    if (stack[stackIndex - 1] != '(')\n                    {\n                        error_pos = p - s + 1;\n                        error_string = SQString::Create(_ss(vm), \"Unmatched ')' in default value\");\n                        return false;\n                    }\n                    stackIndex--;\n                }\n                else if (*p == '[')\n                    stack[stackIndex++] = '[';\n                else if (*p == ']')\n                {\n                    if (stackIndex == 0)\n                        break; // end of default value\n\n                    if (stack[stackIndex - 1] != '[')\n                    {\n                        error_pos = p - s + 1;\n                        error_string = SQString::Create(_ss(vm), \"Unmatched ']' in default value\");\n                        return false;\n                    }\n                    stackIndex--;\n                }\n                else if (*p == '{')\n                    stack[stackIndex++] = '{';\n                else if (*p == '}')\n                {\n                    if (stackIndex == 0 || stack[stackIndex - 1] != '{')\n                    {\n                        error_pos = p - s + 1;\n                        error_string = SQString::Create(_ss(vm), \"Unmatched '}' in default value\");\n                        return false;\n                    }\n                    stackIndex--;\n                }\n                else if (*p == ',' && stackIndex == 0)\n                {\n                    break; // end of default value\n                }\n\n                p++;\n                p = skip_spaces(p);\n            }\n\n            if (stackIndex > 0)\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Unfinished default value, unmatched brackets\");\n                return false;\n            }\n\n            if (*p == '\\0')\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Unterminated function type string\");\n                return false;\n            }\n\n            SQInteger defaultValueLength = p - startDefaultValue;\n            if (defaultValueLength > 0)\n                defaultValue = SQString::Create(_ss(vm), startDefaultValue, defaultValueLength);\n            else\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Expected default value after '='\");\n                return false;\n            }\n        }\n        else // have no default value\n        {\n            if (!insideOptional && res.defaultValues.size() > 0 && !sq_isnull(res.defaultValues.back()))\n            {\n                error_pos = p - s + 1;\n                error_string = SQString::Create(_ss(vm), \"Default value expected after optional argument\");\n                return false;\n            }\n        }\n\n        res.argNames.push_back(argName);\n        res.argTypeMask.push_back(argTypeMask);\n        res.defaultValues.push_back(defaultValue);\n\n        if (!insideOptional && sq_isnull(defaultValue))\n        {\n            res.requiredArgs++;\n        }\n\n        p = skip_spaces(p);\n        if (*p == ',')\n        {\n            p++;\n            p = skip_spaces(p);\n        }\n        else if (*p != ')' && *p != ']' && *p != '[')\n        {\n            error_pos = p - s + 1;\n            error_string = SQString::Create(_ss(vm), \"Expected ',' or ')'\");\n            return false;\n        }\n    }\n\n    // *p == ')'\n\n    if (insideOptional)\n    {\n        error_pos = p - s + 1;\n        error_string = SQString::Create(_ss(vm), \"Unmatched '['\");\n        return false;\n    }\n\n    if (insideString)\n    {\n        error_pos = p - s + 1;\n        error_string = SQString::Create(_ss(vm), \"Unterminated string in function type\");\n        return false;\n    }\n\n    p++;\n    p = skip_spaces(p);\n\n    if (*p == ':')\n    {\n        p++;\n        p = skip_spaces(p);\n        if (!parse_type_mask(vm, p, res.returnTypeMask, error_pos, error_string))\n        {\n            error_pos += p - s + 1;\n            return false;\n        }\n    }\n\n    p = skip_spaces(p);\n    if (*p != '\\0')\n    {\n        error_pos = p - s + 1;\n        error_string = SQString::Create(_ss(vm), \"Unexpected characters after function type string\");\n        return false;\n    }\n\n    return true;\n}\n\n\nvoid sq_stringify_type_mask(char* buffer, int buffer_length, SQUnsignedInteger32 mask)\n{\n    assert(buffer_length > 128);\n\n    if ((mask & _RT_CLOSURE) || (mask & _RT_NATIVECLOSURE))\n        mask |= _RT_CLOSURE | _RT_NATIVECLOSURE;\n\n    char* p = buffer;\n    char* end = buffer + buffer_length - 1;\n\n    auto append = [&](const char* str)\n    {\n        while (*str && p < end)\n            *p++ = *str++;\n    };\n\n    if (mask == ~0u)\n    {\n        append(\"any\");\n        *p = '\\0';\n        return;\n    }\n\n    bool first = true;\n    for (const SQRawTypeDecl* decl = rawTypeDecls; decl->names[0]; decl++)\n        if ((mask & decl->typeMask) == decl->typeMask)\n        {\n            if (!first)\n                append(\"|\");\n\n            append(decl->names[0]);\n            first = false;\n            mask &= ~decl->typeMask;\n        }\n\n    *p = '\\0';\n}\n\n\nSQObjectPtr sq_stringify_function_type(SQVM* vm, const SQFunctionType& ft)\n{\n    const SQInteger bufferSize = 2048; // 2KB buffer\n    char buffer[bufferSize];\n    char* p = buffer;\n    char* end = buffer + bufferSize - 1;\n\n    if (sq_isnull(ft.functionName))\n    {\n        SQObjectPtr tmp;\n        return tmp;\n    }\n\n    auto append = [&](const char* str)\n    {\n        while (*str && p < end)\n        {\n            *p++ = *str++;\n        }\n    };\n\n    auto appendTypeMask = [&](SQUnsignedInteger32 typeMask) {\n        if (typeMask == ~0u)\n        {\n            append(\"any\");\n            return;\n        }\n\n        bool first = true;\n        for (const SQRawTypeDecl* decl = rawTypeDecls; decl->names[0]; decl++)\n        {\n            if ((typeMask & decl->typeMask) == decl->typeMask)\n            {\n                if (!first)\n                {\n                    append(\"|\");\n                }\n                append(decl->names[0]);\n                first = false;\n                typeMask &= ~decl->typeMask;\n            }\n        }\n    };\n\n    if (ft.pure)\n        append(\"pure \");\n\n    if (ft.nodiscard)\n        append(\"nodiscard \");\n\n    if (ft.objectTypeMask != ~0u)\n    {\n        bool isComplexType = true;\n        for (const SQRawTypeDecl* decl = rawTypeDecls; decl->names[0]; decl++)\n            if (ft.objectTypeMask == decl->typeMask)\n            {\n                isComplexType = false;\n                break;\n            }\n\n        if (isComplexType)\n            append(\"(\");\n\n        appendTypeMask(ft.objectTypeMask);\n\n        if (isComplexType)\n            append(\")\");\n\n        append(\".\");\n    }\n\n    append(_stringval(ft.functionName));\n\n    append(\"(\");\n    for (SQInteger i = 0; i < ft.argNames.size(); i++)\n    {\n        if (i > 0)\n            append(\", \");\n\n        if (i == ft.requiredArgs)\n            append(\"[\");\n\n        append(_stringval(ft.argNames[i]));\n\n        if (ft.argTypeMask[i] != ~0u)\n        {\n            append(\": \");\n            appendTypeMask(ft.argTypeMask[i]);\n        }\n\n        if (!sq_isnull(ft.defaultValues[i]))\n        {\n            append(\" = \");\n            if (sq_isstring(ft.defaultValues[i]))\n                append(_stringval(ft.defaultValues[i]));\n            else\n                append(\"<default value>\");\n        }\n    }\n\n    if (ft.argNames.size() > ft.requiredArgs)\n        append(\"]\");\n\n    if (ft.ellipsisArgTypeMask != 0)\n    {\n        if (ft.argNames.size() > 0)\n        {\n            append(\", \");\n        }\n        append(\"...\");\n        if (ft.ellipsisArgTypeMask != ~0u)\n        {\n            append(\": \");\n            appendTypeMask(ft.ellipsisArgTypeMask);\n        }\n    }\n\n    append(\")\");\n\n    if (ft.returnTypeMask != _RT_NULL)\n    {\n        append(\": \");\n        appendTypeMask(ft.returnTypeMask);\n    }\n\n    *p = '\\0';\n\n    return SQObjectPtr(SQString::Create(_ss(vm), buffer, p - buffer));\n}\n"
  },
  {
    "path": "squirrel/compiler/sqtypeparser.h",
    "content": "#pragma once\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"squtils.h\"\n\nstruct SQFunctionType\n{\n    SQObjectPtr functionName;\n    SQUnsignedInteger32 returnTypeMask;\n    SQUnsignedInteger32 objectTypeMask;\n    sqvector<SQObjectPtr> argNames;\n    sqvector<SQUnsignedInteger32> argTypeMask;\n    sqvector<SQObjectPtr> defaultValues; // null|string\n    SQInteger requiredArgs; // Not including `this`\n    SQUnsignedInteger32 ellipsisArgTypeMask; // 0 if no ellipsis\n    bool pure;\n    bool nodiscard;\n\n    SQFunctionType(SQSharedState *ss) :\n        argNames(ss->_alloc_ctx),\n        defaultValues(ss->_alloc_ctx),\n        argTypeMask(ss->_alloc_ctx)\n    {\n        returnTypeMask = ~0u;\n        objectTypeMask = ~0u;\n        requiredArgs = 0;\n        ellipsisArgTypeMask = 0;\n        pure = false;\n        nodiscard = false;\n    }\n};\n\nbool sq_parse_function_type_string(SQVM* vm, const char* s, SQFunctionType& res, SQInteger& error_pos, SQObjectPtr& error_string);\nSQObjectPtr sq_stringify_function_type(SQVM* vm, const SQFunctionType& ft);\nbool sq_type_string_to_mask(const char* type_name, SQUnsignedInteger32& mask, const char*& suggestion);\nvoid sq_stringify_type_mask(char* buffer, int buffer_length, SQUnsignedInteger32 mask);\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/analyzer.cpp",
    "content": "#include \"analyzer.h\"\n#include <squirrel.h>\n\n#include \"sqtable.h\"\n\n#include \"name_shadowing_checker.h\"\n#include \"operator_classification.h\"\n#include \"checker_visitor.h\"\n#include \"global_state.h\"\n\n\nnamespace SQCompilation {\n\n\nconst char *symbolContextName(SymbolKind k) {\n  switch (k)\n  {\n  case SK_EXCEPTION: return \"exception\";\n  case SK_FUNCTION: return \"function\";\n  case SK_CLASS: return \"class\";\n  case SK_TABLE: return \"table\";\n  case SK_VAR: return \"variable\";\n  case SK_BINDING: return \"binding\";\n  case SK_CONST: return \"const\";\n  case SK_ENUM: return \"enum\";\n  case SK_ENUM_CONST: return \"enum const\";\n  case SK_PARAM: return \"parameter\";\n  case SK_FOREACH: return \"iteration variable\";\n  case SK_EXTERNAL_BINDING: return \"external binding\";\n  case SK_IMPORT: return \"import\";\n  default: return \"<unknown>\";\n  }\n}\n\nvoid FunctionInfo::joinModifiable(const FunctionInfo *other) {\n  for (auto &m : other->modifiable) {\n    if (owner == m.owner)\n      continue;\n\n    addModifiable(m.name, m.owner);\n  }\n}\n\nvoid FunctionInfo::addModifiable(const char *name, const FunctionExpr *o) {\n  for (auto &m : modifiable) {\n    if (m.owner == o && strcmp(name, m.name) == 0)\n      return;\n  }\n\n  modifiable.push_back({ o, name });\n}\n\n\n//================================================================\n\n\nStaticAnalyzer::StaticAnalyzer(SQCompilationContext &ctx)\n  : _ctx(ctx) {\n}\n\n\nvoid StaticAnalyzer::reportGlobalNamesWarnings(HSQUIRRELVM vm) {\n  auto errorFunc = _ss(vm)->_compilererrorhandler;\n\n  if (!errorFunc)\n    return;\n\n  // 1. Check multiple declarations\n\n  std::string message;\n\n  for (auto it = declaredGlobals.begin(); it != declaredGlobals.end(); ++it) {\n    const char *name = it->first.c_str();\n    const auto &declarations = it->second;\n\n    if (declarations.size() == 1)\n      continue;\n\n    for (int32_t i = 0; i < declarations.size(); ++i) {\n      const IdLocation &loc = declarations[i];\n      if (loc.diagSilenced)\n        continue;\n\n      message.clear();\n      SQCompilationContext::renderDiagnosticHeader(DiagnosticsId::DI_GLOBAL_NAME_REDEF, &message, name);\n      errorFunc(vm, SEV_WARNING, message.c_str(), loc.filename, loc.line, loc.column, \"\\n\");\n    }\n  }\n\n  // 2. Check undefined usages\n\n  for (auto it = usedGlobals.begin(); it != usedGlobals.end(); ++it) {\n    const std::string &id = it->first;\n\n    bool isKnownBinding = knownBindings.find(id) != knownBindings.end();\n    if (isKnownBinding)\n      continue;\n\n    if (declaredGlobals.find(id) != declaredGlobals.end())\n      continue;\n\n    const auto &usages = it->second;\n\n    for (int32_t i = 0; i < usages.size(); ++i) {\n      const IdLocation &loc = usages[i];\n      if (loc.diagSilenced)\n        continue;\n\n      message.clear();\n      SQCompilationContext::renderDiagnosticHeader(DiagnosticsId::DI_UNDEFINED_GLOBAL, &message, id.c_str());\n      errorFunc(vm, SEV_WARNING, message.c_str(), loc.filename, loc.line, loc.column, \"\\n\");\n    }\n  }\n}\n\nstatic bool isSpaceOrTab(char c) { return c == '\\t' || c == ' '; }\n\nvoid StaticAnalyzer::checkTrailingWhitespaces(HSQUIRRELVM vm, const char *sourceName, const char *code, size_t codeSize) {\n  Arena arena(_ss(vm)->_alloc_ctx, \"tmp\");\n  SQCompilationContext ctx(vm, &arena, sourceName, code, codeSize, nullptr, true);\n\n  int32_t line = 1;\n  int32_t column = 1;\n\n  for (int32_t idx = 0; idx < codeSize - 1; ++idx, ++column) {\n    if (isSpaceOrTab(code[idx])) {\n      int next = code[idx + 1];\n      if (!next || next == '\\n' || next == '\\r') {\n        ctx.reportDiagnostic(DiagnosticsId::DI_SPACE_AT_EOL, line, column - 1, 1);\n      }\n    }\n    else if (code[idx] == '\\n') {\n      column = 0;\n      line++;\n    }\n  }\n}\n\nvoid StaticAnalyzer::mergeKnownBindings(const HSQOBJECT *bindings) {\n  if (bindings && sq_istable(*bindings)) {\n    SQTable *table = _table(*bindings);\n\n    SQInteger idx = 0;\n    SQObjectPtr pos(idx), key, val;\n\n    while ((idx = table->Next(false, pos, key, val)) >= 0) {\n      if (sq_isstring(key)) {\n        SQInteger len = _string(key)->_len;\n        const char *s = _string(key)->_val;\n        knownBindings.emplace(std::string(s, s+len));\n      }\n      pos._unVal.nInteger = idx;\n    }\n  }\n}\n\nvoid StaticAnalyzer::runAnalysis(RootBlock *root, const HSQOBJECT *bindings)\n{\n  mergeKnownBindings(bindings);\n  CheckerVisitor(_ctx).analyze(root, bindings);\n  NameShadowingChecker(_ctx, bindings).analyze(root);\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/analyzer.h",
    "content": "#pragma once\n\n#include \"compiler/ast.h\"\n#include \"compiler/compilationcontext.h\"\n\nnamespace SQCompilation {\n\nclass StaticAnalyzer {\n\n  SQCompilationContext &_ctx;\n\npublic:\n\n  StaticAnalyzer(SQCompilationContext &ctx);\n\n  void runAnalysis(RootBlock *r, const HSQOBJECT *bindings);\n\n  static void mergeKnownBindings(const HSQOBJECT *bindings);\n  static void reportGlobalNamesWarnings(HSQUIRRELVM vm);\n\n  static void checkTrailingWhitespaces(HSQUIRRELVM vm, const char *sn, const char *code, size_t codeSize);\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/analyzer_internal.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\n\nenum ReturnTypeBits\n{\n  RT_NOTHING = 1 << 0,\n  RT_NULL = 1 << 1,\n  RT_BOOL = 1 << 2,\n  RT_NUMBER = 1 << 3,\n  RT_STRING = 1 << 4,\n  RT_TABLE = 1 << 5,\n  RT_ARRAY = 1 << 6,\n  RT_CLOSURE = 1 << 7,\n  RT_FUNCTION_CALL = 1 << 8,\n  RT_UNRECOGNIZED = 1 << 9,\n  RT_THROW = 1 << 10,\n  RT_CLASS = 1 << 11,\n};\n\n\ninline const char *enumFqn(Arena *arena, const char *enumName, const char *cname) {\n  int32_t l1 = strlen(enumName);\n  int32_t l2 = strlen(cname);\n  int32_t l = l1 + 1 + l2 + 1;\n  char *r = (char *)arena->allocate(l);\n  snprintf(r, l, \"%s.%s\", enumName, cname);\n  return r;\n}\n\n\ninline int32_t strhash(const char *s) {\n  int32_t r = 0;\n  while (*s) {\n    r *= 31;\n    r += *s;\n    ++s;\n  }\n\n  return r;\n}\n\nstruct StringHasher {\n  int32_t operator()(const char *s) const {\n    return strhash(s);\n  }\n};\n\nstruct StringEqualer {\n  int32_t operator()(const char *a, const char *b) const {\n    return strcmp(a, b) == 0;\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/assign_seq_terminator.h",
    "content": "#pragma once\n\n#include \"compiler/compilationcontext.h\"\n#include \"compiler/ast.h\"\n#include \"node_equal_checker.h\"\n\n\nnamespace SQCompilation\n{\n\nclass AssignSeqTerminatorFinder : public Visitor {\n\n  const Expr *assignee;\n  bool foundUsage;\n  bool foundInterruptor;\n\n  NodeEqualChecker eqChecker;\n\npublic:\n  AssignSeqTerminatorFinder(const Expr *asg) : assignee(asg), foundUsage(false), foundInterruptor(false), eqChecker() {}\n\n  void visitNode(Node *n) {\n    if (!foundInterruptor && !foundUsage)\n      Visitor::visitNode(n);\n  }\n\n  void visitCallExpr(CallExpr *c) {\n    foundInterruptor = true; // consider call as potential usage\n  }\n\n  void visitExpr(Expr *e) {\n    Visitor::visitExpr(e);\n\n    if (eqChecker.check(assignee, e))\n      foundUsage = true;\n  }\n\n  void visitFunctionExpr(FunctionExpr *e) { /* skip */ }\n\n  bool check(Node *tree) {\n    tree->visit(this);\n    return foundUsage || foundInterruptor;\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/ast_helpers.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\ninline const Expr *deparen(const Expr *e) {\n  if (!e) return nullptr;\n\n  if (e->op() == TO_PAREN)\n    return deparen(static_cast<const UnExpr *>(e)->argument());\n  return e;\n}\n\ninline const Expr *deparenStatic(const Expr *e) {\n  if (!e) return nullptr;\n\n  if (e->op() == TO_PAREN || e->op() == TO_STATIC_MEMO)\n    return deparen(static_cast<const UnExpr *>(e)->argument());\n  return e;\n}\n\ninline const Expr *skipUnary(const Expr *e) {\n  if (!e) return nullptr;\n\n  if (e->op() == TO_INC) {\n    return skipUnary(static_cast<const IncExpr *>(e)->argument());\n  }\n\n  if (TO_NOT <= e->op() && e->op() <= TO_DELETE) {\n    return skipUnary(static_cast<const UnExpr *>(e)->argument());\n  }\n\n  return e;\n}\n\ninline const Statement *lastNonEmpty(const Block *b, int32_t &effectiveSize) {\n  const Statement *r = nullptr;\n  effectiveSize = 0;\n  for (auto stmt : b->statements()) {\n    if (stmt->op() != TO_EMPTY) {\n      r = stmt;\n      effectiveSize += 1;\n    }\n  }\n\n  return r;\n}\n\ninline const Statement *unwrapBody(const Statement *stmt) {\n  if (!stmt)\n    return nullptr;\n\n  if (stmt->op() != TO_BLOCK)\n    return stmt;\n\n  auto &stmts = stmt->asBlock()->statements();\n\n  if (stmts.empty())\n    return nullptr;\n\n  return unwrapBody(stmts.back());\n}\n\n// in contrast to `unwrapBody(...)` above this function skips empty statements\ninline const Statement *unwrapBodyNonEmpty(const Statement *stmt) {\n\n  if (stmt == nullptr)\n    return stmt;\n\n  if (stmt->op() != TO_BLOCK)\n    return stmt;\n\n  int32_t effectiveSize = 0;\n  const Statement *last = lastNonEmpty(stmt->asBlock(), effectiveSize);\n\n  if (effectiveSize == 0)\n    return nullptr;\n\n  return unwrapBodyNonEmpty(last);\n}\n\ninline const Statement *unwrapSingleBlock(const Statement *stmt) {\n  if (!stmt)\n    return nullptr;\n\n  if (stmt->op() != TO_BLOCK)\n    return stmt;\n\n  int32_t effectiveSize = 0;\n  const Statement *last = lastNonEmpty(stmt->asBlock(), effectiveSize);\n\n  if (effectiveSize == 0)\n    return nullptr;\n\n  if (effectiveSize != 1)\n    return stmt;\n\n  return unwrapSingleBlock(last);\n}\n\ninline Expr *unwrapExprStatement(Statement *stmt) {\n  return stmt->op() == TO_EXPR_STMT ? static_cast<ExprStatement *>(stmt)->expression() : nullptr;\n}\n\n\ninline const FunctionExpr *extractFunction(const Node *n) {\n  if (!n)\n    return nullptr;\n\n  if (n->op() == TO_FUNCTION)\n    return static_cast<const FunctionExpr *>(n);\n\n  if (n->op() == TO_VAR)\n    return extractFunction(n->asDeclaration()->asVarDecl()->initializer());\n\n  return nullptr;\n}\n\n\ninline const Expr *extractAssignedExpression(const Node *n) {\n  if (n->op() == TO_ASSIGN || n->op() == TO_NEWSLOT)\n    return static_cast<const BinExpr *>(n)->rhs();\n\n  if (n->op() == TO_VAR)\n    return static_cast<const VarDecl *>(n)->initializer();\n\n  return nullptr;\n}\n\n\ninline const Id *extractReceiver(const Expr *e) {\n  const Expr *last = e;\n\n  for (;;) {\n    e = deparenStatic(e);\n\n    if (e->op() == TO_CALL) { // -V522\n      const CallExpr *c = e->asCallExpr();\n      e = c->callee();\n      if (c->isNullable())\n        last = c->callee();\n    } else if (e->isAccessExpr()) { // -V522\n      const AccessExpr *acc = e->asAccessExpr();\n      e = acc->receiver();\n      if (acc->isNullable())\n        last = acc->receiver();\n    } else {\n      break;\n    }\n  }\n\n  return last->op() == TO_ID ? last->asId() : nullptr;\n}\n\n\ninline bool isFallThroughStatement(const Statement *stmt) {\n  TreeOp op = stmt->op();\n\n  return op != TO_RETURN && op != TO_THROW && op != TO_BREAK && op != TO_CONTINUE;\n}\n\n\ninline bool isFallThroughBranch(const Statement *stmt) {\n  if (stmt->op() != TO_BLOCK)\n    return isFallThroughStatement(stmt);\n\n  const Block *blk = stmt->asBlock();\n\n  for (const Statement *s : blk->statements()) {\n    if (!isFallThroughStatement(s))\n      return false;\n  }\n\n  return true;\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/breakable_scope.h",
    "content": "#pragma once\n\n#include \"checker_visitor.h\"\n\nnamespace SQCompilation\n{\n\nstruct VarScope;\n\nenum BreakableScopeKind {\n  BSK_LOOP,\n  BSK_SWITCH\n};\n\nstruct BreakableScope {\n  BreakableScopeKind kind;\n\n  BreakableScope *parent;\n\n  union {\n    const LoopStatement *loop;\n    const SwitchStatement *swtch;\n  } node;\n\n  VarScope *loopScope;\n  VarScope *exitScope;\n  CheckerVisitor *visitor;\n\n  BreakableScope(CheckerVisitor *v, const SwitchStatement *swtch)\n  : visitor(v), kind(BSK_SWITCH), loopScope(nullptr), exitScope(nullptr), parent(v->breakScope)\n  {\n    node.swtch = swtch;\n    v->breakScope = this;\n  }\n  BreakableScope(CheckerVisitor *v, const LoopStatement *loop, VarScope *ls, VarScope *es)\n    : visitor(v), kind(BSK_LOOP), loopScope(ls), exitScope(es), parent(v->breakScope)\n  {\n    assert(ls/* && es*/);\n    node.loop = loop;\n    v->breakScope = this;\n  }\n  ~BreakableScope()\n  {\n    visitor->breakScope = parent;\n  }\n};\n\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/checker_visitor.cpp",
    "content": "#include <assert.h>\n#include <squirrel.h>\n#include <limits.h>\n\n#include \"checker_visitor.h\"\n#include \"node_complexity_counter.h\"\n#include \"node_diff_computer.h\"\n#include \"node_equal_checker.h\"\n#include \"function_ret_type_eval.h\"\n#include \"modification_checker.h\"\n#include \"loop_terminator_collector.h\"\n#include \"ast_helpers.h\"\n#include \"analyzer_internal.h\"\n#include \"operator_classification.h\"\n#include \"assign_seq_terminator.h\"\n#include \"var_scope.h\"\n#include \"value_ref.h\"\n#include \"symbol_info.h\"\n#include \"naming.h\"\n#include \"config.h\"\n#include \"global_state.h\"\n#include \"breakable_scope.h\"\n\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqclass.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include <sq_char_class.h>\n\n\n\nnamespace SQCompilation\n{\n\nstatic bool isBinaryArith(const Expr *expr) {\n  return TO_OROR <= expr->op() && expr->op() <= TO_SUB;\n}\n\nstatic bool isAssignExpr(const Expr *expr) {\n  return isAssignOp(expr->op());\n}\n\nstatic bool looksLikeBooleanExpr(const Expr *e) {\n  TreeOp op = e->op(); // -V522\n  if (isBooleanResultOperator(op))\n    return true;\n\n  if (op == TO_LITERAL) {\n    return e->asLiteral()->kind() == LK_BOOL; // -V522\n  }\n\n  if (op == TO_NULLC || op == TO_ANDAND || op == TO_OROR) {\n    // check for `x?.y {??, ||, &&} false`\n    return looksLikeBooleanExpr(e->asBinExpr()->rhs());\n  }\n\n  return false;\n}\n\n\nvoid CheckerVisitor::putIntoGlobalNamesMap(std::unordered_map<std::string, std::vector<IdLocation>> &map, enum DiagnosticsId diag, const char *name, const Node *d) {\n  std::string sourcenameCache(_ctx.sourceName());\n\n  auto fnIt = fileNames.find(sourcenameCache);\n  IdLocation loc;\n\n  if (fnIt == fileNames.end()) {\n    auto it2 = fileNames.insert(sourcenameCache);\n    loc.filename = it2.first->c_str();\n  }\n  else {\n    loc.filename = fnIt->c_str();\n  }\n\n  loc.line = d->lineStart();\n  loc.column = d->columnStart();\n  loc.diagSilenced = _ctx.isDisabled(diag, loc.line, loc.column);\n\n  std::string key(name);\n\n  auto it = map.find(key);\n\n  if (it != map.end()) {\n    it->second.push_back(loc);\n  }\n  else {\n    auto it2 = map.insert({ key, std::vector<IdLocation>() });\n    it2.first->second.push_back(loc);\n  }\n}\n\nvoid CheckerVisitor::storeGlobalDeclaration(const char *name, const Node *d) {\n  putIntoGlobalNamesMap(declaredGlobals, DiagnosticsId::DI_GLOBAL_NAME_REDEF, name, d);\n}\n\nvoid CheckerVisitor::storeGlobalUsage(const char *name, const Node *d) {\n  putIntoGlobalNamesMap(usedGlobals, DiagnosticsId::DI_UNDEFINED_GLOBAL, name, d);\n}\n\n\nCheckerVisitor::~CheckerVisitor() {\n  for (auto &p : functionInfoMap) {\n    if (p.second)\n      p.second->~FunctionInfo();\n  }\n  for (auto ev : externalValues)\n    ev->~ExternalValueExpr();\n}\n\nvoid CheckerVisitor::visitNode(Node *n) {\n  nodeStack.push_back({ SST_NODE, n });\n  Visitor::visitNode(n);\n  nodeStack.pop_back();\n}\n\nvoid CheckerVisitor::report(const Node *n, int32_t id, ...) {\n  if (isEffectsGatheringPass)\n    return;\n\n  va_list vargs;\n  va_start(vargs, id);\n\n  _ctx.vreportDiagnostic((enum DiagnosticsId)id, n->lineStart(), n->columnStart(), n->textWidth(), vargs); // -V522\n\n  va_end(vargs);\n}\n\nvoid CheckerVisitor::reportImportSlot(int line, int column, const char *name) {\n  if (isEffectsGatheringPass)\n    return;\n\n  int width = (int)strlen(name);\n  _ctx.reportDiagnostic(DiagnosticsId::DI_IMPORTED_NEVER_USED, line, column, width, name);\n}\n\n\nvoid CheckerVisitor::checkIdUsed(const Id *id, const Node *p, ValueRef *v) {\n  const Expr *e = nullptr;\n  if (p) {\n    if (p->op() == TO_EXPR_STMT)\n      e = static_cast<const ExprStatement *>(p)->expression();\n    else if (p->isExpression())\n      e = p->asExpression();\n  }\n\n  bool assigned = v->assigned;\n\n  if (e && isAssignExpr(e)) {\n    const BinExpr *bin = static_cast<const BinExpr *>(e);\n    const Expr *lhs = bin->lhs();\n    Expr *rhs = bin->rhs();\n    bool simpleAsgn = e->op() == TO_ASSIGN;\n    if (id == lhs) {\n      bool used = v->info->usedAfterAssign || existsInTree(id, rhs);\n      v->info->used |= used;\n      v->assigned = true;\n      v->lastAssigneeScope = currentScope;\n      v->info->usedAfterAssign = false;\n      if (simpleAsgn)\n        return;\n    }\n  }\n\n  // it's usage\n  v->info->used = true;\n  if (assigned) {\n    v->info->usedAfterAssign = true;\n    v->assigned = e ? TO_PLUSEQ <= e->op() && e->op() <= TO_MODEQ : false;\n  }\n}\n\nvoid CheckerVisitor::checkAccessFromStatic(const GetFieldExpr *acc) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *r = acc->receiver();\n\n  if (r->op() != TO_ID || strcmp(r->asId()->name(), \"this\") != 0)\n    return;\n\n  const TableMember *m = nullptr;\n  const ClassExpr *klass = nullptr;\n\n  for (auto it = nodeStack.rbegin(); it != nodeStack.rend(); ++it) {\n    if (it->sst == SST_TABLE_MEMBER) {\n      m = it->member;\n      ++it;\n\n      if (it != nodeStack.rend() && it->sst == SST_NODE && it->n->op() == TO_CLASS) {\n        klass = static_cast<const ClassExpr *>(it->n);\n      }\n\n      break;\n    }\n  }\n\n  if (!m || !m->isStatic() || !klass)\n    return;\n\n  const auto &members = klass->members();\n  const char *memberName = acc->fieldName();\n\n  for (const auto &m : members) {\n    if (m.key->op() == TO_LITERAL && m.key->asLiteral()->kind() == LK_STRING) {\n      const char *klassMemberName = m.key->asLiteral()->s();\n      if (strcmp(memberName, klassMemberName) == 0) {\n        if (!m.isStatic())\n          report(acc, DiagnosticsId::DI_USED_FROM_STATIC, memberName, \"static member\");\n        return;\n      }\n    }\n  }\n\n  report(acc, DiagnosticsId::DI_USED_FROM_STATIC, memberName, \"static member\");\n}\n\nbool CheckerVisitor::hasDynamicContent(const SQObject &container) {\n  if (!sq_istable(container))\n    return false;\n  SQObjectPtr key(_ctx.getVm(), \"__dynamic_content__\");\n  SQObjectPtr val;\n  return _table(container)->Get(key, val);\n}\n\nvoid CheckerVisitor::checkExternalField(const GetFieldExpr *acc) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *r = acc->receiver();\n  r = maybeEval(r, true);\n  if (r->op() != TO_EXTERNAL_VALUE)\n    return;\n\n  const auto &container = r->asExternal()->value();\n  if (sq_isinstance(container))\n    return;\n\n  SQObjectPtr key(_ctx.getVm(), acc->fieldName());\n  SQObject rawVal;\n  if (!SQ_SUCCEEDED(sq_obj_get(_ctx.getVm(), &container, &key, &rawVal, false))) {\n    if (!acc->isNullable() && !hasDynamicContent(container)) {\n      report(acc, DI_MISSING_FIELD, acc->fieldName(), GetTypeName(container));\n      char buf[128];\n      snprintf(buf, sizeof(buf), \"source of %s\", GetTypeName(container));\n      report(r, DI_SEE_OTHER, buf);\n    }\n    return;\n  }\n  sq_poptop(_ctx.getVm()); // pop the stack copy pushed by sq_obj_get\n\n  astValues[acc] = addExternalValue(rawVal, acc);\n}\n\nstatic bool cannotBeNull(const Expr *e) {\n  switch (e->op())\n  {\n  case TO_INC:\n  case TO_NEG: case TO_NOT: case TO_BNOT:\n  case TO_3CMP:\n  case TO_XOR: case TO_OR: case TO_AND:\n  case TO_EQ: case TO_NE: case TO_LE: case TO_LT: case TO_GE: case TO_GT:\n  case TO_IN: case TO_INSTANCEOF:\n  case TO_USHR: case TO_SHL: case TO_SHR:\n  case TO_ADD: case TO_SUB:  case TO_MUL: case TO_DIV: /*case TO_MOD:*/\n  case TO_TYPEOF: case TO_RESUME:\n  case TO_BASE: case TO_ROOT_TABLE_ACCESS:\n  case TO_ARRAY: case TO_TABLE: case TO_CLASS: case TO_FUNCTION:\n    return true;\n  case TO_LITERAL:\n    return e->asLiteral()->kind() != LK_NULL;\n  default:\n    return false;\n  }\n}\n\nvoid CheckerVisitor::reportIfCannotBeNull(const Expr *checkee, const Expr *n, const char *loc) {\n  assert(n);\n\n  if (checkee->op() == TO_NULLC) {\n    checkee = maybeEval(static_cast<const BinExpr *>(checkee)->rhs());\n  }\n\n  if (checkee->op() == TO_TERNARY) {\n    const TerExpr *ter = static_cast<const TerExpr *>(checkee);\n    const Expr *ifTrue = maybeEval(ter->b());\n    const Expr *ifFalse = maybeEval(ter->c());\n\n    if (cannotBeNull(ifTrue) && cannotBeNull(ifFalse)) {\n      report(n, DiagnosticsId::DI_EXPR_NOT_NULL, loc);\n    }\n    return;\n  }\n\n  if (cannotBeNull(checkee))\n    report(n, DiagnosticsId::DI_EXPR_NOT_NULL, loc);\n}\n\nvoid CheckerVisitor::reportModifyIfContainer(const Expr *e, const Expr *mod) {\n  bool found = false;\n  const ForeachStatement *f = nullptr;\n  for (auto it = nodeStack.rbegin(); it != nodeStack.rend(); ++it) {\n    if (it->sst != SST_NODE)\n      continue;\n\n    const Node *n = it->n;\n    if (n->op() == TO_FOREACH) {\n      f = static_cast<const ForeachStatement *>(n);\n\n      if (_equalChecker.check(f->container(), e)) {\n        found = true;\n        break;\n      }\n    }\n  }\n\n  if (!found)\n    return;\n\n  for (auto it = nodeStack.rbegin(); it != nodeStack.rend(); ++it) {\n    if (it->sst != SST_NODE)\n      continue;\n\n    if (it->n == f)\n      break;\n\n    const Node *n = it->n;\n\n    if (n->op() == TO_BLOCK) {\n      const auto &stmts = static_cast<const Block *>(n)->statements();\n      assert(stmts.size() > 0);\n      const Statement *stmt = stmts.back();\n      if (stmt->op() == TO_RETURN || stmt->op() == TO_THROW || stmt->op() == TO_BREAK)\n        return;\n    }\n  }\n\n  report(mod, DiagnosticsId::DI_MODIFIED_CONTAINER);\n}\n\n\nstatic bool stringLooksLikeFormatTemplate(const char *s) {\n  const char *bracePtr = strchr(s, '{');\n  if (bracePtr && (sq_isalpha(bracePtr[1]) || bracePtr[1] == '_'))\n  {\n    // check for strings specific to Dagor DataBlock objects\n    bool isDagorBlk = (strstr(s, \":i=\") || strstr(s, \":r=\") || strstr(s, \":t=\") || strstr(s, \":p2=\") || strstr(s, \":p3=\") || strstr(s, \":tm=\"));\n    return !isDagorBlk && bracePtr[1] && strchr(bracePtr + 2, '}');\n  }\n\n  return false;\n}\n\nvoid CheckerVisitor::checkForgotSubst(const LiteralExpr *l) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (l->kind() != LK_STRING)\n    return;\n\n  const CallExpr *candidate = nullptr;\n\n  for (auto it = nodeStack.rbegin(); it != nodeStack.rend(); ++it) {\n    if (it->sst != SST_NODE)\n      continue;\n\n    const Node *n = it->n;\n\n    if (n->op() == TO_CALL) {\n      candidate = static_cast<const CallExpr *>(n);\n      break;\n    }\n  }\n\n  const char *s = l->s();\n  if (!stringLooksLikeFormatTemplate(s)) {\n    return;\n  }\n\n  bool ok = false;\n\n  if (candidate) {\n    const Expr *callee = deparenStatic(candidate->callee());\n    const auto &arguments = candidate->arguments();\n    if (callee->op() == TO_GETFIELD) { // -V522\n      const GetFieldExpr *f = callee->asGetField();\n      const char *funcName = f->fieldName();\n      if (deparenStatic(f->receiver()) == l) {\n        ok = strcmp(funcName, \"subst\") == 0;\n      } else if (strcmp(funcName, \"split\") == 0) {\n        ok = arguments.size() >= 1 && deparenStatic(arguments[0]) == l;;\n      }\n    }\n    else if (callee->op() == TO_ID) { // -V522\n      if (strcmp(\"loc\", callee->asId()->name()) == 0) {\n        ok = arguments.size() >= 2 && deparenStatic(arguments[1]) == l;\n      }\n    }\n  }\n\n  if (!ok)\n    report(l, DiagnosticsId::DI_FORGOT_SUBST);\n}\n\nvoid CheckerVisitor::checkContainerModification(const UnExpr *u) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (u->op() != TO_DELETE)\n    return;\n\n  const Expr *arg = u->argument();\n\n  if (!arg->isAccessExpr())\n    return;\n\n  const Expr *receiver = arg->asAccessExpr()->receiver();\n\n  reportModifyIfContainer(receiver, u);\n}\n\nvoid CheckerVisitor::checkAndOrPriority(const BinExpr *expr) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  if (expr->op() == TO_OROR) {\n    if (l->op() == TO_ANDAND || r->op() == TO_ANDAND) {\n      report(expr, DiagnosticsId::DI_AND_OR_PAREN);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkBitwiseParenBool(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  if (expr->op() == TO_OROR || expr->op() == TO_ANDAND) {\n    if (l->op() == TO_AND || l->op() == TO_OR || r->op() == TO_AND || r->op() == TO_OR) {\n      report(expr, DiagnosticsId::DI_BITWISE_BOOL_PAREN);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkNullCoalescingPriority(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  if (expr->op() == TO_NULLC) {\n    if (isSuspiciousNeighborOfNullCoalescing(l->op())) {\n      report(l, DiagnosticsId::DI_NULL_COALESCING_PRIORITY, treeopStr(l->op()));\n    }\n\n    if (isSuspiciousNeighborOfNullCoalescing(r->op())) {\n      report(r, DiagnosticsId::DI_NULL_COALESCING_PRIORITY, treeopStr(r->op()));\n    }\n  }\n}\n\nvoid CheckerVisitor::checkAssignmentToItself(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  if (expr->op() == TO_ASSIGN) {\n    auto *ll = deparen(l);\n    auto *rr = deparen(r);\n\n    if (_equalChecker.check(ll, rr)) {\n      report(expr, DiagnosticsId::DI_ASG_TO_ITSELF);\n    }\n  }\n}\n\n\nvoid CheckerVisitor::checkParamAssignInLambda(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (expr->op() != TO_ASSIGN)\n    return;\n\n  const Expr *lhs = expr->lhs();\n  if (lhs->op() != TO_ID)\n    return;\n\n  if (!currentInfo || !currentInfo->declaration)\n    return;\n\n  const FunctionExpr *func = currentInfo->declaration;\n\n  // Only warn in expression lambdas (@(x) expr), not in block-body functions\n  if (!func->isLambda())\n    return;\n\n  const char *name = lhs->asId()->name();\n  ValueRef *v = findValueInScopes(name);\n\n  if (!v || !v->info || v->info->kind != SK_PARAM)\n    return;\n\n  // Only warn if the parameter belongs to the current (innermost) function\n  if (v->info->ownedScope->owner != func)\n    return;\n\n  report(expr, DiagnosticsId::DI_PARAM_ASSIGNMENT_IN_LAMBDA, name);\n}\n\nvoid CheckerVisitor::checkSameOperands(const BinExpr *expr) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  if (isSuspiciousSameOperandsBinaryOp(expr->op())) {\n    const Expr *ll = deparen(l);\n    const Expr *rr = deparen(r);\n\n    if (_equalChecker.check(ll, rr)) {\n      if (ll->op() != TO_LITERAL || (ll->asLiteral()->kind() != LK_FLOAT && ll->asLiteral()->kind() != LK_INT)) { // -V522\n        report(expr, DiagnosticsId::DI_SAME_OPERANDS, treeopStr(expr->op()));\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkAlwaysTrueOrFalse(const Expr *n) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Node *cond = n; // maybeEval(n);\n\n  if (cond->op() == TO_LITERAL) {\n    const LiteralExpr *l = cond->asExpression()->asLiteral();\n    report(n, DiagnosticsId::DI_ALWAYS_T_OR_F, l->raw() ? \"true\" : \"false\");\n  }\n  else if (cond->op() == TO_ARRAY || cond->op() == TO_TABLE || cond->op() == TO_CLASS ||\n           cond->op() == TO_FUNCTION || cond->isDeclaration()) {\n    report(n, DiagnosticsId::DI_ALWAYS_T_OR_F, \"true\");\n  }\n}\n\nvoid CheckerVisitor::checkAlwaysTrueOrFalse(const TerExpr *expr) {\n  checkAlwaysTrueOrFalse(expr->a());\n}\n\nvoid CheckerVisitor::checkTernaryPriority(const TerExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *cond = expr->a();\n\n  if (isSuspiciousTernaryConditionOp(cond->op())) {\n    const BinExpr *binCond = static_cast<const BinExpr *>(cond);\n    const Expr *l = binCond->lhs();\n    const Expr *r = binCond->rhs();\n    bool isIgnore = cond->op() == TO_AND\n      && (isUpperCaseIdentifier(l) || isUpperCaseIdentifier(r)\n        || (r->op() == TO_LITERAL && r->asLiteral()->kind() == LK_INT));\n\n    if (!isIgnore) {\n      report(cond, DiagnosticsId::DI_TERNARY_PRIOR, treeopStr(cond->op()));\n    }\n  }\n}\n\nvoid CheckerVisitor::checkSameValues(const TerExpr *expr) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *ifTrue = expr->b();\n  const Expr *ifFalse = expr->c();\n\n  if (_equalChecker.check(ifTrue, ifFalse)) {\n    report(expr, DiagnosticsId::DI_TERNARY_SAME_VALUES);\n  }\n}\n\nvoid CheckerVisitor::checkCanBeSimplified(const TerExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *cond = expr->a();\n  const Expr *checkee = nullptr;\n\n\n  if (cond->op() == TO_NE) {\n    const BinExpr *b = static_cast<const BinExpr *>(cond);\n\n    if (b->lhs()->op() == TO_LITERAL && b->lhs()->asLiteral()->kind() == LK_NULL)\n      checkee = b->rhs();\n    else if (b->rhs()->op() == TO_LITERAL && b->rhs()->asLiteral()->kind() == LK_NULL)\n      checkee = b->lhs();\n  }\n\n  if (!checkee)\n    return;\n\n  if (expr->c()->op() != TO_LITERAL || expr->c()->asLiteral()->kind() != LK_NULL)\n    return;\n\n  checkee = maybeEval(checkee);\n  const Expr *t = maybeEval(expr->b());\n\n  if (_equalChecker.check(checkee, t)) {\n    report(expr, DiagnosticsId::DI_CAN_BE_SIMPLIFIED);\n  }\n}\n\nvoid CheckerVisitor::checkAlwaysTrueOrFalse(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  TreeOp op = bin->op();\n  if (op != TO_ANDAND && op != TO_OROR)\n    return;\n\n  const Expr *lhs = bin->lhs();\n  const Expr *rhs = bin->rhs();\n\n  TreeOp cmpOp = lhs->op();\n  if (cmpOp == rhs->op() && (cmpOp == TO_NE || cmpOp == TO_EQ)) {\n    const char *constValue = nullptr;\n\n    if (op == TO_ANDAND && cmpOp == TO_EQ)\n      constValue = \"false\";\n\n    if (op == TO_OROR && cmpOp == TO_NE)\n      constValue = \"true\";\n\n    if (!constValue)\n      return;\n\n    const BinExpr *lhsBin = static_cast<const BinExpr *>(lhs);\n    const BinExpr *rhsBin = static_cast<const BinExpr *>(rhs);\n\n    const Expr *lconst = lhsBin->rhs();\n    const Expr *rconst = rhsBin->rhs();\n\n    if (lconst->op() == TO_LITERAL || isUpperCaseIdentifier(lconst)) {\n      if (rconst->op() == TO_LITERAL || isUpperCaseIdentifier(rconst)) {\n        if (_equalChecker.check(lhsBin->lhs(), rhsBin->lhs())) {\n          if (!_equalChecker.check(lconst, rconst)) {\n            report(bin, DiagnosticsId::DI_ALWAYS_T_OR_F, constValue);\n          }\n        }\n      }\n    }\n  }\n  else if ((lhs->op() == TO_NOT || rhs->op() == TO_NOT) && (lhs->op() != rhs->op())) {\n    const char *v = op == TO_OROR ? \"true\" : \"false\";\n    if (lhs->op() == TO_NOT) {\n      const UnExpr *u = static_cast<const UnExpr *>(lhs);\n      if (_equalChecker.check(u->argument(), rhs)) {\n        report(bin, DiagnosticsId::DI_ALWAYS_T_OR_F, v);\n      }\n    }\n    if (rhs->op() == TO_NOT) {\n      const UnExpr *u = static_cast<const UnExpr *>(rhs);\n      if (_equalChecker.check(lhs, u->argument())) {\n        report(bin, DiagnosticsId::DI_ALWAYS_T_OR_F, v);\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkDeclarationInArith(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (isArithOperator(bin->op())) {\n    const Expr *lhs = maybeEval(bin->lhs());\n    const Expr *rhs = maybeEval(bin->rhs());\n\n    if (lhs->op() == TO_TABLE || lhs->op() == TO_CLASS || lhs->op() == TO_FUNCTION ||\n        lhs->op() == TO_ARRAY) {\n      report(bin->lhs(), DiagnosticsId::DI_DECL_IN_EXPR);\n    }\n\n    if (bin->op() != TO_OROR && bin->op() != TO_ANDAND) {\n      if (rhs->op() == TO_TABLE || rhs->op() == TO_CLASS || rhs->op() == TO_FUNCTION ||\n          rhs->op() == TO_ARRAY) {\n        report(bin->rhs(), DiagnosticsId::DI_DECL_IN_EXPR);\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkIntDivByZero(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (isDivOperator(bin->op())) {\n    const Expr *divided = maybeEval(bin->lhs());\n    const Expr *divisor = maybeEval(bin->rhs());\n\n    if (divisor->op() == TO_LITERAL) {\n      const LiteralExpr *rhs = divisor->asLiteral();\n      if (rhs->raw() == 0) {\n        report(bin, DiagnosticsId::DI_DIV_BY_ZERO);\n        return;\n      }\n      if (divided->op() == TO_LITERAL) {\n        const LiteralExpr *lhs = divided->asLiteral();\n        if (lhs->kind() == LK_INT && rhs->kind() == LK_INT) {\n          if (rhs->i() == -1 && lhs->i() == MIN_SQ_INTEGER) {\n            report(bin, DiagnosticsId::DI_INTEGER_OVERFLOW);\n          }\n          else if (lhs->i() % rhs->i() != 0) {\n            report(bin, DiagnosticsId::DI_ROUND_TO_INT);\n          }\n        }\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkPotentiallyNullableOperands(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  TreeOp op = bin->op();\n\n  bool isRelOp = isBoolRelationOperator(op);\n  bool isArithOp = isPureArithOperator(op);\n  bool isAssign = op == TO_ASSIGN || op == TO_NEWSLOT;\n\n  if (!isRelOp && !isArithOp && !isAssign)\n    return;\n\n  const Expr *lhs = bin->lhs();\n  const Expr *rhs = bin->rhs();\n\n  const char *opType = isRelOp ? \"Comparison operation\" : \"Arithmetic operation\";\n\n\n  bool lhsNullable = isPotentiallyNullable(lhs);\n  bool rhsNullable = isPotentiallyNullable(rhs);\n\n  if (!lhsNullable && !rhsNullable)\n    return;\n\n  // string concat with nullable is OK\n  if (couldBeString(lhs) || couldBeString(rhs))\n    return;\n\n  if (lhsNullable) {\n    if (isAssign) {\n      if (lhs->op() != TO_ID) { // -V522\n        report(bin->lhs(), DiagnosticsId::DI_NULLABLE_ASSIGNMENT);\n      }\n    }\n    else {\n      report(bin->lhs(), DiagnosticsId::DI_NULLABLE_OPERANDS, opType);\n    }\n  }\n\n  if (rhsNullable && !isAssign) {\n    report(bin->rhs(), DiagnosticsId::DI_NULLABLE_OPERANDS, opType);\n  }\n}\n\nvoid CheckerVisitor::checkBitwiseToBool(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (!isBitwiseOperator(bin->op()))\n    return;\n\n  const Expr *lhs = maybeEval(bin->lhs());\n  const Expr *rhs = maybeEval(bin->rhs());\n\n  if (looksLikeBooleanExpr(lhs) || looksLikeBooleanExpr(rhs)) {\n    report(bin, DiagnosticsId::DI_BITWISE_OP_TO_BOOL);\n  }\n\n}\n\nvoid CheckerVisitor::checkRelativeCompareWithBool(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (!isBoolRelationOperator(expr->op()))\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  const Expr *dl = deparenStatic(l);\n  const Expr *dr = deparenStatic(r);\n\n  const Expr *el = maybeEval(dl);\n  const Expr *er = maybeEval(dr);\n\n  bool l_b = looksLikeBooleanExpr(l);\n  bool dl_b = looksLikeBooleanExpr(dl);\n  bool el_b = looksLikeBooleanExpr(el);\n\n  bool r_b = looksLikeBooleanExpr(r);\n  bool dr_b = looksLikeBooleanExpr(dr);\n  bool er_b = looksLikeBooleanExpr(er);\n\n  bool left_cb = l_b || dl_b || el_b;\n  bool right_cb = r_b || dr_b || er_b;\n\n  if (left_cb != right_cb) { // -V522\n    report(expr, DiagnosticsId::DI_RELATIVE_CMP_BOOL);\n  }\n}\n\nvoid CheckerVisitor::checkCompareWithBool(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *l = expr->lhs();\n  const Expr *r = expr->rhs();\n\n  TreeOp thisOp = expr->op();\n  TreeOp lhsOp = l->op();\n  TreeOp rhsOp = r->op();\n\n  // if (a == b != c)\n  if (thisOp == TO_EQ || thisOp == TO_NE) {\n    if (lhsOp == TO_EQ || lhsOp == TO_NE || rhsOp == TO_EQ || rhsOp == TO_NE) {\n      report(expr, DiagnosticsId::DI_EQ_PAREN_MISSED);\n      return;\n    }\n  }\n\n  if (isBoolCompareOperator(thisOp) && lhsOp != TO_PAREN && rhsOp != TO_PAREN) {\n    const Expr *lhs = maybeEval(l);\n    const Expr *rhs = maybeEval(r);\n\n    if (isBoolCompareOperator(lhs->op()) || isBoolCompareOperator(rhs->op())) {\n      bool warn = true;\n\n      if (expr->op() == TO_EQ || expr->op() == TO_NE) {\n\n        //function_should_return_bool_prefix\n\n        if (nameLooksLikeResultMustBeBoolean(findFieldName(l)) ||\n          nameLooksLikeResultMustBeBoolean(findFieldName(r)) ||\n          nameLooksLikeResultMustBeBoolean(findFieldName(rhs)) ||\n          nameLooksLikeResultMustBeBoolean(findFieldName(lhs))) {\n          warn = false;\n        }\n\n        if (l->op() == TO_ID && r->op() == TO_ID) {\n          warn = false;\n        }\n      }\n\n      if (warn) {\n        report(expr, DiagnosticsId::DI_COMPARE_WITH_BOOL);\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkCopyOfExpression(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  TreeOp op = bin->op();\n  if (op != TO_OROR && op != TO_ANDAND && op != TO_OR)\n    return;\n\n  const Expr *lhs = bin->lhs();\n  const Expr *cmp = bin->rhs();\n\n  while (cmp->op() == op) {\n    const BinExpr *binCmp = static_cast<const BinExpr *>(cmp);\n\n    if (_equalChecker.check(lhs, binCmp->lhs()) || _equalChecker.check(lhs, binCmp->rhs())) {\n      report(binCmp, DiagnosticsId::DI_COPY_OF_EXPR);\n    }\n    cmp = binCmp->rhs();\n  }\n}\n\nvoid CheckerVisitor::checkConstInBoolExpr(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_OROR && bin->op() != TO_ANDAND)\n    return;\n\n  const Expr *lhs = bin->lhs();\n  const Expr *rhs = bin->rhs();\n\n  bool leftIsConst = lhs->op() == TO_LITERAL || lhs->op() == TO_TABLE || lhs->op() == TO_CLASS ||\n                     lhs->op() == TO_FUNCTION || lhs->op() == TO_ARRAY || isUpperCaseIdentifier(lhs); //-V522\n  bool rightIsConst = rhs->op() == TO_LITERAL || rhs->op() == TO_TABLE || rhs->op() == TO_CLASS ||\n                      rhs->op() == TO_FUNCTION || rhs->op() == TO_ARRAY || isUpperCaseIdentifier(rhs); // -V522\n\n/*  if (rightIsConst && bin->op() == TO_OROR) {\n    if (rhs->op() != TO_LITERAL || rhs->asLiteral()->kind() != LK_BOOL || rhs->asLiteral()->b() != true) {\n      rightIsConst = false;\n    }\n  } */\n\n  if (leftIsConst || rightIsConst) {\n    report(bin, DiagnosticsId::DI_CONST_IN_BOOL_EXPR);\n  }\n}\n\nvoid CheckerVisitor::checkShiftPriority(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (isShiftOperator(bin->op())) {\n    if (isHigherShiftPriority(bin->lhs()->op()) || isHigherShiftPriority(bin->rhs()->op())) {\n      report(bin, DiagnosticsId::DI_SHIFT_PRIORITY);\n    }\n  }\n}\n\n\nvoid CheckerVisitor::checkCompareWithContainer(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (!isCompareOperator(bin->op()))\n    return;\n\n  const Expr *l = bin->lhs();\n  const Expr *r = bin->rhs();\n\n  if (l->op() == TO_ARRAY || r->op() == TO_ARRAY) {\n    report(bin, DiagnosticsId::DI_CMP_WITH_CONTAINER, \"array\");\n  }\n\n  auto isDeclLikeExpr = [](TreeOp op) {\n    return op == TO_TABLE || op == TO_CLASS || op == TO_FUNCTION;\n  };\n  if (isDeclLikeExpr(l->op()) || isDeclLikeExpr(r->op())) {\n    report(bin, DiagnosticsId::DI_CMP_WITH_CONTAINER, \"declaration\");\n  }\n}\n\nvoid CheckerVisitor::checkExtendToAppend(const CallExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *callee = expr->callee();\n  const auto &args = expr->arguments();\n\n  if (callee->op() == TO_GETFIELD) {\n    if (args.size() > 0) {\n      Expr *arg0 = args[0];\n      if (arg0->op() == TO_ARRAY) {\n        if (strcmp(callee->asGetField()->fieldName(), \"extend\") == 0) {\n          report(expr, DiagnosticsId::DI_EXTEND_TO_APPEND);\n        }\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkMergeEmptyTable(const CallExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *callee = expr->callee();\n  const auto &args = expr->arguments();\n\n  if (callee->op() == TO_GETFIELD) {\n    if (args.size() == 1) {\n      Expr *arg0 = args[0];\n      if (arg0->op() == TO_TABLE && arg0->asTableExpr()->members().size() == 0) {\n        if (strcmp(callee->asGetField()->fieldName(), \"__merge\") == 0) {\n          report(expr, DiagnosticsId::DI_MERGE_EMPTY_TABLE);\n        }\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkEmptyArrayResize(const CallExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *callee = expr->callee();\n\n  if (callee->op() == TO_GETFIELD) {\n    const GetFieldExpr *gf = callee->asGetField();\n    if (strcmp(gf->fieldName(), \"resize\") == 0) {\n      const Expr *receiver = gf->receiver();\n      if (receiver->op() == TO_ARRAY && static_cast<const ArrayExpr *>(receiver)->initializers().size() == 0) {\n        report(expr, DiagnosticsId::DI_EMPTY_ARRAY_RESIZE);\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkBoolToStrangePosition(const BinExpr *bin) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_IN && bin->op() != TO_INSTANCEOF)\n    return;\n\n  const Expr *lhs = maybeEval(bin->lhs());\n  const Expr *rhs = maybeEval(bin->rhs());\n\n  if (looksLikeBooleanExpr(lhs) && bin->op() == TO_IN) {\n    report(bin, DiagnosticsId::DI_BOOL_PASSED_TO_STRANGE, \"in\");\n  }\n\n  if (looksLikeBooleanExpr(rhs)) {\n    report(bin, DiagnosticsId::DI_BOOL_PASSED_TO_STRANGE, bin->op() == TO_IN ? \"in\" : \"instanceof\");\n  }\n}\n\nstatic const char *tryExtractKeyName(const Expr *e) {\n\n  if (e->op() == TO_GETFIELD)\n    return e->asGetField()->fieldName();\n\n  if (e->op() == TO_GETSLOT) {\n    e = e->asGetSlot()->key();\n  }\n\n  if (e->op() == TO_LITERAL) {\n    if (e->asLiteral()->kind() == LK_STRING)\n      return e->asLiteral()->s();\n  }\n\n  return nullptr;\n}\n\n\nvoid CheckerVisitor::checkKeyNameMismatch(const Expr *key, const Expr *e) {\n\n  /*\n    function bar() {}\n    let tt = {\n      \"1foo\" : function bar1() { .. }, // OK, not id\n      \"foo2\" : function bar2() { .. }, // WARN\n      \"foo3\" : function foo3() { .. }, // OK\n\n      foo4 = function bar5() { ... }, // WARN\n      foo6 = function foo6() { ... }, // OK\n\n      [\"foo7\"] = function bar7() { ... }, // WARN\n      [\"8foo\"] = function bar8() { ... } // OK, not id\n    }\n    tt.foo <- bar // OK\n    tt.qux <- function fex() { .. } // WARN\n    tt[\"fk\"] <- function uyte() { .. } // WARN\n    tt[\"f:g:h\"] <- function fgh() { .. } // OK\n  */\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fieldName = tryExtractKeyName(key);\n\n  if (!fieldName)\n    return;\n\n  if (e->op() != TO_FUNCTION)\n    return;\n\n  const FunctionExpr *f = e->asFunctionExpr();\n  const char *declName = nullptr;\n\n  if (!f->isLambda() && f->name()[0] != '(') {\n    declName = f->name();\n  }\n\n  if (!declName)\n    return;\n\n  if (!isValidId(fieldName))\n    return;\n\n  if (strcmp(fieldName, declName) != 0) {\n    report(e, DiagnosticsId::DI_KEY_NAME_MISMATCH, fieldName, declName);\n  }\n}\n\nvoid CheckerVisitor::checkNewSlotNameMatch(const BinExpr *bin) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_NEWSLOT)\n    return;\n\n  const Expr *lhs = bin->lhs();\n  const Expr *rhs = bin->rhs();\n\n  checkKeyNameMismatch(lhs, rhs);\n}\n\nvoid CheckerVisitor::checkPlusString(const BinExpr *bin) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_ADD && bin->op() != TO_PLUSEQ)\n    return;\n\n  const Expr *l = maybeEval(bin->lhs());\n  const Expr *r = maybeEval(bin->rhs());\n\n  if (couldBeString(l) || couldBeString(r)) {\n    report(bin, DiagnosticsId::DI_PLUS_STRING);\n  }\n}\n\nvoid CheckerVisitor::checkNewGlobalSlot(const BinExpr *bin) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_NEWSLOT)\n    return;\n\n  const Expr *lhs = bin->lhs();\n\n  if (lhs->op() != TO_GETFIELD)\n    return;\n\n  const GetFieldExpr *gf = lhs->asGetField();\n\n  if (gf->receiver()->op() != TO_ROOT_TABLE_ACCESS)\n    return;\n\n  storeGlobalDeclaration(gf->fieldName(), bin);\n}\n\nvoid CheckerVisitor::checkUselessNullC(const BinExpr *bin) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_NULLC)\n    return;\n\n  const Expr *rhs = maybeEval(bin->rhs());\n\n  if (rhs->op() == TO_LITERAL && rhs->asLiteral()->kind() == LK_NULL)\n    report(bin, DiagnosticsId::DI_USELESS_NULLC);\n}\n\nvoid CheckerVisitor::checkCannotBeNull(const BinExpr *bin) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *loc = nullptr;\n  const Expr *reportee = nullptr;\n  const Expr *checkee = nullptr;\n  if (bin->op() == TO_NULLC) {\n    reportee = bin->lhs();\n    checkee = maybeEval(reportee);\n    loc = \"null coalescing\";\n  }\n  else if (bin->op() == TO_NE || bin->op() == TO_EQ) {\n    const Expr *le = maybeEval(bin->lhs());\n    const Expr *re = maybeEval(bin->rhs());\n\n    loc = \"equal check\";\n\n    if (le->op() == TO_LITERAL && le->asLiteral()->kind() == LK_NULL) {\n      checkee = re;\n      reportee = bin->rhs();\n    }\n    else if (re->op() == TO_LITERAL && re->asLiteral()->kind() == LK_NULL) {\n      checkee = le;\n      reportee = bin->lhs();\n    }\n  }\n\n  if (checkee)\n    reportIfCannotBeNull(checkee, reportee, loc);\n}\n\nvoid CheckerVisitor::checkCanBeSimplified(const BinExpr *bin) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (bin->op() != TO_ANDAND && bin->op() != TO_OROR)\n    return;\n\n  const Expr *lhs = maybeEval(bin->lhs());\n  const Expr *rhs = maybeEval(bin->rhs());\n\n  if (isBoolRelationOperator(lhs->op()) && isBoolRelationOperator(rhs->op())) {\n    const BinExpr *binL = static_cast<const BinExpr *>(lhs);\n    const BinExpr *binR = static_cast<const BinExpr *>(rhs);\n\n    if (_equalChecker.check(binL->lhs(), binR->lhs())) {\n      int leftCmp = (binL->op() == TO_GE) || (binL->op() == TO_GT) ? 1 : -1;\n      int rightCmp = (binR->op() == TO_GE) || (binR->op() == TO_GT) ? 1 : -1;\n\n      if (leftCmp == rightCmp) {\n        const Expr *l = maybeEval(binL->rhs());\n        const Expr *r = maybeEval(binR->rhs());\n\n        bool lConst = l->op() == TO_LITERAL || isUpperCaseIdentifier(l);\n        bool rConst = r->op() == TO_LITERAL || isUpperCaseIdentifier(r);\n\n        if (lConst && rConst) {\n          report(bin, DiagnosticsId::DI_CAN_BE_SIMPLIFIED);\n        }\n      }\n    }\n  }\n}\n\n\nvoid CheckerVisitor::checkRangeCheck(const BinExpr *expr) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (expr->op() != TO_OROR && expr->op() != TO_ANDAND)\n    return;\n\n  const Expr *lhs = maybeEval(expr->lhs());\n  const Expr *rhs = maybeEval(expr->rhs());\n\n  if (isRelationOperator(lhs->op()) && isRelationOperator(rhs->op())) {\n    const Expr *cmpZero = nullptr, *cmpCount = nullptr;\n    int cmpDir = 1;\n\n    const BinExpr *l = static_cast<const BinExpr *>(lhs);\n    const BinExpr *r = static_cast<const BinExpr *>(rhs);\n\n    if (_equalChecker.check(l->lhs(), r->lhs())) {\n      cmpZero = l->rhs();\n      cmpCount = r->rhs();\n    }\n    else if (_equalChecker.check(l->rhs(), r->lhs())) {\n      cmpDir = -1;\n      cmpZero = l->lhs();\n      cmpCount = r->rhs();\n    }\n    else if (_equalChecker.check(l->lhs(), r->rhs())) {\n      cmpZero = l->rhs();\n      cmpCount = r->lhs();\n    }\n\n    if (!cmpZero)\n      return;\n\n    assert(cmpCount);\n\n    if (cmpZero->op() != TO_LITERAL || cmpZero->asLiteral()->kind() != LK_INT || cmpZero->asLiteral()->i() != 0)\n      return;\n\n    if (looksLikeElementCount(maybeEval(cmpCount))) {\n      int leftCmp = (l->op() == TO_GE) || (l->op() == TO_GT) ? 1 : -1;\n      int rightCmp = (r->op() == TO_GE) || (r->op() == TO_GT) ? 1 : -1;\n      bool leftEq = (l->op() == TO_GE) || (l->op() == TO_LE);\n      bool rightEq = (r->op() == TO_GE) || (r->op() == TO_LE);\n\n      if (leftCmp * cmpDir != rightCmp && leftEq == rightEq)\n        report(expr, DiagnosticsId::DI_RANGE_CHECK);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkAlreadyRequired(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (call->arguments().size() != 1)\n    return;\n\n  const Expr *arg = maybeEval(call->arguments()[0]);\n\n  if (arg->op() != TO_LITERAL)\n    return;\n\n  const LiteralExpr *l = arg->asLiteral();\n  if (l->kind() != LK_STRING)\n    return;\n\n\n  const Expr *callee = call->callee();\n  bool isCtor = false;\n  const FunctionInfo *info = findFunctionInfo(callee, isCtor);\n\n  if (isCtor)\n    return;\n\n  const char *name = nullptr;\n\n  if (info) {\n    name = info->declaration->name();\n  }\n  else if (callee->op() == TO_ID) {\n    name = callee->asId()->name();\n  }\n  else if (callee->op() == TO_GETFIELD) {\n    const GetFieldExpr *g = callee->asGetField();\n    if (g->receiver()->op() == TO_ROOT_TABLE_ACCESS) {\n      name = g->fieldName();\n    }\n  }\n\n  if (!name)\n    return;\n\n  if (strcmp(name, \"require\") != 0 && strcmp(name, \"require_optional\") != 0)\n    return;\n\n  const char *moduleName = l->s();\n\n  if (!_ctx.isRequireDisabled(call->lineStart(), call->columnStart()))\n    if (auto fv = findValueInScopes(\"require_optional\"); fv && fv->expression && fv->expression->op() == TO_EXTERNAL_VALUE) {\n      auto vm = _ctx.getVm();\n      SQInteger top = sq_gettop(vm);\n\n      sq_pushobject(vm, fv->expression->asExternal()->value());\n      sq_pushnull(vm);\n      sq_pushstring(vm, moduleName, -1);\n\n      SQRESULT result = sq_call(vm, 2, true, false);\n      if (SQ_SUCCEEDED(result)) {\n        SQObject ret;\n        if (SQ_SUCCEEDED(sq_getstackobj(vm, -1, &ret)) && !sq_isnull(ret)) {\n          astValues[call] = addExternalValue(ret, call);\n        }\n        else if (do_report_missing_modules) {\n          report(call, DI_MISSING_MODULE, moduleName);\n          SQObjectPtr empty;\n          astValues[call] = addExternalValue(empty, call);\n        }\n      }\n      else if (do_report_missing_modules) {\n        report(call, DI_MISSING_MODULE, moduleName);\n        SQObjectPtr empty;\n        astValues[call] = addExternalValue(empty, call);\n      }\n\n      sq_settop(vm, top);\n    }\n\n  if (nodeStack.size() > 2)\n    return; // do not consider require which is not on TL\n\n  if (requiredModules.find(moduleName) != requiredModules.end()) {\n    report(call, DiagnosticsId::DI_ALREADY_REQUIRED, moduleName);\n  }\n  else {\n    requiredModules.insert(moduleName);\n  }\n}\n\nvoid CheckerVisitor::checkCallNullable(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *c = call->callee();\n\n  if (!call->isNullable() && isPotentiallyNullable(c)) {\n    report(c, DiagnosticsId::DI_ACCESS_POT_NULLABLE, c->op() == TO_ID ? c->asId()->name() : \"expression\", \"function\");\n  }\n}\n\nvoid CheckerVisitor::checkPersistCall(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *calleeName = extractFunctionName(call);\n\n  if (!calleeName)\n    return;\n\n  const auto &arguments = call->arguments();\n  const Expr *keyExpr = nullptr;\n\n  if (strcmp(\"persist\", calleeName) == 0) {\n    if (arguments.size() < 2)\n      return;\n    keyExpr = arguments[0];\n  }\n  else if (strcmp(\"mkWatched\", calleeName) == 0) {\n    if (arguments.size() < 2)\n      return;\n\n    const Expr *persistsFunc = maybeEval(arguments[0]);\n    if (persistsFunc->op() != TO_ID || strcmp(\"persist\", persistsFunc->asId()->name()) != 0)\n      return;\n\n    keyExpr = arguments[1];\n  }\n\n  if (!keyExpr)\n    return;\n\n  const Expr *evalKeyExpr = maybeEval(keyExpr);\n\n  if (evalKeyExpr->op() != TO_LITERAL)\n    return;\n\n  const LiteralExpr *l = evalKeyExpr->asLiteral();\n\n  if (l->kind() != LK_STRING)\n    return;\n\n  const char *key = l->s();\n\n  auto r = persistedKeys.emplace(key);\n\n  if (!r.second) {\n    report(keyExpr, DiagnosticsId::DI_DUPLICATE_PERSIST_ID, key);\n  }\n}\n\nvoid CheckerVisitor::checkForbiddenCall(const CallExpr *call) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fn = extractFunctionName(call);\n\n  if (!fn)\n    return;\n\n  if (isForbiddenFunctionName(fn)) {\n    report(call, DiagnosticsId::DI_FORBIDDEN_FUNC, fn);\n  }\n}\n\nvoid CheckerVisitor::checkCallFromRoot(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fn = extractFunctionName(call);\n\n  if (!fn)\n    return;\n\n  if (!nameLooksLikeMustBeCalledFromRoot(fn)) {\n    return;\n  }\n\n  bool do_report = false;\n\n  for (auto it = nodeStack.rbegin(); it != nodeStack.rend(); ++it) {\n    if (it->sst == SST_TABLE_MEMBER)\n      continue;\n\n    TreeOp op = it->n->op();\n\n    if (op == TO_FUNCTION || op == TO_CLASS) {\n      do_report = true;\n      break;\n    }\n  }\n\n  if (do_report) {\n    report(call, DiagnosticsId::DI_CALL_FROM_ROOT, fn);\n  }\n}\n\nvoid CheckerVisitor::checkForbiddenParentDir(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fn = extractFunctionName(call);\n\n  if (!fn)\n    return;\n\n  if (!nameLooksLikeForbiddenParentDir(fn)) {\n    return;\n  }\n\n  const auto &arguments = call->arguments();\n\n  if (arguments.size() < 1)\n    return;\n\n  const Expr *arg = maybeEval(arguments[0]);\n\n  if (arg->op() != TO_LITERAL || arg->asLiteral()->kind() != LK_STRING)\n    return;\n\n  const char *path = arg->asLiteral()->s();\n\n  const char * p = strstr(path, \"..\");\n  if (p && (p[2] == '/' || p[2] == '\\\\')) {\n    report(call, DiagnosticsId::DI_FORBIDDEN_PARENT_DIR);\n  }\n}\n\nvoid CheckerVisitor::checkFormatArguments(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &arguments = call->arguments();\n\n  for (int32_t i = 0; i < arguments.size(); ++i) {\n    const Expr *arg = deparenStatic(arguments[i]);\n    if (arg->op() == TO_LITERAL && arg->asLiteral()->kind() == LK_STRING) { // -V522\n      int32_t formatsCount = 0;\n      for (const char *s = arg->asLiteral()->s(); *s; ++s) {\n        if (*s == '%') {\n          if (*(s + 1) == '%') {\n            s++;\n          }\n          else {\n            formatsCount++;\n          }\n        }\n      }\n\n      if (formatsCount && formatsCount != (arguments.size() - i - 1)) {\n        const char *name = extractFunctionName(call);\n        if (!name)\n          return;\n\n        if (nameLooksLikeFormatFunction(name)) {\n          report(arguments[i], DiagnosticsId::DI_FORMAT_ARGUMENTS_COUNT);\n        }\n      }\n\n      return;\n    }\n  }\n}\n\nint32_t CheckerVisitor::normalizeParamNameLength(const char *name) {\n  int32_t r = 0;\n\n  while (*name) {\n    if (*name != '_')\n      ++r;\n    ++name;\n  }\n\n  return r;\n}\n\nconst char *CheckerVisitor::normalizeParamName(const char *name, char *buffer) {\n\n  if (!buffer) {\n    int32_t nl = normalizeParamNameLength(name);\n    buffer = (char *)arena->allocate(nl + 1);\n  }\n\n  int32_t i = 0, j = 0;\n  while (name[i]) {\n    char c = name[i++];\n    if (c != '_') {\n      buffer[j++] = std::tolower(c);\n    }\n  }\n\n  buffer[j] = '\\0';\n\n  return buffer;\n}\n\nvoid CheckerVisitor::checkArguments(const CallExpr *callExpr) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  bool dummy;\n  const FunctionInfo *info = findFunctionInfo(callExpr->callee(), dummy);\n  const SQFunctionProto *proto = nullptr;\n  const SQNativeClosure *nclosure = nullptr;\n\n  const char *funcName;\n  int numParams;\n  int dpParameters;\n  bool isVararg;\n\n  if (info) {\n    const FunctionExpr *decl = info->declaration;\n    funcName = decl->name();\n    numParams = info->parameters.size();\n    isVararg = decl->isVararg();\n\n    dpParameters = 0;\n    for (auto &p : decl->parameters()) {\n      if (p->hasDefaultValue())\n        ++dpParameters;\n    }\n  }\n  else {\n    const ExternalValueExpr *ev = findExternalValue(callExpr->callee());\n    if (!ev)\n      return;\n\n    const SQObject& v = ev->value();\n    if (sq_isclosure(v)) {\n      proto = _closure(v)->_function;\n      funcName = sq_isstring(proto->_name) ? _stringval(proto->_name) : \"unknown\";\n      numParams = proto->_nparameters - 1; // not counting 'this'\n      isVararg = proto->_varparams;\n      dpParameters = proto->_ndefaultparams;\n    }\n    else if (sq_isfunction(v)) {\n      assert(!\"Encountered function proto - internal structure, should not happen\");\n      return;\n    }\n    else if (sq_isnativeclosure(v)) {\n      nclosure = _nativeclosure(v);\n      if (nclosure->_nparamscheck == 0)\n        return;\n      funcName = sq_isstring(nclosure->_name) ? _stringval(nclosure->_name) : \"unknown native\";\n      numParams = std::abs(nclosure->_nparamscheck)-1; // not counting 'this'\n      isVararg = nclosure->_nparamscheck < 0;\n      dpParameters = 0;\n    }\n    else\n      return;\n  }\n\n  if (numParams < 0) numParams = 0;\n\n  const int effectiveParamSizeUP = std::max<int>(isVararg ? numParams - 1 : numParams, 0);\n  const int effectiveParamSizeLB = effectiveParamSizeUP - dpParameters;\n  const int maxParamSize = isVararg ? INT_MAX : effectiveParamSizeUP;\n\n  const auto &args = callExpr->arguments();\n\n  if (!(effectiveParamSizeLB <= args.size() && args.size() <= maxParamSize)) {\n    report(callExpr, DiagnosticsId::DI_PARAM_COUNT_MISMATCH, funcName,\n      effectiveParamSizeLB, maxParamSize, args.size());\n    report(maybeEval(callExpr->callee(), true), DI_SEE_OTHER, \"the function\");\n  }\n\n  for (int i = 0; i < numParams; ++i) {\n    const char *paramName;\n    if (info) paramName = info->parameters[i];\n    else if (proto) {\n      if (!sq_isstring(proto->_parameters[i + 1])) continue;\n      paramName = _stringval(proto->_parameters[i + 1]);\n    }\n    else {\n      if (!nclosure)\n        assert(0);\n      continue;\n    }\n\n    for (int j = 0; j < args.size(); ++j) {\n      const Expr *arg = args[j];\n      const char *possibleArgName = nullptr;\n\n      if (arg->op() == TO_ID)\n        possibleArgName = arg->asId()->name();\n      else if (arg->op() == TO_GETFIELD)\n        possibleArgName = arg->asGetField()->fieldName();\n\n      if (!possibleArgName)\n        continue;\n\n      int32_t argNL = normalizeParamNameLength(possibleArgName);\n      char *buffer = (char *)sq_malloc(_ctx.allocContext(), argNL + 1);\n      normalizeParamName(possibleArgName, buffer);\n\n      if (i != j) {\n        if (strcmp(\"vargv\", paramName) != 0 || (j != numParams)) {\n          if (strcmp(paramName, buffer) == 0) {  // -V575\n            report(arg, DiagnosticsId::DI_PARAM_POSITION_MISMATCH, paramName);\n          }\n        }\n      }\n\n      sq_free(_ctx.allocContext(), buffer, argNL + 1);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkContainerModification(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *name = extractFunctionName(call);\n\n  if (!name)\n    return;\n\n  if (!nameLooksLikeModifiesObject(name))\n    return;\n\n  const Expr *callee = call->callee();\n\n  if (!callee->isAccessExpr())\n    return;\n\n  reportModifyIfContainer(callee->asAccessExpr()->receiver(), call);\n}\n\n// Detect ambiguous expressions that may modify either a temporary or a persistent object\nstatic bool hasMixedLifetime(const Expr *e) {\n  e = deparenStatic(e);\n\n  const Expr *expr0 = nullptr, *expr1 = nullptr;\n\n  if (e->op() == TO_NULLC) { //-V522\n    const BinExpr *nullc = static_cast<const BinExpr *>(e);\n    expr0 = deparenStatic(nullc->lhs()); //-V522\n    expr1 = deparenStatic(nullc->rhs()); //-V522\n  }\n  else if (e->op() == TO_TERNARY) { //-V522\n    const TerExpr *ter = static_cast<const TerExpr *>(e);\n    expr0 = deparenStatic(ter->b()); //-V522\n    expr1 = deparenStatic(ter->c()); //-V522\n  }\n  else\n    return false;\n\n  auto isDeclLikeExpr = [](TreeOp op) {\n    return op == TO_ARRAY || op == TO_TABLE || op == TO_CLASS || op == TO_FUNCTION;\n  };\n  bool isLiteral0 = isDeclLikeExpr(expr0->op()); //-V522\n  bool isLiteral1 = isDeclLikeExpr(expr1->op()); //-V522\n\n  return (isLiteral0 != isLiteral1);\n}\n\nvoid CheckerVisitor::checkUnwantedModification(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *name = extractFunctionName(call);\n\n  if (!name)\n    return;\n\n  if (!nameLooksLikeModifiesObject(name))\n    return;\n\n  const Expr *callee = call->callee();\n\n  if (!callee->isAccessExpr())\n    return;\n\n  if (nodeStack.back().sst == SST_NODE) {\n    const Node *p = nodeStack.back().n;\n    if (p->op() == TO_NEWSLOT)\n      return;\n  }\n\n  if (hasMixedLifetime(callee->asAccessExpr()->receiver()))\n    report(call, DiagnosticsId::DI_UNWANTED_MODIFICATION, name);\n}\n\nvoid CheckerVisitor::checkCannotBeNull(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (!call->isNullable())\n    return;\n\n  const Expr *callee = call->callee();\n\n  reportIfCannotBeNull(maybeEval(callee), callee, \"call\");\n}\n\nvoid CheckerVisitor::checkBooleanLambda(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fn = extractFunctionName(call);\n\n  if (!fn)\n    return;\n\n  if (!nameLooksLikeFunctionTakeBooleanLambda(fn))\n    return;\n\n  if (call->arguments().size() < 1)\n    return;\n\n  const Expr *arg = deparenStatic(call->arguments()[0]);\n\n  if (arg->op() != TO_FUNCTION) // -V522\n    return;\n\n  const FunctionExpr *f = arg->asFunctionExpr();\n\n  FunctionReturnTypeEvaluator rte(this);\n\n  bool r = false;\n  unsigned typesMask = rte.compute(f->body(), r);\n\n  typesMask &= ~(RT_UNRECOGNIZED | RT_FUNCTION_CALL | RT_BOOL | RT_NUMBER | RT_NULL);\n\n  if (typesMask != 0) {\n    report(arg, DiagnosticsId::DI_BOOL_LAMBDA_REQUIRED, fn);\n  }\n}\n\nvoid CheckerVisitor::checkCallbackReturnValue(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fn = extractFunctionName(call);\n\n  if (!fn)\n    return;\n\n  if (!nameLooksLikeRequiresResultFromCallback(fn))\n    return;\n\n  if (call->arguments().size() < 1)\n    return;\n\n  const Expr *arg = maybeEval(call->arguments()[0]);\n\n  if (arg->op() != TO_FUNCTION) // -V522\n    return;\n\n  const FunctionExpr *f = arg->asFunctionExpr();\n\n  FunctionReturnTypeEvaluator rte(this);\n\n  bool allPathsReturn = false;\n  unsigned typesMask = rte.compute(f->body(), allPathsReturn);\n\n  if (typesMask & RT_NOTHING) {\n    report(arg, DiagnosticsId::DI_CALLBACK_SHOULD_RETURN_VALUE, fn);\n  }\n}\n\nvoid CheckerVisitor::checkCallbackShouldNotReturn(const CallExpr *call) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *fn = extractFunctionName(call);\n\n  if (!fn)\n    return;\n\n  if (!nameLooksLikeIgnoresCallbackResult(fn))\n    return;\n\n  if (call->arguments().size() < 1)\n    return;\n\n  const Expr *arg = maybeEval(call->arguments()[0]);\n\n  if (arg->op() != TO_FUNCTION) // -V522\n    return;\n\n  const FunctionExpr *f = arg->asFunctionExpr();\n\n  // Lambda with a single call expression like @(x) arr.append(x) is likely\n  // a side-effect callback where the return value is incidental.\n  if (f->isLambda()) {\n    const Block *body = f->body()->asBlock();\n    const auto &stmts = body->statements();\n    if (stmts.size() == 1 && stmts[0]->op() == TO_RETURN) {\n      const ReturnStatement *ret = static_cast<const ReturnStatement *>(stmts[0]);\n      if (ret->argument() && ret->argument()->op() == TO_CALL)\n        return;\n    }\n  }\n\n  FunctionReturnTypeEvaluator rte(this);\n\n  bool allPathsReturn = false;\n  unsigned typesMask = rte.compute(f->body(), allPathsReturn);\n\n  unsigned valueMask = typesMask & ~(RT_NOTHING | RT_THROW | RT_FUNCTION_CALL | RT_UNRECOGNIZED);\n  if (valueMask != 0) {\n    report(arg, DiagnosticsId::DI_CALLBACK_SHOULD_NOT_RETURN, fn);\n  }\n}\n\nvoid CheckerVisitor::checkAssertCall(const CallExpr *call) {\n\n  // assert(x != null) or assert(x != null, \"X should not be null\")\n\n  const Expr *callee = maybeEval(call->callee());\n\n  if (callee->op() != TO_ID)\n    return;\n\n  if (strcmp(\"assert\", callee->asId()->name()) != 0)\n    return;\n\n\n  const SQUnsignedInteger argSize = call->arguments().size();\n\n  if (!argSize || argSize > 2)\n    return;\n\n  const Expr *cond = call->arguments()[0];\n\n  speculateIfConditionHeuristics(cond, currentScope, nullptr);\n}\n\nconst char *CheckerVisitor::extractFunctionName(const CallExpr *call) {\n  const Expr *c = maybeEval(call->callee());\n\n  const char *calleeName = nullptr;\n  if (c->op() == TO_ID)\n    calleeName = c->asId()->name();\n  else if (c->op() == TO_FUNCTION) {\n    calleeName = c->asFunctionExpr()->name();\n  }\n  else if (c->op() == TO_GETFIELD)\n    calleeName = c->asGetField()->fieldName();\n\n  return calleeName;\n}\n\nvoid CheckerVisitor::visitBinaryBranches(Expr *lhs, Expr *rhs, bool inv) {\n  VarScope *trunkScope = currentScope;\n  VarScope *branchScope = nullptr;\n\n  lhs->visit(this);\n\n  branchScope = trunkScope->copy(arena);\n\n  if (inv) {\n    speculateIfConditionHeuristics(lhs, nullptr, branchScope);\n  }\n  else {\n    speculateIfConditionHeuristics(lhs, branchScope, nullptr);\n  }\n\n  currentScope = branchScope;\n  rhs->visit(this);\n\n  trunkScope->merge(branchScope);\n\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitLiteralExpr(LiteralExpr *l) {\n  checkForgotSubst(l);\n}\n\nvoid CheckerVisitor::visitId(Id *id) {\n  const StackSlot &ss = nodeStack.back();\n  const Node *parentNode = nullptr;\n\n  if (ss.sst == SST_NODE)\n    parentNode = ss.n;\n\n  ValueRef *v = findValueInScopes(id->name());\n\n  if (!v)\n    return;\n\n  checkIdUsed(id, parentNode, v);\n}\n\nvoid CheckerVisitor::visitUnExpr(UnExpr *expr) {\n  checkContainerModification(expr);\n\n  Visitor::visitUnExpr(expr);\n}\n\nvoid CheckerVisitor::visitBinExpr(BinExpr *expr) {\n  checkAndOrPriority(expr);\n  checkBitwiseParenBool(expr);\n  checkNullCoalescingPriority(expr);\n  checkAssignmentToItself(expr);\n  checkParamAssignInLambda(expr);\n  checkSameOperands(expr);\n  checkAlwaysTrueOrFalse(expr);\n  checkDeclarationInArith(expr);\n  checkIntDivByZero(expr);\n  checkPotentiallyNullableOperands(expr);\n  checkBitwiseToBool(expr);\n  checkCompareWithBool(expr);\n  checkRelativeCompareWithBool(expr);\n  checkCopyOfExpression(expr);\n  checkConstInBoolExpr(expr);\n  checkShiftPriority(expr);\n  checkCompareWithContainer(expr);\n  checkBoolToStrangePosition(expr);\n  checkNewSlotNameMatch(expr);\n  checkPlusString(expr);\n  checkNewGlobalSlot(expr);\n  checkUselessNullC(expr);\n  checkCannotBeNull(expr);\n  checkCanBeSimplified(expr);\n  checkRangeCheck(expr);\n\n  Expr *lhs = expr->lhs();\n  Expr *rhs = expr->rhs();\n\n  switch (expr->op())\n  {\n  case TO_NULLC:\n  case TO_OROR:\n    nodeStack.push_back({ SST_NODE, expr });\n    visitBinaryBranches(lhs, rhs, true);\n    nodeStack.pop_back();\n    break;\n  case TO_ANDAND:\n    nodeStack.push_back({ SST_NODE, expr });\n    visitBinaryBranches(lhs, rhs, false);\n    nodeStack.pop_back();\n    break;\n  case TO_PLUSEQ:\n  case TO_MINUSEQ:\n  case TO_MULEQ:\n  case TO_DIVEQ:\n  case TO_MODEQ:\n  case TO_NEWSLOT:\n  case TO_ASSIGN:\n    nodeStack.push_back({ SST_NODE, expr });\n    expr->rhs()->visit(this);\n    expr->lhs()->visit(this);\n    nodeStack.pop_back();\n    break;\n  default:\n    Visitor::visitBinExpr(expr);\n    break;\n  }\n\n  applyBinaryToScope(expr);\n}\n\nvoid CheckerVisitor::visitTerExpr(TerExpr *expr) {\n  checkTernaryPriority(expr);\n  checkSameValues(expr);\n  checkAlwaysTrueOrFalse(expr);\n  checkCanBeSimplified(expr);\n\n  nodeStack.push_back({ SST_NODE, expr });\n\n  expr->a()->visit(this);\n\n  VarScope *trunkScope = currentScope;\n\n  VarScope *ifTrueScope = trunkScope->copy(arena);\n  VarScope *ifFalseScope = trunkScope->copy(arena);\n\n  speculateIfConditionHeuristics(expr->a(), ifTrueScope, ifFalseScope);\n\n  currentScope = ifTrueScope;\n  expr->b()->visit(this);\n\n  currentScope = ifFalseScope;\n  expr->c()->visit(this);\n\n  nodeStack.pop_back();\n\n  ifTrueScope->merge(ifFalseScope);\n  trunkScope->copyFrom(ifTrueScope);\n\n  ifTrueScope->~VarScope();\n  ifFalseScope->~VarScope();\n\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitIncExpr(IncExpr *expr) {\n  const char *name = computeNameRef(deparenStatic(expr->argument()), nullptr, 0);\n  if (name) {\n    ValueRef *v = findValueInScopes(name);\n\n    if (v) {\n      if (currentInfo) {\n        currentInfo->addModifiable(name, v->info->ownedScope->owner);\n      }\n\n      v->expression = nullptr;\n      v->state = VRS_MULTIPLE;\n      v->flagsNegative = v->flagsPositive = 0;\n    }\n  }\n\n  Visitor::visitIncExpr(expr);\n}\n\nvoid CheckerVisitor::visitCallExpr(CallExpr *expr) {\n  checkExtendToAppend(expr);\n  checkMergeEmptyTable(expr);\n  checkEmptyArrayResize(expr);\n  checkAlreadyRequired(expr);\n  checkCallNullable(expr);\n  checkPersistCall(expr);\n  checkForbiddenCall(expr);\n  checkCallFromRoot(expr);\n  checkForbiddenParentDir(expr);\n  checkFormatArguments(expr);\n  checkContainerModification(expr);\n  checkUnwantedModification(expr);\n  checkCannotBeNull(expr);\n  checkBooleanLambda(expr);\n  checkCallbackReturnValue(expr);\n  checkCallbackShouldNotReturn(expr);\n\n  applyCallToScope(expr);\n\n  checkAssertCall(expr);\n\n  Visitor::visitCallExpr(expr);\n\n  checkArguments(expr);\n}\n\nvoid CheckerVisitor::checkBoolIndex(const GetSlotExpr *expr) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *key = maybeEval(expr->key())->asExpression();\n\n  if (isBooleanResultOperator(key->op())) {\n    report(expr->key(), DiagnosticsId::DI_BOOL_AS_INDEX);\n  }\n}\n\nvoid CheckerVisitor::checkNullableIndex(const GetSlotExpr *expr) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *key = expr->key();\n\n  if (!isSafeAccess(expr) && isPotentiallyNullable(key)) {\n    report(expr->key(), DiagnosticsId::DI_POTENTIALLY_NULLABLE_INDEX);\n  }\n}\n\nvoid CheckerVisitor::checkGlobalAccess(const GetFieldExpr *expr) {\n  if (expr->receiver()->op() != TO_ROOT_TABLE_ACCESS)\n    return;\n\n  const BinExpr *newslot = nullptr;\n\n  for (auto it = nodeStack.rbegin(); it != nodeStack.rend(); ++it) {\n    if (it->sst != SST_NODE)\n      continue;\n\n    const Node *n = it->n;\n\n    if (n->op() != TO_NEWSLOT)\n      continue;\n\n    newslot = static_cast<const BinExpr *>(n);\n    break;\n  }\n\n  if (newslot) {\n    const Expr *lhs = deparen(newslot->lhs());\n    if (lhs == expr)\n      return;\n  }\n\n  storeGlobalUsage(expr->fieldName(), expr);\n}\n\nvoid CheckerVisitor::visitGetFieldExpr(GetFieldExpr *expr) {\n  checkAccessNullable(expr);\n  checkEnumConstUsage(expr);\n  checkGlobalAccess(expr);\n  checkAccessFromStatic(expr);\n\n  Visitor::visitGetFieldExpr(expr);\n\n  checkExternalField(expr);\n}\n\nvoid CheckerVisitor::visitGetSlotExpr(GetSlotExpr *expr) {\n  checkBoolIndex(expr);\n  checkNullableIndex(expr);\n  checkAccessNullable(expr);\n\n  Visitor::visitGetSlotExpr(expr);\n}\n\nvoid CheckerVisitor::checkDuplicateSwitchCases(SwitchStatement *swtch) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &cases = swtch->cases();\n\n  for (int32_t i = 0; i < int32_t(cases.size()) - 1; ++i) {\n    for (int32_t j = i + 1; j < cases.size(); ++j) {\n      const auto &icase = cases[i];\n      const auto &jcase = cases[j];\n\n      if (_equalChecker.check(icase.val, jcase.val)) {\n        report(jcase.val, DiagnosticsId::DI_DUPLICATE_CASE);\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkMissedBreak(const SwitchStatement *swtch) {\n  if (isEffectsGatheringPass)\n    return;\n\n  auto &cases = swtch->cases();\n\n  FunctionReturnTypeEvaluator rtEvaluator(this);\n\n  const Statement *last = nullptr;\n  for (auto &c : cases) {\n\n    if (last) {\n      report(last, DiagnosticsId::DI_MISSED_BREAK);\n    }\n    last = nullptr;\n\n    const Statement *stmt = c.stmt;\n    bool r = false;\n    rtEvaluator.compute(stmt, r);\n    if (!r) {\n      const Statement *uw = unwrapBodyNonEmpty(stmt);\n\n      if (!uw)\n        continue; // empty case statement -> FT\n\n      const TreeOp op = uw->op();\n      if (op != TO_BLOCK) {\n        if (op != TO_BREAK)\n          last = unwrapBody(stmt);\n      }\n      else {\n        const Block *b = uw->asBlock();\n        int32_t dummy;\n        const Statement *tmp = lastNonEmpty(b, dummy);\n        if (tmp && tmp->op() != TO_BREAK) {\n          last = unwrapBody(b);\n        }\n      }\n    }\n  }\n\n  if (last && swtch->defaultCase().stmt) {\n    /*\n      switch (x) {\n        case A:\n          ...\n          break;\n\n        case B:\n          ...   <-- missed break\n        default:\n          ...\n      }\n    */\n    report(last, DiagnosticsId::DI_MISSED_BREAK);\n  }\n}\n\nvoid CheckerVisitor::checkDuplicateIfBranches(IfStatement *ifStmt) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  if (_equalChecker.check(ifStmt->thenBranch(), ifStmt->elseBranch())) {\n    report(ifStmt->elseBranch(), DiagnosticsId::DI_THEN_ELSE_EQUAL);\n  }\n}\n\nvoid CheckerVisitor::checkDuplicateIfConditions(IfStatement *ifStmt) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const Statement *elseB = unwrapSingleBlock(ifStmt->elseBranch());\n  const Expr *duplicated = nullptr;\n\n  if (elseB && elseB->op() == TO_IF) {\n    if (findIfWithTheSameCondition(ifStmt->condition(), static_cast<const IfStatement *>(elseB), duplicated)) {\n      // TODO: high-light both conditions, original and duplicated\n      report(duplicated, DiagnosticsId::DI_DUPLICATE_IF_EXPR);\n    }\n  }\n}\n\nstatic bool wrappedBody(const Statement *stmt) {\n  if (stmt->op() != TO_BLOCK)\n    return false;\n\n  const Block *b = stmt->asBlock();\n\n  if (b->statements().size() != 1)\n    return false;\n\n  const Statement *wp = b->statements().back();\n\n  return stmt->lineStart() == wp->lineStart()\n    && stmt->lineEnd() == wp->lineEnd()\n    && stmt->columnStart() == wp->columnStart()\n    && stmt->columnEnd() == wp->columnEnd();\n}\n\nvoid CheckerVisitor::checkSuspiciousFormattingOfStetementSequence(const Statement *prev, const Statement *cur)\n{\n  if (prev && cur && prev->lineStart() != cur->lineStart() && prev->columnStart() != cur->columnStart())\n    report(cur, DiagnosticsId::DI_INVALID_INDENTATION, std::to_string(prev->lineStart()).c_str(), std::to_string(cur->lineStart()).c_str());\n}\n\nvoid CheckerVisitor::checkSuspiciousFormatting(const Statement *body, const Statement *stmt) {\n  if (wrappedBody(body)) {\n    if (stmt->lineStart() != body->lineStart() && stmt->columnStart() >= body->columnStart()) {\n\n      // check if it is not `else if (...) ... ` pattern\n      const IfStatement *elif = nullptr;\n      const size_t nssize = nodeStack.size();\n      if (nssize >= 2) {\n        for (int i = 1; i <= 2; ++i) {\n          auto &ss = nodeStack[nssize - i];\n          if (ss.sst == SST_NODE && ss.n->op() == TO_IF) {\n            elif = static_cast<const IfStatement *>(ss.n);\n            break;\n          }\n        }\n      }\n\n      if (elif)\n        return;\n\n      report(body, DiagnosticsId::DI_SUSPICIOUS_FMT);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkVariableMismatchForLoop(ForStatement *loop) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *varname = nullptr;\n  Node *init = loop->initializer();\n  Expr *cond = loop->condition();\n  Expr *mod = loop->modifier();\n\n  if (init) {\n    if (init->op() == TO_ASSIGN) {\n      Expr *l = static_cast<BinExpr *>(init)->lhs();\n      if (l->op() == TO_ID)\n        varname = l->asId()->name();\n    }\n\n    if (init->op() == TO_VAR) {\n      VarDecl *decl = static_cast<VarDecl *>(init);\n      varname = decl->name();\n    }\n  }\n\n  if (varname && cond) {\n    if (isBinaryArith(cond)) {\n      BinExpr *bin = static_cast<BinExpr *>(cond);\n      Expr *l = bin->lhs();\n      Expr *r = bin->rhs();\n\n      if (l->op() == TO_ID) {\n        if (strcmp(l->asId()->name(), varname) != 0) {\n          if (r->op() != TO_ID || (strcmp(r->asId()->name(), varname) != 0)) {\n            report(cond, DiagnosticsId::DI_MISMATCH_LOOP_VAR);\n          }\n        }\n      }\n    }\n  }\n\n  if (varname && mod) {\n    if (isAssignExpr(mod)) {\n      Expr *lhs = static_cast<BinExpr *>(mod)->lhs();\n      if (lhs->op() == TO_ID) {\n        if (strcmp(varname, lhs->asId()->name()) != 0) {\n          report(mod, DiagnosticsId::DI_MISMATCH_LOOP_VAR);\n        }\n      }\n    }\n\n    if (mod->op() == TO_INC) {\n      Expr *arg = static_cast<IncExpr *>(mod)->argument();\n      if (arg->op() == TO_ID) {\n        if (strcmp(varname, arg->asId()->name()) != 0) {\n          report(mod, DiagnosticsId::DI_MISMATCH_LOOP_VAR);\n        }\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkUnterminatedLoop(LoopStatement *loop) {\n\n  if (isEffectsGatheringPass)\n    return;\n\n  LoopTerminatorCollector collector(true);\n  Statement *body = loop->body();\n\n  body->visit(&collector);\n\n  if (collector.hasUnconditionalTerminator()) {\n    const Statement *t = collector.terminator;\n    assert(t);\n    const char *type = terminatorOpToName(t->op());\n\n    report(t, DiagnosticsId::DI_UNCOND_TERMINATED_LOOP, type);\n  }\n}\n\nvoid CheckerVisitor::checkEmptyWhileBody(WhileStatement *loop) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Statement *body = unwrapBody(loop->body());\n\n  if (body && body->op() == TO_EMPTY) {\n    report(body, DiagnosticsId::DI_EMPTY_BODY, \"'while' loop\");\n  }\n}\n\nvoid CheckerVisitor::checkEmptyThenBody(IfStatement *stmt) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Statement *thenStmt = unwrapBody(stmt->thenBranch());\n\n  if (thenStmt && thenStmt->op() == TO_EMPTY) {\n    report(thenStmt, DiagnosticsId::DI_EMPTY_BODY, \"'then' branch of 'if'\");\n  }\n}\n\nstatic bool terminateAssignSequence(const Expr *assignee, Node *tree) {\n  AssignSeqTerminatorFinder finder(assignee);\n\n  return finder.check(tree);\n}\n\nvoid CheckerVisitor::checkAssignedTwice(const Block *b) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &statements = b->statements();\n\n  for (int32_t i = 0; i < int32_t(statements.size()) - 1; ++i) {\n    const Expr *iexpr = unwrapExprStatement(statements[i]);\n\n    if (iexpr && isAssignOp(iexpr->op())) {\n      const BinExpr *iassgn = static_cast<const BinExpr *>(iexpr);\n      const Expr *firstAssignee = iassgn->lhs();\n\n      for (int32_t j = i + 1; j < statements.size(); ++j) {\n        Statement *stmt = statements[j];\n        Expr *jexpr = unwrapExprStatement(stmt);\n\n        if (jexpr && jexpr->op() == TO_ASSIGN) {\n          const BinExpr *jassgn = static_cast<const BinExpr *>(jexpr);\n\n          if (_equalChecker.check(firstAssignee, jassgn->lhs())) {\n            bool ignore = existsInTree(firstAssignee, jassgn->rhs());\n            if (!ignore && firstAssignee->op() == TO_GETSLOT) {\n              const GetSlotExpr *getT = firstAssignee->asGetSlot();\n              ignore = indexChangedInTree(getT->key());\n              if (!ignore) {\n                for (int32_t m = i + 1; m < j; ++m) {\n                  if (checkModification(getT->key(), statements[m])) {\n                    ignore = true;\n                    break;\n                  }\n                }\n              }\n            }\n\n            if (!ignore) {\n              report(jassgn, DiagnosticsId::DI_ASSIGNED_TWICE);\n            }\n          }\n        }\n        else if (terminateAssignSequence(firstAssignee, stmt)) {\n          break;\n        }\n      }\n    }\n  }\n}\n\n\nvoid CheckerVisitor::checkFunctionPairSimilarity(const FunctionExpr *f1, const FunctionExpr *f2) {\n  int32_t diff = NodeDiffComputer::compute(f1->body(), f2->body(), 4);\n  if (diff < 4) {\n    const char *name1 = f1->name();\n    const char *name2 = f2->name();\n\n    if (diff == 0)\n      report(f2, DiagnosticsId::DI_DUPLICATE_FUNC, name1, name2);\n    else {\n      int32_t complexity = NodeComplexityComputer::compute(f1->body(), functionComplexityThreshold * 3);\n      if (diff <= complexity / functionComplexityThreshold)\n        report(f2, DiagnosticsId::DI_SIMILAR_FUNC, name1, name2);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkFunctionSimilarity(const Block *b) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &statements = b->statements();\n\n  for (int32_t i = 0; i < int32_t(statements.size()); ++i) {\n    const FunctionExpr *f1 = extractFunction(statements[i]);\n    if (!f1)\n      continue;\n\n    int32_t complexity = NodeComplexityComputer::compute(f1->body(), functionComplexityThreshold);\n\n    if (complexity >= functionComplexityThreshold) {\n      for (int32_t j = i + 1; j < int32_t(statements.size()); ++j) {\n        if (const FunctionExpr *f2 = extractFunction(statements[j])) {\n          checkFunctionPairSimilarity(f1, f2);\n        }\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkFunctionSimilarity(const TableExpr *table) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &members = table->members();\n\n  for (int32_t i = 0; i < int32_t(members.size()); ++i) {\n    const FunctionExpr *f1 = extractFunction(members[i].value);\n    if (!f1)\n      continue;\n\n    int32_t complexity = NodeComplexityComputer::compute(f1->body(), functionComplexityThreshold);\n    if (complexity >= functionComplexityThreshold) {\n      for (int32_t j = i + 1; j < int32_t(members.size()); ++j) {\n        if (const FunctionExpr *f2 = extractFunction(members[j].value))\n          checkFunctionPairSimilarity(f1, f2);\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::checkAssignExpressionSimilarity(const Block *b) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &statements = b->statements();\n\n  for (int32_t i = 0; i < int32_t(statements.size()); ++i) {\n\n    const Expr *assigned1 = extractAssignedExpression(statements[i]);\n\n    if (!assigned1)\n      continue;\n\n    int32_t complexity = NodeComplexityComputer::compute(assigned1, statementComplexityThreshold);\n\n    if (complexity >= statementComplexityThreshold) {\n\n      for (int32_t j = i + 1; j < int32_t(statements.size()); ++j) {\n        const Expr *assigned2 = extractAssignedExpression(statements[j]);\n\n        if (!assigned2)\n          continue;\n\n        int32_t diff = NodeDiffComputer::compute(assigned1, assigned2, 3);\n        if (diff < 3) {\n          if (diff == 0)\n            report(assigned2, DiagnosticsId::DI_DUPLICATE_ASSIGN_EXPR);\n          else {\n            complexity = NodeComplexityComputer::compute(assigned1, statementSimilarityThreshold * 2);\n            if (diff <= complexity / statementSimilarityThreshold)\n              report(assigned2, DiagnosticsId::DI_SIMILAR_ASSIGN_EXPR);\n          }\n        }\n      }\n    }\n  }\n}\n\n// Determines if a function call's result should be utilized based on its name.\n// Returns true if the result SHOULD be utilized (warn if discarded).\n// Returns false if it's OK to discard the result (no warning).\n//\n// Special case: Boolean-named functions (is*, has*, etc.) with a single\n// \"valuable\" argument are treated as potential setters, not getters.\n// Example: isEnabled(true) might SET enabled state, not query it.\n// In this case we suppress the warning.\nbool CheckerVisitor::shouldCallResultBeUtilized(const char *name, const CallExpr *call) {\n  if (!name)\n    return false;\n\n  // Functions like __merge, findvalue, filter - always should utilize result\n  if (nameLooksLikeResultMustBeUtilized(name))\n    return true;\n\n  // Boolean-named functions (is*, has*, get*, etc.)\n  if (nameLooksLikeResultMustBeBoolean(name)) {\n    const auto &args = call->arguments();\n\n    // Multiple or zero arguments - likely a getter, should utilize result\n    if (args.size() != 1)\n      return true;\n\n    const Expr *arg = args[0];\n\n    // Single boolean expression argument (true, false, x > 0, etc.)\n    // Looks like: isEnabled(true) - setting state to true\n    if (looksLikeBooleanExpr(arg))\n      return false;\n\n    // Single identifier with boolean-like name (isValid, hasItems, etc.)\n    // Looks like: isEnabled(isCurrentlyValid) - setting state from another boolean\n    if (arg->op() == TO_ID) {\n      if (nameLooksLikeResultMustBeBoolean(arg->asId()->name()))\n        return false;\n    }\n\n    // Single call to a function whose result should be utilized\n    // Looks like: isEnabled(getValue()) - passing a meaningful value\n    // If the inner call returns something \"valuable\", we're using it as input\n    // to potentially set state, so suppress warning for the outer call\n    if (arg->op() == TO_CALL) {\n      const CallExpr *innerCall = arg->asCallExpr();\n      const Expr *callee = innerCall->callee();\n      const char *calleeName = nullptr;\n      if (callee->op() == TO_ID)\n        calleeName = callee->asId()->name();\n      else if (callee->op() == TO_GETFIELD)\n        calleeName = callee->asGetField()->fieldName();\n\n      // Recursive check: if inner call's result should be utilized,\n      // then we're passing a \"valuable\" result to outer function,\n      // which suggests outer function might be a setter\n      if (shouldCallResultBeUtilized(calleeName, innerCall))\n        return false;\n    }\n\n    // Try to evaluate the argument - it might resolve to a boolean\n    // Example: let x = true; isEnabled(x) - x evaluates to true\n    const Expr *evaled = maybeEval(arg);\n    if (looksLikeBooleanExpr(evaled))\n      return false;\n\n    // Single non-boolean argument - likely a getter, should utilize result\n    return true;\n  }\n\n  return false;\n}\n\nvoid CheckerVisitor::checkUnutilizedResult(const ExprStatement *s) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *e = s->expression();\n\n  if (e->op() == TO_CALL) {\n    const CallExpr *c = static_cast<const CallExpr *>(e);\n    const Expr *callee = c->callee();\n\n    const char *calleeName = nullptr;\n    if (callee->op() == TO_ID) {\n      calleeName = callee->asId()->name();\n    }\n    else if (callee->op() == TO_GETFIELD) {\n      calleeName = callee->asGetField()->fieldName();\n    }\n\n    if (calleeName && shouldCallResultBeUtilized(calleeName, c)) {\n      report(e, DiagnosticsId::DI_NAME_LIKE_SHOULD_RETURN, calleeName);\n    }\n  }\n  else if (!isAssignExpr(e) && e->op() != TO_INC && e->op() != TO_NEWSLOT && e->op() != TO_DELETE) {\n    report(s, DiagnosticsId::DI_UNUTILIZED_EXPRESSION);\n  }\n}\n\nvoid CheckerVisitor::checkForgottenDo(const Block *b) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &statements = b->statements();\n\n  for (int32_t i = 1; i < statements.size(); ++i) {\n    Statement *prev = statements[i - 1];\n    Statement *stmt = statements[i];\n\n    if (stmt->op() == TO_WHILE && prev->op() == TO_BLOCK) {\n      report(stmt, DiagnosticsId::DI_FORGOTTEN_DO);\n    }\n  }\n}\n\nvoid CheckerVisitor::checkUnreachableCode(const Block *block) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const auto &statements = block->statements();\n\n  for (int32_t i = 0; i < int32_t(statements.size()) - 1; ++i) {\n    Statement *stmt = statements[i];\n    Statement *next = statements[i + 1];\n    if (isBlockTerminatorStatement(stmt->op())) {\n      if (next->op() != TO_BREAK) {\n        if (!onlyEmptyStatements(i + 1, statements)) {\n          report(next, DiagnosticsId::DI_UNREACHABLE_CODE, terminatorOpToName(stmt->op()));\n          break;\n        }\n      }\n    }\n  }\n}\n\nvoid CheckerVisitor::visitExprStatement(ExprStatement *stmt) {\n  checkUnutilizedResult(stmt);\n\n  Visitor::visitExprStatement(stmt);\n}\n\nvoid CheckerVisitor::visitBlock(Block *b) {\n  checkForgottenDo(b);\n  checkUnreachableCode(b);\n  checkAssignedTwice(b);\n  checkFunctionSimilarity(b);\n  checkAssignExpressionSimilarity(b);\n\n  VarScope *thisScope = currentScope;\n  VarScope blockScope(thisScope ? thisScope->owner : nullptr, thisScope);\n  currentScope = &blockScope;\n\n  nodeStack.push_back({ SST_NODE, b });\n\n  Statement* prevStatement = nullptr;\n\n  for (Statement *s : b->statements()) {\n    s->visit(this);\n    blockScope.evalId += 1;\n\n    if (s->op() != TO_EMPTY) {\n      checkSuspiciousFormattingOfStetementSequence(prevStatement, s);\n      prevStatement = s;\n    }\n  }\n\n  nodeStack.pop_back();\n\n  blockScope.parent = nullptr;\n  blockScope.checkUnusedSymbols(this);\n  currentScope = thisScope;\n}\n\nvoid CheckerVisitor::visitForStatement(ForStatement *loop) {\n  checkUnterminatedLoop(loop);\n  checkVariableMismatchForLoop(loop);\n  checkSuspiciousFormatting(loop->body(), loop);\n\n  VarScope *trunkScope = currentScope;\n\n  Node *init = loop->initializer();\n  Expr *cond = loop->condition();\n  Expr *mod = loop->modifier();\n\n  VarScope *copyScope = trunkScope->copy(arena);\n  VarScope loopScope(copyScope->owner, copyScope);\n  currentScope = &loopScope;\n\n  if (init) {\n    init->visit(this);\n  }\n\n  if (cond) {\n    cond->visit(this);\n  }\n\n  bool wasGatheringEffects = isEffectsGatheringPass;\n  isEffectsGatheringPass = true;\n\n  {\n    VarScope *dummyScope = loopScope.copy(arena, false);\n    BreakableScope bs(this, loop, dummyScope, nullptr); // null because we don't (??) interest in exit effect here\n    currentScope = dummyScope;\n\n    loop->body()->visit(this);\n\n    if (mod)\n      mod->visit(this);\n\n    loopScope.merge(dummyScope);\n\n    dummyScope->parent = nullptr;\n    dummyScope->~VarScope();\n  }\n\n  isEffectsGatheringPass = wasGatheringEffects;\n\n  if (!isEffectsGatheringPass) {\n    BreakableScope bs(this, loop, &loopScope, copyScope);\n    currentScope = &loopScope;\n\n    if (cond)\n      speculateIfConditionHeuristics(cond, &loopScope, copyScope);\n\n    loop->body()->visit(this);\n\n    if (mod)\n      mod->visit(this);\n  }\n\n  trunkScope->merge(copyScope);\n  loopScope.checkUnusedSymbols(this);\n\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::checkNullableContainer(const ForeachStatement *loop) {\n  if (isEffectsGatheringPass)\n    return;\n\n  if (isPotentiallyNullable(loop->container())) {\n    report(loop->container(), DiagnosticsId::DI_POTENTIALLY_NULLABLE_CONTAINER);\n  }\n}\n\nvoid CheckerVisitor::visitForeachStatement(ForeachStatement *loop) {\n  checkUnterminatedLoop(loop);\n  checkNullableContainer(loop);\n  checkSuspiciousFormatting(loop->body(), loop);\n\n\n  VarScope *trunkScope = currentScope;\n  VarScope *copyScope = trunkScope->copy(arena);\n  VarScope loopScope(trunkScope->owner, copyScope);\n  currentScope = &loopScope;\n\n  const VarDecl *idx = loop->idx();\n  const VarDecl *val = loop->val();\n\n  if (idx) {\n    SymbolInfo *info = makeSymbolInfo(SK_FOREACH);\n    ValueRef *v = makeValueRef(info);\n    v->state = VRS_UNKNOWN;\n    v->expression = nullptr;\n    info->declarator.v = idx;\n    info->ownedScope = &loopScope; //-V506\n    declareSymbol(idx->name(), v);\n  }\n\n  if (val) {\n    SymbolInfo *info = makeSymbolInfo(SK_FOREACH);\n    ValueRef *v = makeValueRef(info);\n    v->state = VRS_UNKNOWN;\n    v->expression = nullptr;\n    info->declarator.v = val;\n    info->ownedScope = &loopScope; //-V506\n    declareSymbol(val->name(), v);\n  }\n\n  StackSlot slot;\n  slot.n = loop;\n  slot.sst = SST_NODE;\n  nodeStack.push_back(slot);\n\n  loop->container()->visit(this);\n\n  bool wasGatheringEffects = isEffectsGatheringPass;\n  isEffectsGatheringPass = true;\n\n  {\n    VarScope *dummyScope = loopScope.copy(arena, false);\n    BreakableScope bs(this, loop, dummyScope, nullptr); // null because we don't (??) interest in exit effect here\n    currentScope = dummyScope;\n\n    loop->body()->visit(this);\n\n    loopScope.merge(dummyScope);\n\n    dummyScope->parent = nullptr;\n    dummyScope->~VarScope();\n  }\n  isEffectsGatheringPass = wasGatheringEffects;\n\n  if (!isEffectsGatheringPass) {\n    BreakableScope bs(this, loop, &loopScope, copyScope);\n\n    currentScope = &loopScope;\n    loop->body()->visit(this);\n  }\n\n  nodeStack.pop_back();\n\n  trunkScope->merge(copyScope);\n  loopScope.checkUnusedSymbols(this);\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitWhileStatement(WhileStatement *loop) {\n  checkUnterminatedLoop(loop);\n  checkEmptyWhileBody(loop);\n  checkSuspiciousFormatting(loop->body(), loop);\n\n  loop->condition()->visit(this);\n\n  VarScope *trunkScope = currentScope;\n  VarScope *loopScope = trunkScope->copy(arena);\n  currentScope = loopScope;\n\n  bool wasGatheringEffects = isEffectsGatheringPass;\n  isEffectsGatheringPass = true;\n\n  {\n    BreakableScope bs(this, loop, loopScope, nullptr); // null because we don't (??) interest in exit effect here\n    loop->body()->visit(this);\n  }\n  isEffectsGatheringPass = wasGatheringEffects;\n\n  if (!isEffectsGatheringPass) {\n    BreakableScope bs(this, loop, loopScope, trunkScope);\n    speculateIfConditionHeuristics(loop->condition(), loopScope, trunkScope);\n\n    loop->body()->visit(this);\n  }\n\n  trunkScope->merge(loopScope);\n  loopScope->~VarScope();\n\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitDoWhileStatement(DoWhileStatement *loop) {\n  checkUnterminatedLoop(loop);\n\n  VarScope *trunkScope = currentScope;\n  VarScope *loopScope = trunkScope->copy(arena);\n  currentScope = loopScope;\n\n  bool wasGatheringEffects = isEffectsGatheringPass;\n  isEffectsGatheringPass = true;\n\n  {\n    BreakableScope bs(this, loop, loopScope, nullptr); // null because we don't (??) interest in exit effect here\n    loop->body()->visit(this);\n    loop->condition()->visit(this);\n  }\n  isEffectsGatheringPass = wasGatheringEffects;\n\n  if (!isEffectsGatheringPass) {\n    BreakableScope bs(this, loop, loopScope, trunkScope);\n    loop->body()->visit(this);\n    loop->condition()->visit(this);\n  }\n\n  trunkScope->copyFrom(loopScope);\n  loopScope->~VarScope();\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitBreakStatement(BreakStatement *breakStmt) {\n  VarScope *trunkScope = currentScope;\n  BreakableScope *bs = breakScope;\n  assert(bs);\n\n  if (bs->kind != BSK_LOOP)\n    return;\n\n  if (bs->exitScope)\n    bs->exitScope->mergeUnbalanced(trunkScope);\n}\n\nvoid CheckerVisitor::visitContinueStatement(ContinueStatement *continueStmt) {\n  VarScope *trunkScope = currentScope;\n  BreakableScope *bs = breakScope;\n  assert(bs);\n\n  while (bs->kind != BSK_LOOP)\n    bs = bs->parent;\n\n  assert(bs->loopScope);\n\n  bs->loopScope->mergeUnbalanced(trunkScope);\n}\n\n\nbool CheckerVisitor::detectTypeOfPattern(const Expr *expr, const Expr *&res_checkee, const LiteralExpr *&res_lit) {\n  // Either of 'typeof checkee ==/!= \"lit\"' or 'type(checkee) ==/!= \"lit\"\n  expr = deparenStatic(expr);\n\n  TreeOp op = expr->op(); // -V522\n\n  if (op != TO_EQ && op != TO_NE)\n    return false; // not typeof pattern\n\n  const BinExpr *bin = expr->asBinExpr();\n\n  const Expr *lhs = deparenStatic(bin->lhs());\n  const Expr *rhs = deparenStatic(bin->rhs());\n\n  const LiteralExpr *l_lit = lhs->op() == TO_LITERAL ? lhs->asLiteral() : nullptr; // -V522\n  const LiteralExpr *r_lit = rhs->op() == TO_LITERAL ? rhs->asLiteral() : nullptr; // -V522\n\n  if (!l_lit && !r_lit)\n    return false;\n\n  if (l_lit && r_lit)\n    return false;\n\n  const LiteralExpr *lit = l_lit ? l_lit : r_lit;\n\n  if (lit->kind() != LK_STRING) // -V522\n    return false;\n\n  const Expr *checkExpr = lit == lhs ? rhs : lhs;\n\n  if (checkExpr->op() == TO_TYPEOF) { // -V522\n    const UnExpr *typeOf = static_cast<const UnExpr *>(checkExpr);\n    res_checkee = deparenStatic(typeOf->argument()); // -V522\n    res_lit = lit;\n    return true;\n  }\n\n  if (checkExpr->op() == TO_CALL) {\n    // check for `type(check)` pattern\n\n    const CallExpr *call = checkExpr->asCallExpr();\n    const Expr *callee = maybeEval(call->callee());\n\n    if (callee->op() != TO_ID || strcmp(\"type\", callee->asId()->name()) != 0) {\n      return false;\n    }\n\n    if (call->arguments().size() != 1)\n      return false;\n\n    res_checkee = deparenStatic(call->arguments()[0]);\n    res_lit = lit;\n    return true;\n  }\n\n  return false;\n}\n\nbool CheckerVisitor::detectNullCPattern(TreeOp op, const Expr *cond, const Expr *&checkee) {\n\n  // detect patterns like `(o?.x ?? D) <op> D` which implies o not null\n\n  // (o?.f ?? D) != V -- then-branch implies `o` non-null\n  // (o?.f ?? D) == V -- assume else-branch implies `o` non-null\n  // (o?.f ?? D) > V -- then-b implies `o` non-null\n  // (o?.f ?? D) < V -- then-b implies `o` non-null\n  // (o?.f ?? D) >= V -- else-branch implies `o` non-null\n  // (o?.f ?? D) <= V -- else-branch implies `o` non-null\n\n  if (op != TO_LT && op != TO_GT && op != TO_EQ && op != TO_NE && op != TO_LE && op != TO_GE) {\n    return false;\n  }\n\n  const BinExpr *bin = cond->asBinExpr();\n\n  const Expr *lhs = deparenStatic(bin->lhs());\n  const Expr *rhs = deparenStatic(bin->rhs());\n\n  if (lhs->op() != TO_NULLC && rhs->op() != TO_NULLC) // -V522\n    return false;\n\n  const BinExpr *nullc = lhs->op() == TO_NULLC ? lhs->asBinExpr() : rhs->asBinExpr();\n  const Expr *V = lhs == nullc ? rhs : lhs;\n  const Expr *D = deparenStatic(nullc->rhs());\n  const Expr *candidate = deparenStatic(nullc->lhs());\n\n  const Expr *reciever = extractReceiver(candidate);\n\n  if (reciever == nullptr)\n    return false;\n\n  if (V->op() == TO_ID || _equalChecker.check(D, V)) { // -V522\n    checkee = reciever;\n    return true;\n  }\n\n  return false;\n}\n\nvoid CheckerVisitor::speculateIfConditionHeuristics(const Expr *cond, VarScope *thenScope, VarScope *elseScope, bool inv) {\n\n  std::unordered_set<const Expr *> visited;\n\n  speculateIfConditionHeuristics(cond, thenScope, elseScope, visited, -1, 0, inv);\n}\n\n#define NULL_CHECK_F 1\n\nvoid CheckerVisitor::speculateIfConditionHeuristics(const Expr *cond, VarScope *thenScope, VarScope *elseScope, std::unordered_set<const Expr *> &visited, int32_t evalId, unsigned flags, bool inv) {\n  cond = deparenStatic(cond);\n\n  if (visited.find(cond) != visited.end()) {\n    return;\n  }\n\n  visited.emplace(cond);\n\n  TreeOp op = cond->op();\n\n  VarScope *thisScope = currentScope;\n\n  if (op == TO_NOT) {\n    const UnExpr *u = static_cast<const UnExpr *>(cond);\n    return speculateIfConditionHeuristics(u->argument(), thenScope, elseScope, visited, evalId, flags, !inv);\n  }\n\n  bool invertLR = false;\n  if (op == TO_NE) {\n    op = TO_EQ;\n    inv = !inv;\n  } else if (op == TO_OROR) {\n    // apply a || b <==> !(!a && !b)\n    op = TO_ANDAND;\n    invertLR = true;\n    inv = !inv;\n  }\n\n  if (inv) {\n    std::swap(thenScope, elseScope);\n  }\n\n  const Expr *nullcCheckee = nullptr;\n  if (detectNullCPattern(op, cond, nullcCheckee)) {\n    // (o?.f ?? D) == V -- assume else-branch implies `o` non-null\n    // (o?.f ?? D) > V -- then-b implies `o` non-null\n    // (o?.f ?? D) < V -- then-b implies `o` non-null\n\n    if (op == TO_LE || op == TO_GE) {\n      if (elseScope) {\n        currentScope = elseScope;\n        setValueFlags(nullcCheckee, 0, RT_NULL);\n      }\n    } else if (op == TO_EQ) {\n      if (elseScope) {\n        currentScope = elseScope;\n        setValueFlags(nullcCheckee, 0, RT_NULL);\n      }\n    }\n    else {\n      assert(op == TO_LT || op == TO_GT);\n      if (thenScope) {\n        currentScope = thenScope;\n        setValueFlags(nullcCheckee, 0, RT_NULL);\n      }\n    }\n\n    currentScope = thisScope; // -V519\n    return;\n  }\n\n  if (op == TO_NULLC) {\n    // o?.f ?? false\n    // o?.f ?? true\n    const BinExpr *bin = cond->asBinExpr();\n    const Expr *lhs = deparenStatic(bin->lhs());\n    const Expr *rhs = deparenStatic(bin->rhs());\n\n    if (rhs->op() != TO_LITERAL) { // -V522\n      return;\n    }\n\n    const LiteralExpr *lit = rhs->asLiteral();\n    bool nullCond;\n    switch (lit->kind())\n    {\n    case LK_BOOL:\n      nullCond = rhs->asLiteral()->b();\n      break;\n    case LK_NULL:\n      nullCond = false;\n      break;\n    case LK_INT:\n      nullCond = lit->i() != 0;\n      break;\n    case LK_FLOAT:\n      nullCond = lit->f() != 0.0f;\n      break;\n    case LK_STRING:\n      nullCond = true;\n      break;\n    default:\n      assert(0 && \"unknown literal kind\");\n      break;\n    }\n\n    unsigned pf, nf;\n\n    if (nullCond) {\n      pf = RT_NULL;\n      nf = 0;\n    }\n    else {\n      pf = 0;\n      nf = RT_NULL;\n    }\n\n    const Expr *receiver = extractReceiver(lhs);\n\n    if (!receiver)\n      return;\n\n    if (thenScope && !nullCond) {\n      currentScope = thenScope;\n      setValueFlags(receiver, pf, nf);\n    }\n\n    if (elseScope && nullCond) {\n      currentScope = elseScope;\n      setValueFlags(receiver, nf, pf); // -V764\n    }\n\n    currentScope = thisScope; // -V519\n\n    return;\n  }\n\n  if (evalId == -1 && op == TO_CALL && thenScope) {\n    // if condition looks like `if (foo(x)) x.bar()` consider call as null check\n    currentScope = thenScope;\n    const CallExpr *call = cond->asCallExpr();\n    for (auto parg : call->arguments()) {\n      auto arg = deparenStatic(parg);\n      if (arg->op() == TO_ID) { // -V522\n        setValueFlags(arg, 0, RT_NULL);\n      }\n    }\n\n    const Expr *callee = extractReceiver(call->callee());\n    if (callee) {\n      setValueFlags(callee, 0, RT_NULL);\n    }\n\n    currentScope = thisScope; // -V519\n    return;\n  }\n\n  if (op == TO_ID) {\n    int32_t evalIndex = -1;\n    const Expr *eval = maybeEval(cond, evalIndex);\n\n    bool notOverriden = evalId == -1 || evalIndex < evalId;\n\n    if (thenScope && notOverriden) {\n      // set iff it was explicit check like `if (o) { .. }`\n      // otherwise there could be complexities, see intersected_assignment.nut\n      currentScope = thenScope;\n      setValueFlags(cond, 0, RT_NULL);\n      currentScope = thisScope;\n    }\n\n    if (elseScope && notOverriden && (flags & NULL_CHECK_F)) {\n      // set NULL iff it was explicit null check `if (o == null) { ... }` otherwise it could not be null, see w233_inc_in_for.nut\n      currentScope = elseScope;\n      setValueFlags(cond, RT_NULL, 0);\n      currentScope = thisScope;\n    }\n\n    if (eval != cond) {\n      // let cond = x != null\n      // if (cond) { ... }\n      speculateIfConditionHeuristics(eval, thenScope, elseScope, visited, evalIndex, flags, false);\n    }\n    return;\n  }\n\n  if (op == TO_GETSLOT || op == TO_GETFIELD) {\n    // x?[y]\n    const AccessExpr *acc = static_cast<const AccessExpr *>(cond);\n    const Expr *reciever = extractReceiver(deparenStatic(acc->receiver()));\n\n    if (reciever && thenScope) {\n      currentScope = thenScope;\n      setValueFlags(reciever, 0, RT_NULL);\n    }\n\n    if (op == TO_GETSLOT) {\n      const Expr *key = deparenStatic(acc->asGetSlot()->key());\n      if (thenScope) {\n        currentScope = thenScope;\n        setValueFlags(key, 0, RT_NULL);\n      }\n    }\n\n    currentScope = thisScope; // -V519\n\n    return;\n  }\n\n  if (op == TO_EQ) {\n    const BinExpr *bin = cond->asBinExpr();\n    const Expr *lhs = deparenStatic(bin->lhs());\n    const Expr *rhs = deparenStatic(bin->rhs());\n\n    const LiteralExpr *lhs_lit = lhs->op() == TO_LITERAL ? lhs->asLiteral() : nullptr; // -V522\n    const LiteralExpr *rhs_lit = rhs->op() == TO_LITERAL ? rhs->asLiteral() : nullptr; // -V522\n\n    const LiteralExpr *lit = lhs_lit ? lhs_lit : rhs_lit;\n    const Expr *testee = lit == lhs ? rhs : lhs;\n\n    if (!lit)\n      return;\n\n    if (lit->kind() == LK_NULL) {\n      speculateIfConditionHeuristics(testee, elseScope, thenScope, visited, evalId, flags | NULL_CHECK_F, false);\n      return;\n    }\n\n    const Expr *receiver = extractReceiver(testee);\n\n    if (receiver && thenScope) {\n      currentScope = thenScope;\n      setValueFlags(receiver, 0, RT_NULL);\n      currentScope = thisScope;\n    }\n\n  }\n\n  if (isRelationOperator(op)) {\n    const BinExpr *bin = cond->asBinExpr();\n    const Expr *lhs = deparenStatic(bin->lhs());\n    const Expr *rhs = deparenStatic(bin->rhs());\n\n    const Id *lhs_id = lhs->op() == TO_ID ? lhs->asId() : nullptr; // -V522\n    const Id *rhs_id = rhs->op() == TO_ID ? rhs->asId() : nullptr; // -V522\n\n    if (thenScope) {\n      currentScope = thenScope;\n      if (lhs_id) {\n        setValueFlags(lhs_id, 0, RT_NULL);\n      }\n      if (rhs_id) {\n        setValueFlags(rhs_id, 0, RT_NULL);\n      }\n      currentScope = thisScope;\n    }\n    return;\n  }\n\n  const LiteralExpr *typeLit = nullptr;\n  const Expr *typeCheckee = nullptr;\n\n  if (detectTypeOfPattern(cond, typeCheckee, typeLit)) {\n    assert(typeCheckee && typeLit);\n\n    const Id *checkeeId = extractReceiver(typeCheckee);\n    if (!checkeeId)\n      return;\n\n    bool nullCheck = strcmp(typeLit->s(), \"null\") == 0; // todo: should it be more precise in case of avaliable names\n    bool accessCheck = typeCheckee != checkeeId;\n\n    // if it's null check we could know for sure that true-branch implies NULL and false-branch implies NON_NULL\n    // if it's not a null check we could only guarantee that true-branch implies NON_NULL\n    unsigned pt = 0, nt = 0, pe = 0, ne = 0;\n\n    if (nullCheck) {\n      if (accessCheck) {\n        ne = RT_NULL;\n      }\n      else {\n        pt = RT_NULL;\n        ne = RT_NULL;\n      }\n    }\n    else {\n      nt = RT_NULL;\n    }\n\n    if (thenScope) {\n      currentScope = thenScope;\n      setValueFlags(checkeeId, pt, nt);\n    }\n    if (elseScope) {\n      currentScope = elseScope;\n      setValueFlags(checkeeId, pe, ne);\n    }\n\n    currentScope = thisScope; // -V519\n\n    return;\n  }\n\n  if (op == TO_ANDAND) {\n    const BinExpr *bin = cond->asBinExpr();\n    const Expr *lhs = bin->lhs();\n    const Expr *rhs = bin->rhs();\n\n    VarScope *lhsEScope = nullptr;\n    VarScope *rhsEScope = nullptr;\n\n    // In '&&' operator all effects of the left-hand side work for the right side as well\n    if (elseScope) {\n      lhsEScope = elseScope->copy(arena);\n      rhsEScope = elseScope->copy(arena);\n    }\n\n    speculateIfConditionHeuristics(lhs, thenScope, lhsEScope, visited, evalId, flags, invertLR);\n    speculateIfConditionHeuristics(rhs, thenScope, rhsEScope, visited, evalId, flags, invertLR);\n\n    if (elseScope) {\n      // In contrast in `false`-branch there is no such integral effect, all we could say is something common of both side so\n      // to compute that `common` part intersect lhs with rhs\n      lhsEScope->intersectScopes(rhsEScope); // -V522\n      elseScope->copyFrom(lhsEScope);\n\n      lhsEScope->~VarScope(); // -V522\n      rhsEScope->~VarScope(); // -V522\n    }\n\n    return;\n  }\n\n  if (op == TO_INSTANCEOF || op == TO_IN) {\n    const BinExpr *bin = cond->asBinExpr();\n    const Expr *lhs = bin->lhs();\n    const Expr *rhs = bin->rhs();\n\n    const Expr *checkee = extractReceiver(lhs);\n\n    if (checkee && thenScope) {\n      currentScope = thenScope;\n      setValueFlags(checkee, 0, RT_NULL);\n    }\n\n    if (op == TO_IN) {\n      checkee = extractReceiver(rhs);\n      if (checkee && thenScope) {\n        currentScope = thenScope;\n        setValueFlags(checkee, 0, RT_NULL);\n      }\n    }\n\n    currentScope = thisScope; // -V519\n\n    return;\n  }\n}\n\n\nvoid CheckerVisitor::visitIfStatement(IfStatement *ifstmt) {\n  checkEmptyThenBody(ifstmt);\n  checkDuplicateIfConditions(ifstmt);\n  checkDuplicateIfBranches(ifstmt);\n  checkAlwaysTrueOrFalse(ifstmt->condition());\n  checkSuspiciousFormatting(ifstmt->thenBranch(), ifstmt);\n\n  VarScope *trunkScope = currentScope;\n  VarScope *thenScope = trunkScope->copy(arena);\n  VarScope *dummyScope = trunkScope->copy(arena);\n  VarScope *elseScope = ifstmt->elseBranch() ? trunkScope->copy(arena) : nullptr;\n\n  nodeStack.push_back({ SST_NODE, ifstmt });\n\n  currentScope = dummyScope;\n\n  ifstmt->condition()->visit(this);\n\n  currentScope = trunkScope;\n\n  // pass fall-through branch to not lose effects\n  speculateIfConditionHeuristics(ifstmt->condition(), thenScope, elseScope ? elseScope : trunkScope);\n\n  currentScope = thenScope;\n\n  ifstmt->thenBranch()->visit(this);\n\n  bool isThenFT = isFallThroughBranch(ifstmt->thenBranch());\n  bool isElseFT = true;\n\n  if (ifstmt->elseBranch()) {\n    currentScope = elseScope;\n    ifstmt->elseBranch()->visit(this);\n    isElseFT = isFallThroughBranch(ifstmt->elseBranch());\n  }\n\n  nodeStack.pop_back();\n\n  if (isThenFT && isElseFT) {\n    if (elseScope) {\n      thenScope->merge(elseScope);\n      trunkScope->copyFrom(thenScope);\n    }\n    else {\n      trunkScope->merge(thenScope);\n    }\n  }\n  else if (isThenFT) {\n    trunkScope->copyFrom(thenScope);\n  }\n  else if (elseScope && isElseFT) {\n    trunkScope->copyFrom(elseScope);\n  }\n\n  if (elseScope)\n    elseScope->~VarScope();\n\n  thenScope->~VarScope();\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitSwitchStatement(SwitchStatement *swtch) {\n  checkDuplicateSwitchCases(swtch);\n  checkMissedBreak(swtch);\n\n  Expr *expr = swtch->expression();\n  expr->visit(this);\n\n  auto &cases = swtch->cases();\n  VarScope *trunkScope = currentScope;\n\n  BreakableScope breakScope(this, swtch); // -V688\n\n  std::vector<VarScope *> scopes;\n\n  for (auto &c : cases) {\n    c.val->visit(this);\n    VarScope *caseScope = trunkScope->copy(arena);\n    currentScope = caseScope;\n    c.stmt->visit(this);\n    scopes.push_back(caseScope);\n  }\n\n  if (swtch->defaultCase().stmt) {\n    VarScope *defaultScope = trunkScope->copy(arena);\n    currentScope = defaultScope;\n    swtch->defaultCase().stmt->visit(this);\n    scopes.push_back(defaultScope);\n  }\n\n  for (VarScope *s : scopes) {\n    trunkScope->merge(s);\n    s->~VarScope();\n  }\n\n  currentScope = trunkScope;\n}\n\nvoid CheckerVisitor::visitTryStatement(TryStatement *tryStmt) {\n\n  Statement *t = tryStmt->tryStatement();\n  Id *id = tryStmt->exceptionId();\n  Statement *c = tryStmt->catchStatement();\n\n  VarScope *trunkScope = currentScope;\n  VarScope *tryScope = trunkScope->copy(arena);\n  currentScope = tryScope;\n  t->visit(this);\n\n  VarScope *copyScope = trunkScope->copy(arena);\n  VarScope catchScope(copyScope->owner, copyScope);\n  currentScope = &catchScope;\n  SymbolInfo *info = makeSymbolInfo(SK_EXCEPTION);\n  ValueRef *v = makeValueRef(info);\n  v->state = VRS_UNKNOWN;\n  v->expression = nullptr;\n  info->declarator.x = id;\n  info->ownedScope = &catchScope; //-V506\n\n  declareSymbol(id->name(), v);\n\n  id->visit(this);\n  c->visit(this);\n\n  tryScope->merge(copyScope);\n  trunkScope->copyFrom(tryScope);\n\n  tryScope->~VarScope();\n  currentScope = trunkScope;\n}\n\nconst char *CheckerVisitor::findSlotNameInStack(const Node *decl) {\n  auto it = nodeStack.rbegin();\n  auto ie = nodeStack.rend();\n\n  while (it != ie) {\n    auto slot = *it;\n    if (slot.sst == SST_NODE) {\n      const Node *n = slot.n;\n      if (n->op() == TO_NEWSLOT) {\n        const BinExpr *bin = static_cast<const BinExpr *>(n);\n        Expr *lhs = bin->lhs();\n        Expr *rhs = bin->rhs();\n        if (rhs == decl) {\n          if (lhs->op() == TO_LITERAL) {\n            if (lhs->asLiteral()->kind() == LK_STRING) {\n              return lhs->asLiteral()->s();\n            }\n          }\n          return nullptr;\n        }\n      }\n    }\n    else {\n      assert(slot.sst == SST_TABLE_MEMBER);\n      Expr *lhs = slot.member->key;\n      Expr *rhs = slot.member->value;\n      if (rhs == decl) {\n        if (lhs->op() == TO_LITERAL) {\n            if (lhs->asLiteral()->kind() == LK_STRING) {\n              return lhs->asLiteral()->s();\n            }\n          }\n        return nullptr;\n      }\n    }\n    ++it;\n  }\n\n  return nullptr;\n}\n\nvoid CheckerVisitor::checkFunctionReturns(FunctionExpr *func) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const char *name = func->name();\n\n  if (!name || name[0] == '(') {\n    name = findSlotNameInStack(func);\n  }\n\n  bool dummy;\n  unsigned returnFlags = FunctionReturnTypeEvaluator(this).compute(func->body(), dummy);\n\n  bool reported = false;\n\n  if (returnFlags & ~(RT_BOOL | RT_UNRECOGNIZED | RT_FUNCTION_CALL | RT_NULL)) { // Null is castable to boolean\n    if (nameLooksLikeResultMustBeBoolean(name)) {\n      Node *reportNode = func->nameId();\n      if (!reportNode) // just for safety\n        reportNode = func;\n      report(reportNode, DiagnosticsId::DI_NAME_RET_BOOL, name);\n      reported = true;\n    }\n  }\n\n  if (!!(returnFlags & RT_NOTHING) &&\n    !!(returnFlags & (RT_NUMBER | RT_STRING | RT_TABLE | RT_CLASS | RT_ARRAY | RT_CLOSURE | RT_UNRECOGNIZED | RT_THROW)))\n  {\n    if ((returnFlags & RT_THROW) == 0)\n      report(func, DiagnosticsId::DI_NOT_ALL_PATH_RETURN_VALUE);\n    reported = true;\n  }\n  else if (returnFlags)\n  {\n    unsigned flagsDiff = returnFlags & ~(RT_THROW | RT_NOTHING | RT_NULL | RT_UNRECOGNIZED | RT_FUNCTION_CALL);\n    if (flagsDiff)\n    {\n      bool powerOfTwo = !(flagsDiff & (flagsDiff - 1));\n      if (!powerOfTwo)\n      {\n        report(func, DiagnosticsId::DI_RETURNS_DIFFERENT_TYPES);\n        reported = true;\n      }\n    }\n  }\n\n  if (!reported) {\n    if (!!(returnFlags & RT_NOTHING) && nameLooksLikeFunctionMustReturnResult(name)) {\n      report(func, DiagnosticsId::DI_NAME_EXPECTS_RETURN, name);\n    }\n  }\n}\n\n\nvoid CheckerVisitor::checkAccessNullable(const DestructuringDecl *dd) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *i = dd->initExpression();\n  const Expr *initializer = i;\n\n  if (isPotentiallyNullable(initializer)) {\n    bool allHasDefault = true;\n\n    for (auto d : dd->declarations()) {\n      if (d->initializer() == nullptr) {\n        allHasDefault = false;\n        break;\n      }\n    }\n\n    if (!allHasDefault) {\n      report(dd, DiagnosticsId::DI_ACCESS_POT_NULLABLE, i->op() == TO_ID ? i->asId()->name() : \"expression\", \"container\");\n    }\n  }\n}\n\nvoid CheckerVisitor::checkAccessNullable(const AccessExpr *acc) {\n  if (isEffectsGatheringPass)\n    return;\n\n  const Expr *r = acc->receiver();\n\n  if (!isSafeAccess(acc) && isPotentiallyNullable(r)) {\n    report(r, DiagnosticsId::DI_ACCESS_POT_NULLABLE, \"expression\", \"container\");\n  }\n}\n\nvoid CheckerVisitor::checkEnumConstUsage(const GetFieldExpr *acc) {\n  if (isEffectsGatheringPass)\n    return;\n\n  char buffer[64] = { 0 };\n  const char *receiverName = computeNameRef(acc->receiver(), buffer, sizeof buffer);\n\n  if (!receiverName)\n    return;\n\n  const ValueRef *enumV = findValueInScopes(receiverName);\n  if (!enumV || enumV->info->kind != SK_ENUM)\n    return;\n\n  const char *fqn = enumFqn(arena, receiverName, acc->fieldName());\n  const ValueRef *constV = findValueInScopes(fqn);\n\n  if (!constV) {\n    // very suspicious\n    return;\n  }\n\n  constV->info->used = true;\n}\n\nvoid CheckerVisitor::visitTableExpr(TableExpr *table) {\n  checkFunctionSimilarity(table);\n\n  for (auto &member : table->members()) {\n    StackSlot slot;\n    slot.sst = SST_TABLE_MEMBER;\n    slot.member = &member;\n\n    checkKeyNameMismatch(member.key, member.value);\n\n    nodeStack.push_back(slot);\n    member.key->visit(this);\n    member.value->visit(this);\n    nodeStack.pop_back();\n  }\n}\n\nvoid CheckerVisitor::visitClassExpr(ClassExpr *klass) {\n  nodeStack.push_back({ SST_NODE, klass });\n\n  if (klass->classKey())\n    klass->classKey()->visit(this);\n\n  if (klass->classBase())\n    klass->classBase()->visit(this);\n\n  visitTableExpr(klass);\n\n  nodeStack.pop_back();\n}\n\nvoid CheckerVisitor::visitFunctionExpr(FunctionExpr *func) {\n  VarScope *parentScope = currentScope;\n  VarScope *copyScope = parentScope->copy(arena, true);\n  VarScope functionScope(func, copyScope);\n\n  SymbolInfo *info = makeSymbolInfo(SK_FUNCTION);\n  ValueRef *v = makeValueRef(info);\n  v->state = VRS_DECLARED;\n  v->expression = nullptr;\n  info->declarator.f = func;\n  info->ownedScope = currentScope;\n  info->used = true;\n\n  declareSymbol(func->name(), v);\n\n  pushFunctionScope(&functionScope, func);\n\n  FunctionInfo *oldInfo = currentInfo;\n  FunctionInfo *newInfo = functionInfoMap[func];\n\n  currentInfo = newInfo;\n  assert(newInfo);\n\n  checkFunctionReturns(func);\n\n  Visitor::visitFunctionExpr(func);\n\n  if (oldInfo) {\n    oldInfo->joinModifiable(newInfo);\n  }\n\n  functionScope.checkUnusedSymbols(this);\n\n  currentInfo = oldInfo;\n  currentScope = parentScope;\n}\n\nValueRef *CheckerVisitor::findValueInScopes(const char *ref) {\n  if (!ref)\n    return nullptr;\n\n  VarScope *current = currentScope;\n  VarScope *s = current;\n\n  while (s) {\n    auto &symbols = s->symbols;\n    auto it = symbols.find(ref);\n    if (it != symbols.end()) {\n      return it->second;\n    }\n\n    s = s->parent;\n  }\n\n  return nullptr;\n}\n\nvoid CheckerVisitor::applyAssignmentToScope(const BinExpr *bin) {\n  assert(bin->op() == TO_ASSIGN);\n\n  const Expr *lhs = bin->lhs();\n  const Expr *rhs = bin->rhs();\n\n  if (lhs->op() != TO_ID)\n    return;\n\n  const char *name = lhs->asId()->name();\n  ValueRef *v = findValueInScopes(name);\n\n  if (!v) {\n    // TODO: what if declarator == null\n    SymbolInfo *info = makeSymbolInfo(SK_VAR);\n    v = makeValueRef(info);\n    currentScope->symbols[name] = v;\n    info->ownedScope = currentScope;\n    info->declarator.v = nullptr;\n    if (currentInfo) {\n      currentInfo->addModifiable(name, info->ownedScope->owner);\n    }\n  }\n\n  v->expression = rhs;\n  v->state = VRS_EXPRESSION;\n  v->flagsNegative = v->flagsPositive = 0;\n  v->assigned = true;\n  v->lastAssigneeScope = currentScope;\n  v->evalIndex = currentScope->evalId;\n\n  if (isPotentiallyNullable(rhs)) {\n    v->flagsPositive |= RT_NULL;\n  }\n\n}\n\nvoid CheckerVisitor::applyAssignEqToScope(const BinExpr *bin) {\n  assert(TO_PLUSEQ <= bin->op() && bin->op() <= TO_MODEQ);\n\n  const Expr *lhs = bin->lhs();\n  const char *name = computeNameRef(lhs, nullptr, 0);\n  if (!name)\n    return;\n\n  ValueRef *v = findValueInScopes(name);\n\n  if (v) {\n    if (currentInfo) {\n      currentInfo->addModifiable(name, v->info->ownedScope->owner);\n    }\n    v->kill();\n    v->evalIndex = currentScope->evalId;\n  }\n}\n\nvoid CheckerVisitor::applyBinaryToScope(const BinExpr *bin) {\n  switch (bin->op())\n  {\n  case TO_ASSIGN:\n    return applyAssignmentToScope(bin);\n  case TO_PLUSEQ:\n  case TO_MINUSEQ:\n  case TO_MULEQ:\n  case TO_DIVEQ:\n  case TO_MODEQ:\n    return applyAssignEqToScope(bin);\n  default:\n    break;\n  }\n}\n\nstatic const char double_colon_str[] = \"::\";\nstatic const char base_str[] = \"base\";\n\nint32_t CheckerVisitor::computeNameLength(const Expr *e) {\n  switch (e->op()) // -V522\n  {\n  case TO_GETFIELD: return computeNameLength(e->asGetField());\n  //case TO_GETSLOT: return computeNameLength(e->asGetSlot());\n  case TO_ID: return strlen(e->asId()->name());\n  case TO_ROOT_TABLE_ACCESS: return strlen(double_colon_str);\n  case TO_BASE: return strlen(base_str);\n  default:\n    return -1;\n  }\n}\n\nvoid CheckerVisitor::computeNameRef(const Expr *e, char *b, int32_t &ptr, int32_t size) {\n  switch (e->op())\n  {\n  case TO_GETFIELD: return computeNameRef(e->asGetField(), b, ptr, size);\n  //case TO_GETSLOT: return computeNameRef(lhs->asGetSlot());\n  case TO_ID: {\n    int32_t l = snprintf(&b[ptr], size - ptr, \"%s\", e->asId()->name());\n    ptr += l;\n    break;\n  }\n  case TO_ROOT_TABLE_ACCESS:\n    snprintf(&b[ptr], size - ptr, \"%s\", double_colon_str);\n    ptr += strlen(double_colon_str);\n    break;\n  case TO_BASE:\n    snprintf(&b[ptr], size - ptr, \"%s\", base_str);\n    ptr += strlen(base_str);\n    break;\n  default:\n    assert(0);\n  }\n}\n\nconst char *CheckerVisitor::computeNameRef(const Expr *lhs, char *buffer, size_t bufferSize) {\n  int32_t length = computeNameLength(lhs);\n  if (length < 0)\n    return nullptr;\n\n  char *result = buffer;\n\n  if (!result || bufferSize < (length + 1)) {\n    result = (char *)arena->allocate(length + 1);\n  }\n\n  int32_t ptr = 0;\n  computeNameRef(lhs, result, ptr, length + 1);\n  assert(ptr == length);\n  return result;\n}\n\nvoid CheckerVisitor::setValueFlags(const Expr *lvalue, unsigned pf, unsigned nf) {\n\n  char buffer[128] = { 0 };\n\n  const char *name = computeNameRef(lvalue, buffer, sizeof buffer);\n\n  if (!name)\n    return;\n\n  ValueRef *v = findValueInScopes(name);\n\n  if (v) {\n    v->flagsPositive |= pf;\n    v->flagsPositive &= ~nf;\n    v->flagsNegative |= nf;\n    v->flagsNegative &= ~pf;\n  }\n}\n\nconst ValueRef *CheckerVisitor::findValueForExpr(const Expr *e) {\n  e = deparenStatic(e);\n  if (!e) return nullptr;\n\n  if (auto it = astValues.find(e); it != astValues.end())\n    return it->second;\n\n  char buffer[128] = { 0 };\n\n  const char *n = computeNameRef(e, buffer, sizeof buffer);\n\n  if (!n) {\n    return nullptr;\n  }\n\n  return findValueInScopes(n);\n}\n\nbool CheckerVisitor::isSafeAccess(const AccessExpr *acc) {\n  if (acc->isNullable())\n    return true;\n\n  const Expr *recevier = acc->receiver();\n\n  if (recevier->isAccessExpr()) {\n    return isSafeAccess(recevier->asAccessExpr());\n  }\n\n  return false;\n}\n\nbool CheckerVisitor::isPotentiallyNullable(const Expr *e) {\n  std::unordered_set<const Expr *> v;\n\n  return isPotentiallyNullable(e, v);\n}\n\nbool CheckerVisitor::isPotentiallyNullable(const Expr *e, std::unordered_set<const Expr *> &visited) {\n\n  e = deparenStatic(e);\n\n  auto existed = visited.find(e);\n  if (existed != visited.end()) {\n    return false;\n  }\n\n  visited.emplace(e);\n\n  const ValueRef *v = findValueForExpr(e);\n\n  if (v) {\n    if (v->flagsPositive & RT_NULL)\n      return true;\n\n    if (v->flagsNegative & RT_NULL)\n      return false;\n\n    // Check aliased source variable's current flags if it wasn't reassigned.\n    // This handles: let y = x; if (!x) return; y.field\n    // (y is non-null via x)\n    if (v->origin && v->origin->evalIndex == v->originEvalIndex) {\n      if (v->origin->flagsNegative & RT_NULL)\n        return false;\n    }\n  }\n\n  e = maybeEval(e);\n\n  if (e->op() == TO_LITERAL) {\n    const LiteralExpr *l = e->asLiteral();\n    return l->kind() == LK_NULL;\n  }\n\n  if (e->isAccessExpr()) {\n    if (e->asAccessExpr()->isNullable()) {\n      return true;\n    }\n  }\n\n  if (e->op() == TO_CALL) {\n    const CallExpr *call = static_cast<const CallExpr *>(e);\n    if (call->isNullable()) {\n      return true;\n    }\n\n    const char *funcName = nullptr;\n    const Expr *callee = call->callee();\n\n    if (callee->op() == TO_ID) {\n      funcName = callee->asId()->name();\n    }\n    else if (callee->op() == TO_GETFIELD) {\n      funcName = callee->asGetField()->fieldName();\n    }\n\n    if (funcName) {\n      if (canFunctionReturnNull(funcName)) {\n        return true;\n      }\n    }\n  }\n\n  if (e->op() == TO_NULLC) {\n    return isPotentiallyNullable(static_cast<const BinExpr *>(e)->rhs(), visited);\n  }\n\n  if (e->op() == TO_TERNARY) {\n    const TerExpr *t = static_cast<const TerExpr *>(e);\n    return isPotentiallyNullable(t->b(), visited) || isPotentiallyNullable(t->c(), visited);\n  }\n\n  v = findValueForExpr(e);\n\n  if (v) {\n    switch (v->state)\n    {\n    case VRS_EXPRESSION:\n    case VRS_INITIALIZED:\n      return isPotentiallyNullable(v->expression, visited);\n    default:\n      return false;\n    }\n  }\n\n  return false;\n}\n\nbool CheckerVisitor::couldBeString(const Expr *e) {\n  if (!e)\n    return false;\n\n  e = deparenStatic(e);\n\n  if (e->op() == TO_LITERAL) { // -V522\n    return e->asLiteral()->kind() == LK_STRING;\n  }\n\n  if (e->op() == TO_NULLC) {\n    const BinExpr *b = static_cast<const BinExpr *>(e);\n    if (b->rhs()->op() == TO_LITERAL && b->rhs()->asLiteral()->kind() == LK_STRING) // -V522\n      return couldBeString(b->lhs());\n  }\n\n  if (e->op() == TO_CALL) { // -V522\n    const char *name = nullptr;\n    const Expr *callee = static_cast<const CallExpr *>(e)->callee();\n\n    if (callee->op() == TO_ID)\n      name = callee->asId()->name();\n    else if (callee->op() == TO_GETFIELD)\n      name = callee->asGetField()->fieldName();\n\n    if (name) {\n      return nameLooksLikeResultMustBeString(name) || strcmp(name, \"loc\") == 0;\n    }\n  }\n\n  if (e->op() == TO_ADD) { // -V522\n    // check for string concat\n    const BinExpr *b = e->asBinExpr();\n    return couldBeString(b->lhs()) || couldBeString(b->rhs());\n  }\n\n  const Expr *evaled = maybeEval(e);\n\n  if (evaled != e && evaled->op() == TO_LITERAL) // do not go too deep\n    return couldBeString(evaled);\n\n  return false;\n}\n\nconst Expr *CheckerVisitor::maybeEval(const Expr *e, bool allow_external) {\n  int32_t dummy = -1;\n  return maybeEval(e, dummy, allow_external);\n}\n\nconst Expr *CheckerVisitor::maybeEval(const Expr *e, int32_t &evalId, bool allow_external) {\n  std::unordered_set<const Expr *> visited;\n  return maybeEval(e, evalId, visited, allow_external);\n}\n\nconst Expr *CheckerVisitor::maybeEval(const Expr *e, int32_t &evalId, std::unordered_set<const Expr *> &visited, bool allow_external) {\n\n  if (visited.find(e) != visited.end())\n    return e;\n\n  visited.emplace(e);\n\n  e = deparenStatic(e);\n  const ValueRef *v = findValueForExpr(e);\n\n  if (!v) {\n    return e;\n  }\n\n  evalId = v->evalIndex;\n  if (v->hasValue()) {\n    if (!allow_external && v->expression && v->expression->op() == TO_EXTERNAL_VALUE)\n      return e;\n    // If this variable was initialized from another variable (aliased) and that source\n    // variable has been reassigned since, stop evaluating the expression chain.\n    // Example: let a = null; let b = a; a = 123; return b ?? 2\n    if (v->origin && v->expression && v->expression->op() == TO_ID) {\n      if (v->origin->evalIndex != v->originEvalIndex) {\n        return e;\n      }\n    }\n    return maybeEval(v->expression, evalId, visited, allow_external);\n  }\n  else {\n    return e;\n  }\n}\n\nconst char *CheckerVisitor::findFieldName(const Expr *e) {\n  if (e->op() == TO_ID)\n    return e->asId()->name();\n\n  if (e->op() == TO_GETFIELD)\n    return e->asGetField()->fieldName();\n\n  if (e->op() == TO_CALL)\n    return findFieldName(e->asCallExpr()->callee());\n\n  const ValueRef *v = findValueForExpr(e);\n\n  if (v && v->expression && v->expression->op() == TO_FUNCTION) {\n    return v->expression->asFunctionExpr()->name();\n  }\n\n  return \"\";\n}\n\nint32_t CheckerVisitor::computeNameLength(const GetFieldExpr *acc) {\n  int32_t size = computeNameLength(acc->receiver());\n\n  if (size < 0) {\n    return size;\n  }\n\n  size += 1;\n  size += strlen(acc->fieldName());\n  return size;\n}\n\nvoid CheckerVisitor::computeNameRef(const GetFieldExpr *access, char *b, int32_t &ptr, int32_t size) {\n  computeNameRef(access->receiver(), b, ptr, size);\n  b[ptr++] = '.';\n  int32_t l = snprintf(&b[ptr], size - ptr, \"%s\", access->fieldName());\n  ptr += l;\n}\n\nconst ExternalValueExpr *CheckerVisitor::findExternalValue(const Expr *e) {\n  const Expr *ee = maybeEval(e, true);\n\n  if (ee->op() == TO_EXTERNAL_VALUE)\n    return static_cast<const ExternalValueExpr *>(ee);\n\n  char buffer[128] = { 0 };\n  const char *name = computeNameRef(ee, buffer, sizeof buffer);\n  if (!name)\n    return nullptr;\n\n  const ValueRef *v = findValueInScopes(name);\n\n  if (!v || !v->hasValue())\n    return nullptr;\n\n  const Expr *expr = maybeEval(v->expression, true);\n\n  if (expr->op() == TO_EXTERNAL_VALUE)\n    return static_cast<const ExternalValueExpr *>(expr);\n\n  return nullptr;\n}\n\n\nconst FunctionInfo *CheckerVisitor::findFunctionInfo(const Expr *e, bool &isCtor) {\n  const Expr *ee = maybeEval(e);\n\n  if (ee->op() == TO_FUNCTION) {\n    return functionInfoMap[ee->asFunctionExpr()];\n  }\n\n  char buffer[128] = { 0 };\n\n  const char *name = computeNameRef(ee, buffer, sizeof buffer);\n\n  if (!name)\n    return nullptr;\n\n  const ValueRef *v = findValueInScopes(name);\n\n  if (!v || !v->hasValue())\n    return nullptr;\n\n  const Expr *expr = maybeEval(v->expression);\n\n  if (expr->op() == TO_FUNCTION) {\n    return functionInfoMap[expr->asFunctionExpr()];\n  }\n  else if (expr->op() == TO_CLASS) {\n    const ClassExpr *klass = expr->asClassExpr();\n    isCtor = true;\n    if (FunctionExpr *ctor = klass->findConstructor())\n      return functionInfoMap[ctor];\n  }\n\n  return nullptr;\n}\n\nvoid CheckerVisitor::applyKnownInvocationToScope(const ValueRef *value) {\n  const FunctionInfo *info = nullptr;\n\n  if (value->hasValue()) {\n    const Expr *expr = maybeEval(value->expression);\n    assert(expr != nullptr);\n\n    if (expr->op() == TO_FUNCTION) {\n      info = functionInfoMap[expr->asFunctionExpr()];\n    }\n    else if (expr->op() == TO_CLASS) {\n      const ClassExpr *klass = expr->asClassExpr();\n      if (FunctionExpr *ctor = klass->findConstructor())\n        info = functionInfoMap[ctor];\n    }\n    else if (expr->op() == TO_TABLE) {\n      // Tables don't have function info\n    }\n    else if (expr->op() == TO_EXTERNAL_VALUE) {\n      applyUnknownInvocationToScope();\n      return;\n    }\n  }\n\n  if (!info) {\n    // probably it is class constructor\n    return;\n  }\n\n  for (auto s : info->modifiable) {\n    VarScope *scope = currentScope->findScope(s.owner);\n    if (!scope)\n      continue;\n\n    auto it = scope->symbols.find(s.name);\n    if (it != scope->symbols.end()) {\n      if (it->second->isConstant())\n        continue;\n\n      if (currentInfo) {\n        currentInfo->addModifiable(it->first, it->second->info->ownedScope->owner);\n      }\n      it->second->kill();\n    }\n  }\n}\n\nvoid CheckerVisitor::applyUnknownInvocationToScope() {\n  VarScope *s = currentScope;\n\n  while (s) {\n    auto &symbols = s->symbols;\n    for (auto &sym : symbols) {\n      if (sym.second->isConstant())\n        continue;\n      if (currentInfo) {\n        currentInfo->addModifiable(sym.first, sym.second->info->ownedScope->owner);\n      }\n      sym.second->kill();\n    }\n    s = s->parent;\n  }\n}\n\nvoid CheckerVisitor::applyCallToScope(const CallExpr *call) {\n  const Expr *callee = deparenStatic(call->callee());\n\n  if (callee->op() == TO_ID) { // -V522\n    const Id *calleeId = callee->asId();\n    //const NameRef ref(nullptr, calleeId->name());\n    const ValueRef *value = findValueInScopes(calleeId->name());\n    if (value) {\n      applyKnownInvocationToScope(value);\n    }\n    else {\n      // unknown invocation by pure Id points to some external\n      // function which could not modify any scoped value\n    }\n  }\n  else if (callee->op() == TO_GETFIELD) {\n    char buffer[128] = { 0 };\n    const char *ref = computeNameRef(callee, buffer, sizeof buffer);\n    const ValueRef *value = findValueInScopes(ref);\n    if (value) {\n      applyKnownInvocationToScope(value);\n    }\n    else if (!ref || strcmp(ref, double_colon_str) != 0) {\n      // we don't know what exactly is being called so assume the most conservative case\n      applyUnknownInvocationToScope();\n    }\n  }\n  else {\n    // unknown invocation so everything could be modified\n    applyUnknownInvocationToScope();\n  }\n}\n\nvoid CheckerVisitor::pushFunctionScope(VarScope *functionScope, const FunctionExpr *decl) {\n\n  FunctionInfo *info = functionInfoMap[decl];\n\n  if (!info) {\n    info = makeFunctionInfo(decl, currentScope->owner);\n    functionInfoMap[decl] = info;\n  }\n\n  currentScope = functionScope;\n}\n\nvoid CheckerVisitor::declareSymbol(const char *nameRef, ValueRef *v) {\n  currentScope->symbols[nameRef] = v;\n}\n\nvoid CheckerVisitor::visitParamDecl(ParamDecl *p) {\n  Visitor::visitParamDecl(p);\n\n  const Expr *dv = p->defaultValue();\n\n  SymbolInfo *info = makeSymbolInfo(SK_PARAM);\n  ValueRef *v = makeValueRef(info);\n  v->state = VRS_UNKNOWN;\n  v->expression = nullptr;\n  info->declarator.p = p;\n  info->ownedScope = currentScope;\n  info->used = p->isVararg();\n\n  if (dv && dv->op() == TO_LITERAL) {\n    if (dv->asLiteral()->kind() == LK_NULL) {\n      v->flagsPositive |= RT_NULL;\n    }\n  }\n\n  declareSymbol(p->name(), v);\n\n  assert(currentInfo);\n  if (!isEffectsGatheringPass)\n    currentInfo->parameters.push_back(normalizeParamName(p->name()));\n}\n\nvoid CheckerVisitor::visitVarDecl(VarDecl *decl) {\n  Visitor::visitVarDecl(decl);\n\n  SymbolInfo *info = makeSymbolInfo(decl->isAssignable() ? SK_VAR : SK_BINDING);\n  ValueRef *v = makeValueRef(info);\n  const Expr *init = decl->initializer();\n  const Expr *origInit = deparenStatic(init);\n  init = maybeEval(init, true);\n  if (decl->isDestructured()) {\n    v->state = VRS_UNKNOWN;\n    v->expression = nullptr;\n  }\n  else {\n    v->state = VRS_INITIALIZED;\n    if (init) {\n      v->expression = init;\n    }\n    else {\n      v->expression = &nullValue;\n      v->flagsPositive |= RT_NULL;\n    }\n  }\n\n  if (init) {\n    if (init->op() == TO_LITERAL) {\n      if (init->asLiteral()->kind() == LK_NULL) {\n        v->flagsPositive |= RT_NULL;\n      }\n    }\n  }\n\n  // Track aliasing: if initialized from a variable, store reference for dynamic flag lookup.\n  // This allows checking the source's current flags even if they change after this declaration.\n  if (origInit && origInit->op() == TO_ID) {\n    const ValueRef *vr = findValueForExpr(origInit);\n    if (vr) {\n      v->flagsPositive = vr->flagsPositive;\n      v->flagsNegative = vr->flagsNegative;\n      v->origin = vr;\n      v->originEvalIndex = vr->evalIndex;\n    }\n  }\n\n  info->declarator.v = decl;\n  info->ownedScope = currentScope;\n\n  declareSymbol(decl->name(), v);\n  astValues[decl] = v;\n}\n\nvoid CheckerVisitor::visitConstDecl(ConstDecl *cnst) {\n\n  if (cnst->isGlobal()) {\n    storeGlobalDeclaration(cnst->name(), cnst);\n  }\n\n  SymbolInfo *info = makeSymbolInfo(SK_CONST);\n  ValueRef *v = makeValueRef(info);\n  v->state = VRS_INITIALIZED;\n  v->expression = cnst->value();\n  info->declarator.c = cnst;\n  info->ownedScope = currentScope;\n  info->used = cnst->isGlobal();\n\n  declareSymbol(cnst->name(), v);\n\n  Visitor::visitConstDecl(cnst);\n}\n\nvoid CheckerVisitor::visitEnumDecl(EnumDecl *enm) {\n\n  if (enm->isGlobal()) {\n    storeGlobalDeclaration(enm->name(), enm);\n  }\n\n  SymbolInfo *info = makeSymbolInfo(SK_ENUM);\n  ValueRef *ev = makeValueRef(info);\n  ev->state = VRS_DECLARED;\n  ev->expression = nullptr;\n  info->declarator.e = enm;\n  info->ownedScope = currentScope;\n  info->used = enm->isGlobal();\n  declareSymbol(enm->name(), ev);\n\n  for (auto &c : enm->consts()) {\n    SymbolInfo *constInfo = makeSymbolInfo(SK_ENUM_CONST);\n    ValueRef *cv = makeValueRef(constInfo);\n    cv->state = VRS_INITIALIZED;\n    cv->expression = c.val;\n    constInfo->declarator.ec = &c;\n    constInfo->ownedScope = currentScope;\n    constInfo->used = enm->isGlobal();\n\n    const char *fqn = enumFqn(arena, enm->name(), c.id);\n    declareSymbol(fqn, cv);\n\n    c.val->visit(this);\n  }\n}\n\nvoid CheckerVisitor::checkDestructuredVarDefault(VarDecl *var) {\n  const Expr *def = var->initializer();\n  def = maybeEval(def, true);\n  if (def) {\n    auto vv = astValues[var];\n    assert(vv);\n    vv->state = VRS_INITIALIZED;\n    vv->expression = def;\n  }\n  else {\n    report(var, DiagnosticsId::DI_MISSING_DESTRUCTURED_VALUE, var->name());\n  }\n}\n\nvoid CheckerVisitor::visitDestructuringDecl(DestructuringDecl *d) {\n\n  checkAccessNullable(d);\n\n  Visitor::visitDestructuringDecl(d);\n\n  if (auto v = findValueForExpr(d->initExpression()); v && v->hasValue() && v->expression) {\n    if (v->expression->op() == TO_EXTERNAL_VALUE) {\n      const auto &init = v->expression->asExternal()->value();\n      if (sq_isnull(init)) {\n        for (auto var : d->declarations()) {\n          checkDestructuredVarDefault(var);\n        }\n      }\n      else if (sq_istable(init)) {\n        if (d->type() == DT_TABLE) {\n          auto table = _table(init);\n          for (auto var : d->declarations()) {\n            SQObjectPtr val;\n            if (table->GetStr(var->name(), strlen(var->name()), val)) {\n              auto vv = astValues[var];\n              assert(vv);\n              vv->state = VRS_INITIALIZED;\n              vv->expression = addExternalValue(val, var)->expression;\n            }\n            else {\n              checkDestructuredVarDefault(var);\n            }\n          }\n        }\n        else {\n          report(d, DiagnosticsId::DI_DESTRUCTURED_TYPE_MISMATCH, \"table\");\n        }\n      }\n      else if (sq_isclass(init)) {\n        if (d->type() == DT_TABLE) {\n          auto klass = _class(init);\n          for (auto var : d->declarations()) {\n            SQObjectPtr key(_ctx.getVm(), var->name());\n            SQObjectPtr val;\n            if (klass->Get(key, val)) {\n              auto vv = astValues[var];\n              assert(vv);\n              vv->state = VRS_INITIALIZED;\n              vv->expression = addExternalValue(val, var)->expression;\n            }\n            else {\n              checkDestructuredVarDefault(var);\n            }\n          }\n        }\n        else {\n          report(d, DiagnosticsId::DI_DESTRUCTURED_TYPE_MISMATCH, \"class\");\n        }\n      }\n      else if (sq_isinstance(init)) {\n        if (d->type() == DT_TABLE) {\n          auto inst = _instance(init);\n          for (auto var : d->declarations()) {\n            SQObjectPtr key(_ctx.getVm(), var->name());\n            SQObjectPtr val;\n            if (inst->Get(key, val)) {\n              auto vv = astValues[var];\n              assert(vv);\n              vv->state = VRS_INITIALIZED;\n              vv->expression = addExternalValue(val, var)->expression;\n            }\n            else {\n              checkDestructuredVarDefault(var);\n            }\n          }\n        }\n        else {\n          report(d, DiagnosticsId::DI_DESTRUCTURED_TYPE_MISMATCH, \"instance\");\n        }\n      }\n      else if (sq_isarray(init)) {\n        if (d->type() == DT_ARRAY) {\n          auto array = _array(init);\n          SQInteger index = 0;\n          for (auto var : d->declarations()) {\n            SQObjectPtr val;\n            if (array->Get(index, val)) {\n              auto vv = astValues[var];\n              assert(vv);\n              vv->state = VRS_INITIALIZED;\n              vv->expression = addExternalValue(val, var)->expression;\n            }\n            else {\n              checkDestructuredVarDefault(var);\n            }\n            index++;\n          }\n        }\n        else {\n          report(d, DiagnosticsId::DI_DESTRUCTURED_TYPE_MISMATCH, \"array\");\n        }\n      }\n      else {\n        report(d, DiagnosticsId::DI_DESTRUCTURED_TYPE_MISMATCH, GetTypeName(init));\n      }\n    }\n    else if (v->expression->op() == TO_TABLE) {\n      // TODO: check table destructuring\n    }\n    else if (v->expression->op() == TO_ARRAY) {\n      // TODO: check array destructuring\n    }\n  }\n}\n\nvoid CheckerVisitor::visitImportStatement(ImportStmt *import) {\n  if (import->slots.empty()) {\n    // Handle whole-module imports\n    ImportInfo *importInfo = (ImportInfo *)arena->allocate(sizeof(ImportInfo));\n    importInfo->line = import->lineStart();\n    importInfo->column = import->moduleAlias ? import->aliasCol : import->nameCol;\n    importInfo->name = import->moduleAlias ? import->moduleAlias : import->moduleName;\n\n    // Find an external value auto-collected from bindings in analyze()\n    ValueRef *existing = findValueInScopes(importInfo->name);\n    assert(existing);\n\n    SymbolInfo *info = makeSymbolInfo(SK_IMPORT);\n    ValueRef *v = makeValueRef(info);\n    v->state = VRS_INITIALIZED;\n    v->expression = existing->expression; //-V522\n    info->declarator.imp = importInfo;\n    info->ownedScope = currentScope;\n\n    // Warning! This redeclares symbol with the same name\n    // This is a temporary solution and will be fixed separately\n    declareSymbol(importInfo->name, v);\n  }\n  else {\n    for (const SQModuleImportSlot &slot : import->slots) {\n      if (strcmp(slot.name, \"*\") == 0)\n        continue;\n\n      ImportInfo *importInfo = (ImportInfo *)arena->allocate(sizeof(ImportInfo));\n      importInfo->line = slot.line;\n      importInfo->column = slot.column;\n      importInfo->name = slot.alias ? slot.alias : slot.name;\n\n      // Find an external value auto-collected from bindings in analyze()\n      ValueRef *existing = findValueInScopes(importInfo->name);\n      assert(existing);\n\n      SymbolInfo *info = makeSymbolInfo(SK_IMPORT);\n      ValueRef *v = makeValueRef(info);\n      v->state = VRS_INITIALIZED;\n      v->expression = existing->expression; //-V522\n      info->declarator.imp = importInfo;\n      info->ownedScope = currentScope;\n\n      // Warning! This redeclares symbol with the same name\n      // This is a temporary solution and will be fixed separately\n      declareSymbol(importInfo->name, v);\n    }\n  }\n\n  Visitor::visitImportStatement(import);\n}\n\nValueRef* CheckerVisitor::addExternalValue(const SQObject &val, const Node *location) {\n  SymbolInfo *info = makeSymbolInfo(SK_EXTERNAL_BINDING);\n  ValueRef *v = makeValueRef(info);\n  // Create ExternalValueExpr with span from location (if provided) or invalid span\n  SourceSpan spanFromLoc = location ? location->sourceSpan() : SourceSpan::invalid();\n  ExternalValueExpr *ev = new(arena) ExternalValueExpr(val, spanFromLoc);\n  externalValues.push_back(ev);\n\n  info->declarator.ev = ev;\n  v->state = VRS_INITIALIZED;\n  v->expression = ev;\n  if (sq_isnull(val)) v->flagsPositive |= RT_NULL;\n  // TODO: could create LiteralExpr for some values\n\n  return v;\n}\n\nvoid CheckerVisitor::analyze(RootBlock *root, const HSQOBJECT *bindings) {\n  assert(currentScope == nullptr);\n  VarScope rootScope(nullptr, nullptr);\n  currentScope = &rootScope;\n\n  if (bindings && sq_istable(*bindings)) {\n    SQTable *table = _table(*bindings);\n\n    SQInteger idx = 0;\n    SQObjectPtr pos(idx), key, val;\n\n    while ((idx = table->Next(false, pos, key, val)) >= 0) {\n      if (sq_isstring(key)) {\n        const char *name = _string(key)->_val;\n        declareSymbol(name, addExternalValue(val, root));\n      }\n      pos._unVal.nInteger = idx;\n    }\n  }\n\n  root->visit(this);\n\n  rootScope.parent = nullptr;\n  currentScope = nullptr;\n}\n\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/checker_visitor.h",
    "content": "#pragma once\n\n#include \"compiler/compilationcontext.h\"\n#include \"node_equal_checker.h\"\n#include \"modification_checker.h\"\n#include \"ast_helpers.h\"\n#include \"function_info.h\"\n#include \"value_ref.h\"\n\n#include <unordered_set>\n\n\nnamespace SQCompilation\n{\n\nstruct VarScope;\nstruct BreakableScope;\n\n\nstruct IdLocation {\n  const char *filename;\n  int32_t line, column;\n  bool diagSilenced;\n};\n\n\nclass PredicateCheckerVisitor : public Visitor\n{\n  bool deepCheck;\n  bool result;\n  const Node *checkee;\n\nprotected:\n  NodeEqualChecker equalChecker;\n\n  PredicateCheckerVisitor(bool deep) : deepCheck(deep), result(false), checkee(nullptr) {}\n\n  virtual bool doCheck(const Node *checkee, Node *n) const = 0;\n\npublic:\n  void visitNode(Node *n) {\n    if (doCheck(checkee, n)) {\n      result = true;\n      return;\n    }\n\n    if (deepCheck)\n      n->visitChildren(this);\n  }\n\n  bool check(const Node *toCheck, Node *tree) {\n    result = false;\n    checkee = toCheck;\n    tree->visit(this); // -V522\n    return result;\n  }\n};\n\n\nclass CheckModificationVisitor : public PredicateCheckerVisitor\n{\nprotected:\n  bool doCheck(const Node *checkee, Node *n) const {\n    TreeOp op = n->op();\n\n    if (op == TO_ASSIGN || (TO_PLUSEQ <= op && op <= TO_MODEQ)) {\n      BinExpr *bin = static_cast<BinExpr *>(n);\n      return equalChecker.check(checkee, bin->lhs());\n    }\n\n    if (op == TO_INC) {\n      IncExpr *inc = static_cast<IncExpr *>(n);\n      return equalChecker.check(checkee, inc->argument());\n    }\n\n    return false;\n  }\npublic:\n  CheckModificationVisitor() : PredicateCheckerVisitor(false) {}\n};\n\n\nclass ExistsChecker : public PredicateCheckerVisitor\n{\nprotected:\n  bool doCheck(const Node *checkee, Node *n) const {\n    return equalChecker.check(checkee, n);\n  }\n\npublic:\n  ExistsChecker() : PredicateCheckerVisitor(true) {}\n};\n\n\nclass CheckerVisitor : public Visitor\n{\n  friend struct VarScope;\n  friend struct BreakableScope;\n  friend class FunctionReturnTypeEvaluator;\n\n  const int32_t functionComplexityThreshold = 45; // get threshold complexity from command line args\n  const int32_t statementComplexityThreshold = 23;\n  const int32_t statementSimilarityThreshold = 33;\n\n  SQCompilationContext &_ctx;\n\n  NodeEqualChecker _equalChecker;\n\n  void report(const Node *n, int32_t id, ...);\n  void reportImportSlot(int line, int column, const char *name);\n\n  void checkKeyNameMismatch(const Expr *key, const Expr *expr);\n\n  void checkAlwaysTrueOrFalse(const Expr *expr);\n\n  void checkIdUsed(const Id *id, const Node *p, ValueRef *v);\n\n  void reportIfCannotBeNull(const Expr *checkee, const Expr *n, const char *loc);\n  void reportModifyIfContainer(const Expr *e, const Expr *mod);\n  void checkForgotSubst(const LiteralExpr *l);\n  void checkContainerModification(const UnExpr *expr);\n  void checkAndOrPriority(const BinExpr *expr);\n  void checkBitwiseParenBool(const BinExpr *expr);\n  void checkNullCoalescingPriority(const BinExpr *expr);\n  void checkAssignmentToItself(const BinExpr *expr);\n  void checkSameOperands(const BinExpr *expr);\n  void checkAlwaysTrueOrFalse(const BinExpr *expr);\n  void checkDeclarationInArith(const BinExpr *expr);\n  void checkIntDivByZero(const BinExpr *expr);\n  void checkPotentiallyNullableOperands(const BinExpr *expr);\n  void checkBitwiseToBool(const BinExpr *expr);\n  void checkCompareWithBool(const BinExpr *expr);\n  void checkRelativeCompareWithBool(const BinExpr *expr);\n  void checkCopyOfExpression(const BinExpr *expr);\n  void checkConstInBoolExpr(const BinExpr *expr);\n  void checkShiftPriority(const BinExpr *expr);\n  void checkCompareWithContainer(const BinExpr *expr);\n  void checkBoolToStrangePosition(const BinExpr *expr);\n  void checkNewSlotNameMatch(const BinExpr *expr);\n  void checkPlusString(const BinExpr *expr);\n  void checkNewGlobalSlot(const BinExpr *);\n  void checkUselessNullC(const BinExpr *);\n  void checkCannotBeNull(const BinExpr *);\n  void checkCanBeSimplified(const BinExpr *expr);\n  void checkRangeCheck(const BinExpr *expr);\n  void checkParamAssignInLambda(const BinExpr *expr);\n  void checkAlwaysTrueOrFalse(const TerExpr *expr);\n  void checkTernaryPriority(const TerExpr *expr);\n  void checkSameValues(const TerExpr *expr);\n  void checkCanBeSimplified(const TerExpr *expr);\n  void checkExtendToAppend(const CallExpr *callExpr);\n  void checkMergeEmptyTable(const CallExpr *callExpr);\n  void checkEmptyArrayResize(const CallExpr *callExpr);\n  void checkAlreadyRequired(const CallExpr *callExpr);\n  void checkCallNullable(const CallExpr *callExpr);\n  void checkPersistCall(const CallExpr *callExpr);\n  void checkForbiddenCall(const CallExpr *callExpr);\n  void checkCallFromRoot(const CallExpr *callExpr);\n  void checkForbiddenParentDir(const CallExpr *callExpr);\n  void checkFormatArguments(const CallExpr *callExpr);\n  void checkArguments(const CallExpr *callExpr);\n  void checkContainerModification(const CallExpr *expr);\n  void checkUnwantedModification(const CallExpr *expr);\n  void checkCannotBeNull(const CallExpr *expr);\n  void checkBooleanLambda(const CallExpr *expr);\n  void checkCallbackReturnValue(const CallExpr *expr);\n  void checkCallbackShouldNotReturn(const CallExpr *expr);\n  void checkBoolIndex(const GetSlotExpr *expr);\n  void checkNullableIndex(const GetSlotExpr *expr);\n  void checkGlobalAccess(const GetFieldExpr *expr);\n  void checkAccessFromStatic(const GetFieldExpr *expr);\n  void checkExternalField(const GetFieldExpr *expr);\n\n  bool hasDynamicContent(const SQObject &container);\n\n  bool findIfWithTheSameCondition(const Expr * condition, const IfStatement * elseNode, const Expr *&duplicated) {\n    if (_equalChecker.check(condition, elseNode->condition())) {\n      duplicated = elseNode->condition();\n      return true;\n    }\n\n    const Statement *elseB = unwrapSingleBlock(elseNode->elseBranch());\n\n    if (elseB && elseB->op() == TO_IF) {\n      return findIfWithTheSameCondition(condition, static_cast<const IfStatement *>(elseB), duplicated);\n    }\n\n    return false;\n  }\n\n  const char *normalizeParamName(const char *name, char *buffer = nullptr);\n  int32_t normalizeParamNameLength(const char *n);\n\n  void checkDuplicateSwitchCases(SwitchStatement *swtch);\n  void checkDuplicateIfBranches(IfStatement *ifStmt);\n  void checkDuplicateIfConditions(IfStatement *ifStmt);\n  void checkSuspiciousFormatting(const Statement *body, const Statement *stmt);\n  void checkSuspiciousFormattingOfStetementSequence(const Statement* prev, const Statement* cur);\n\n  bool onlyEmptyStatements(int32_t start, const ArenaVector<Statement *> &statements) {\n    for (int32_t i = start; i < statements.size(); ++i) {\n      Statement *stmt = statements[i];\n      if (stmt->op() != TO_EMPTY)\n        return false;\n    }\n\n    return true;\n  }\n\n  bool existsInTree(const Expr *toSearch, Expr *tree) const {\n    return ExistsChecker().check(toSearch, tree);\n  }\n\n  bool indexChangedInTree(Expr *index) const {\n    return ModificationChecker().check(index);\n  }\n\n  bool checkModification(Expr *key, Node *tree) {\n    return CheckModificationVisitor().check(key, tree);\n  }\n\n  bool shouldCallResultBeUtilized(const char *name, const CallExpr *call);\n\n  void checkUnterminatedLoop(LoopStatement *loop);\n  void checkVariableMismatchForLoop(ForStatement *loop);\n  void checkEmptyWhileBody(WhileStatement *loop);\n  void checkEmptyThenBody(IfStatement *stmt);\n  void checkForgottenDo(const Block *block);\n  void checkUnreachableCode(const Block *block);\n  void checkAssignedTwice(const Block *b);\n\n  void checkFunctionSimilarity(const Block *b);\n  void checkFunctionSimilarity(const TableExpr *table);\n  void checkFunctionPairSimilarity(const FunctionExpr *f1, const FunctionExpr *f2);\n\n  void checkAssignExpressionSimilarity(const Block *b);\n  void checkUnutilizedResult(const ExprStatement *b);\n  void checkNullableContainer(const ForeachStatement *loop);\n  void checkMissedBreak(const SwitchStatement *swtch);\n\n  const char *findSlotNameInStack(const Node *);\n  void checkFunctionReturns(FunctionExpr *func);\n\n  void checkAccessNullable(const DestructuringDecl *d);\n  void checkAccessNullable(const AccessExpr *acc);\n  void checkEnumConstUsage(const GetFieldExpr *acc);\n\n  enum StackSlotType {\n    SST_NODE,\n    SST_TABLE_MEMBER\n  };\n\n  struct StackSlot {\n    StackSlotType sst;\n    union {\n      const Node *n;\n      const TableMember *member;\n    };\n  };\n\n  std::vector<StackSlot> nodeStack;\n\n  VarScope *currentScope;\n  BreakableScope *breakScope;\n\n  FunctionInfo *makeFunctionInfo(const FunctionExpr *d, const FunctionExpr *o) {\n    void *mem = arena->allocate(sizeof(FunctionInfo));\n    return new(mem) FunctionInfo(d, o);\n  }\n\n  ValueRef *makeValueRef(SymbolInfo *info) {\n    void *mem = arena->allocate(sizeof(ValueRef));\n    return new (mem) ValueRef(info, currentScope->evalId);\n  }\n\n  SymbolInfo *makeSymbolInfo(SymbolKind kind) {\n    void *mem = arena->allocate(sizeof(SymbolInfo));\n    return new (mem) SymbolInfo(kind);\n  }\n\n  std::unordered_map<const FunctionExpr *, FunctionInfo *> functionInfoMap;\n\n  std::unordered_set<const char *, StringHasher, StringEqualer> requiredModules;\n  std::unordered_set<const char *, StringHasher, StringEqualer> persistedKeys;\n\n  std::unordered_map<const Node *, ValueRef *> astValues;\n  std::vector<ExternalValueExpr *> externalValues;\n\n  Arena *arena;\n\n  FunctionInfo *currentInfo;\n\n  void declareSymbol(const char *name, ValueRef *v);\n  void pushFunctionScope(VarScope *functionScope, const FunctionExpr *decl);\n\n  void applyCallToScope(const CallExpr *call);\n  void applyBinaryToScope(const BinExpr *bin);\n  void applyAssignmentToScope(const BinExpr *bin);\n  void applyAssignEqToScope(const BinExpr *bin);\n\n  int32_t computeNameLength(const GetFieldExpr *access);\n  void computeNameRef(const GetFieldExpr *access, char *b, int32_t &ptr, int32_t size);\n  int32_t computeNameLength(const Expr *e);\n  void computeNameRef(const Expr *lhs, char *buffer, int32_t &ptr, int32_t size);\n  const char *computeNameRef(const Expr *lhs, char *buffer, size_t bufferSize);\n\n  ValueRef *findValueInScopes(const char *ref);\n  void applyKnownInvocationToScope(const ValueRef *ref);\n  void applyUnknownInvocationToScope();\n\n  const ExternalValueExpr *findExternalValue(const Expr *e);\n  const FunctionInfo *findFunctionInfo(const Expr *e, bool &isCtor);\n\n  void setValueFlags(const Expr *lvalue, unsigned pf, unsigned nf);\n  const ValueRef *findValueForExpr(const Expr *e);\n  const Expr *maybeEval(const Expr *e, int32_t &evalId, std::unordered_set<const Expr *> &visited, bool allow_external = false);\n  const Expr *maybeEval(const Expr *e, int32_t &evalId, bool allow_external = false);\n  const Expr *maybeEval(const Expr *e, bool allow_external = false);\n\n  const char *findFieldName(const Expr *e);\n\n  bool isSafeAccess(const AccessExpr *acc);\n  bool isPotentiallyNullable(const Expr *e);\n  bool isPotentiallyNullable(const Expr *e, std::unordered_set<const Expr *> &visited);\n  bool couldBeString(const Expr *e);\n\n  void visitBinaryBranches(Expr *lhs, Expr *rhs, bool inv);\n  void speculateIfConditionHeuristics(const Expr *cond, VarScope *thenScope, VarScope *elseScope, bool inv = false);\n  void speculateIfConditionHeuristics(const Expr *cond, VarScope *thenScope, VarScope *elseScope, std::unordered_set<const Expr *> &visited, int32_t evalId, unsigned flags, bool inv);\n  bool detectTypeOfPattern(const Expr *expr, const Expr *&r_checkee, const LiteralExpr *&r_lit);\n  bool detectNullCPattern(TreeOp op, const Expr *expr, const Expr *&checkee);\n\n  void checkAssertCall(const CallExpr *call);\n  const char *extractFunctionName(const CallExpr *call);\n\n  LiteralExpr trueValue, falseValue, nullValue;\n\n  bool isEffectsGatheringPass;\n\n  void putIntoGlobalNamesMap(std::unordered_map<std::string, std::vector<IdLocation>> &map, enum DiagnosticsId diag, const char *name, const Node *d);\n  void storeGlobalDeclaration(const char *name, const Node *d);\n  void storeGlobalUsage(const char *name, const Node *d);\n\npublic:\n\n  CheckerVisitor(SQCompilationContext &ctx)\n    : _ctx(ctx)\n    , arena(ctx.arena())\n    , currentInfo(nullptr)\n    , currentScope(nullptr)\n    , breakScope(nullptr)\n    , trueValue(SourceSpan::invalid(), true)\n    , falseValue(SourceSpan::invalid(), false)\n    , nullValue(SourceSpan::invalid())\n    , isEffectsGatheringPass(false) {}\n\n  ~CheckerVisitor();\n\n  void visitNode(Node *n);\n\n  void visitLiteralExpr(LiteralExpr *l);\n  void visitId(Id *id);\n  void visitUnExpr(UnExpr *expr);\n  void visitBinExpr(BinExpr *expr);\n  void visitTerExpr(TerExpr *expr);\n  void visitIncExpr(IncExpr *expr);\n  void visitCallExpr(CallExpr *expr);\n  void visitGetFieldExpr(GetFieldExpr *expr);\n  void visitGetSlotExpr(GetSlotExpr *expr);\n\n  void visitExprStatement(ExprStatement *stmt);\n\n  void visitBlock(Block *b);\n  void visitForStatement(ForStatement *loop);\n  void visitForeachStatement(ForeachStatement *loop);\n  void visitWhileStatement(WhileStatement *loop);\n  void visitDoWhileStatement(DoWhileStatement *loop);\n  void visitIfStatement(IfStatement *ifstmt);\n\n  void visitBreakStatement(BreakStatement *breakStmt);\n  void visitContinueStatement(ContinueStatement *continueStmt);\n\n  void visitSwitchStatement(SwitchStatement *swtch);\n\n  void visitTryStatement(TryStatement *tryStmt);\n\n  void visitFunctionExpr(FunctionExpr *func);\n\n  void visitTableExpr(TableExpr *table);\n  void visitClassExpr(ClassExpr *klass);\n\n  void visitParamDecl(ParamDecl *p);\n  void visitVarDecl(VarDecl *decl);\n  void visitConstDecl(ConstDecl *cnst);\n  void visitEnumDecl(EnumDecl *enm);\n  void visitDestructuringDecl(DestructuringDecl *decl);\n\n  void visitImportStatement(ImportStmt *import);\n\n  ValueRef* addExternalValue(const SQObject &val, const Node *location);\n  void checkDestructuredVarDefault(VarDecl *var);\n\n  void analyze(RootBlock *root, const HSQOBJECT *bindings);\n};\n\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/config.cpp",
    "content": "#include \"config.h\"\n#include \"keyValueFile.h\"\n\n\nnamespace SQCompilation\n{\n\nbool do_report_missing_modules = false;\n\nstd::vector<std::string> function_forbidden;\nstd::vector<std::string> format_function_name;\nstd::vector<std::string> function_can_return_string;\nstd::vector<std::string> function_should_return_bool_prefix;\nstd::vector<std::string> function_should_return_something_prefix;\nstd::vector<std::string> function_result_must_be_utilized;\nstd::vector<std::string> function_can_return_null;\nstd::vector<std::string> function_takes_boolean_lambda;\nstd::vector<std::string> function_requires_result_from_callback;\nstd::vector<std::string> function_ignores_callback_result;\nstd::vector<std::string> function_forbidden_parent_dir;\nstd::vector<std::string> function_modifies_object;\nstd::vector<std::string> function_must_be_called_from_root;\n\n\nvoid resetAnalyzerConfig() {\n\n  function_forbidden = {\n\n  };\n\n  format_function_name = {\n    \"prn\",\n    \"print\",\n    \"form\",\n    \"fmt\",\n    \"log\",\n    \"dbg\",\n    \"assert\",\n  };\n\n  function_can_return_string = {\n    \"subst\",\n    \"concat\",\n    \"tostring\",\n    \"toupper\",\n    \"tolower\",\n    \"slice\",\n    \"trim\",\n    \"join\",\n    \"format\",\n    \"replace\"\n  };\n\n  function_should_return_bool_prefix = {\n    \"has\",\n    \"Has\",\n    \"have\",\n    \"Have\",\n    \"should\",\n    \"Should\",\n    \"need\",\n    \"Need\",\n    \"is\",\n    \"Is\",\n    \"was\",\n    \"Was\",\n    \"will\",\n    \"Will\",\n    \"contains\",\n    \"match\",\n    \"startswith\",\n    \"endswith\"\n  };\n\n  function_should_return_something_prefix = {\n    \"get\",\n    \"Get\"\n  };\n\n  function_result_must_be_utilized = {\n    \"__merge\",\n    \"indexof\",\n    \"findindex\",\n    \"findvalue\",\n    \"len\",\n    \"reduce\",\n    \"tostring\",\n    \"tointeger\",\n    \"tofloat\",\n    \"slice\",\n    \"tolower\",\n    \"toupper\"\n  };\n\n  function_can_return_null = {\n    \"indexof\",\n    \"findindex\",\n    \"findvalue\",\n    \"require_optional\"\n  };\n\n  function_takes_boolean_lambda = {\n    \"findvalue\",\n    \"findindex\",\n    \"filter\"\n  };\n\n  function_ignores_callback_result = {\n    \"each\",\n    \"mutate\",\n  };\n\n  function_requires_result_from_callback = {\n    \"filter\",\n    \"findindex\",\n    \"findvalue\",\n    \"map\",\n    \"reduce\",\n    \"sort\",\n    \"apply\",\n    \"modify\",\n  };\n\n  function_forbidden_parent_dir = {\n    \"require\",\n    \"require_optional\",\n  };\n\n  function_modifies_object = {\n    \"extend\",\n    \"append\",\n    \"__update\",\n    \"insert\",\n    \"apply\",\n    \"clear\",\n    \"sort\",\n    \"reverse\",\n    \"resize\",\n    \"rawdelete\",\n    \"rawset\",\n    \"remove\"\n  };\n\n  function_must_be_called_from_root = {\n    \"keepref\"\n  };\n}\n\nbool loadAnalyzerConfigFile(const char *configFile) {\n  KeyValueFile config;\n  if (!config.loadFromFile(configFile)) {\n    return false;\n  }\n\n  return loadAnalyzerConfigFile(config);\n}\n\nbool loadAnalyzerConfigFile(const KeyValueFile &config) {\n  do_report_missing_modules = config.getBool(\"report_missing_modules\", false);\n\n  for (auto && v : config.getValuesList(\"forbidden_function\"))\n    function_forbidden.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_can_return_null\"))\n    function_can_return_null.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_result_must_be_utilized\"))\n    function_result_must_be_utilized.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_can_return_string\"))\n    function_can_return_string.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_should_return_bool_prefix\"))\n    function_should_return_bool_prefix.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_should_return_something_prefix\"))\n    function_should_return_something_prefix.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_forbidden_parent_dir\"))\n    function_forbidden_parent_dir.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_modifies_object\"))\n    function_modifies_object.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_must_be_called_from_root\"))\n    function_must_be_called_from_root.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_requires_result_from_callback\"))\n    function_requires_result_from_callback.push_back(v);\n\n  for (auto && v : config.getValuesList(\"function_ignores_callback_result\"))\n    function_ignores_callback_result.push_back(v);\n\n  return true;\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/config.h",
    "content": "#pragma once\n\n#include <string>\n#include <vector>\n\nclass KeyValueFile;\n\nnamespace SQCompilation\n{\n\nextern bool do_report_missing_modules;\n\nextern std::vector<std::string> function_can_return_string;\nextern std::vector<std::string> function_should_return_bool_prefix;\nextern std::vector<std::string> function_should_return_something_prefix;\nextern std::vector<std::string> function_result_must_be_utilized;\nextern std::vector<std::string> function_can_return_null;\nextern std::vector<std::string> function_takes_boolean_lambda;\nextern std::vector<std::string> function_requires_result_from_callback;\nextern std::vector<std::string> function_ignores_callback_result;\nextern std::vector<std::string> format_function_name;\nextern std::vector<std::string> function_forbidden;\nextern std::vector<std::string> function_forbidden_parent_dir;\nextern std::vector<std::string> function_modifies_object;\nextern std::vector<std::string> function_must_be_called_from_root;\n\nvoid resetAnalyzerConfig();\nbool loadAnalyzerConfigFile(const KeyValueFile &configBlk);\nbool loadAnalyzerConfigFile(const char *configFile);\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/function_info.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\nstruct FunctionInfo {\n\n  FunctionInfo(const FunctionExpr *d, const FunctionExpr *o) : declaration(d), owner(o) {}\n\n  ~FunctionInfo() = default;\n\n  struct Modifiable {\n    const FunctionExpr *owner;\n    const char *name;\n  };\n\n  const FunctionExpr *owner;\n  std::vector<Modifiable> modifiable;\n  const FunctionExpr *declaration;\n  std::vector<const char *> parameters;\n\n  void joinModifiable(const FunctionInfo *other);\n  void addModifiable(const char *name, const FunctionExpr *o);\n\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/function_ret_type_eval.cpp",
    "content": "#include \"function_ret_type_eval.h\"\n#include \"naming.h\"\n#include \"checker_visitor.h\"\n\n\nnamespace SQCompilation\n{\n\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalStmt(const Statement *n) {\n  switch (n->op())\n  {\n    case TO_RETURN: return evalReturn(static_cast<const ReturnStatement *>(n));\n    case TO_THROW: return evalThrow(static_cast<const ThrowStatement *>(n));\n    case TO_FOR: case TO_FOREACH: case TO_WHILE: case TO_DOWHILE:\n      return evalLoop(static_cast<const LoopStatement *>(n));\n    case TO_IF: return evalIf(static_cast<const IfStatement *>(n));\n    case TO_SWITCH: return evalSwitch(static_cast<const SwitchStatement *>(n));\n    case TO_BLOCK: return evalBlock(static_cast<const Block *>(n));\n    case TO_TRY: return evalTry(static_cast<const TryStatement *>(n));\n    case TO_BREAK:\n    case TO_CONTINUE:\n      return StmtEvalResult::fallsThrough(); // Control flow, but no return\n    default:\n      return StmtEvalResult::fallsThrough(); // Expression statements, declarations, etc.\n  }\n}\n\nunsigned FunctionReturnTypeEvaluator::evalLiteral(const LiteralExpr *lit) {\n  switch (lit->kind())\n  {\n    case LK_STRING: return RT_STRING;\n    case LK_NULL: return RT_NULL;\n    case LK_BOOL: return RT_BOOL;\n    default: return RT_NUMBER;\n  }\n}\n\nunsigned FunctionReturnTypeEvaluator::evalExpr(const Expr *expr) {\n  switch (expr->op())\n  {\n    case TO_LITERAL:\n      return evalLiteral(static_cast<const LiteralExpr *>(expr));\n    case TO_OROR:\n    case TO_ANDAND:\n    case TO_NULLC:\n      return evalCompoundBin(static_cast<const BinExpr *>(expr));\n    case TO_NE:\n    case TO_EQ:\n    case TO_GE:\n    case TO_GT:\n    case TO_LE:\n    case TO_LT:\n    case TO_INSTANCEOF:\n    case TO_IN:\n    case TO_NOT:\n      return RT_BOOL;\n    case TO_ADD:\n      return evalAddExpr(static_cast<const BinExpr *>(expr));\n    case TO_MOD: {\n      const BinExpr *b = static_cast<const BinExpr *>(expr);\n      if (canBeString(b->rhs())) // this special pattern 'o % \"something\"'\n        return RT_UNRECOGNIZED;\n    } // -V796 fall through\n    case TO_SUB:\n    case TO_MUL:\n    case TO_DIV:\n    case TO_NEG:\n    case TO_BNOT:\n    case TO_3CMP:\n    case TO_AND:\n    case TO_OR:\n    case TO_XOR:\n    case TO_SHL:\n    case TO_SHR:\n    case TO_USHR:\n    case TO_INC:\n      return RT_NUMBER;\n    case TO_CALL:\n      return evalCall(expr->asCallExpr());\n    case TO_TABLE:\n      return RT_TABLE;\n    case TO_CLASS:\n      return RT_CLASS;\n    case TO_FUNCTION:\n      return RT_CLOSURE;\n    case TO_ARRAY:\n      return RT_ARRAY;\n    case TO_PAREN:\n      return evalExpr(static_cast<const UnExpr *>(expr)->argument());\n    case TO_TERNARY: {\n        const TerExpr *ter = static_cast<const TerExpr *>(expr);\n        return evalExpr(ter->b()) | evalExpr(ter->c());\n    }\n    case TO_ID:\n        return evalId(expr->asId());\n    case TO_GETFIELD: {\n        unsigned flags = evalGetField(expr->asGetField());\n        if (expr->asAccessExpr()->isNullable())\n          flags |= RT_NULL;\n        return flags;\n    }\n    case TO_GETSLOT:\n        if (expr->asAccessExpr()->isNullable())\n          return RT_NULL;\n        return 0;\n    case TO_ASSIGN:\n        return RT_NOTHING;\n    default:\n      if (canBeString(expr))\n        return RT_STRING;\n      else\n        return RT_UNRECOGNIZED;\n  }\n}\n\nunsigned FunctionReturnTypeEvaluator::evalAddExpr(const BinExpr *expr) {\n  assert(expr->op() == TO_ADD);\n\n  unsigned lhsFlags = evalExpr(expr->lhs());\n  unsigned rhsFlags = evalExpr(expr->rhs());\n\n  if ((lhsFlags & RT_STRING) || (rhsFlags & RT_STRING)) {\n    // concat with string is casted to string\n    return RT_STRING;\n  }\n  else if ((lhsFlags | rhsFlags) & RT_NUMBER) {\n    return RT_NUMBER;\n  }\n  else {\n    return lhsFlags | rhsFlags;\n  }\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalReturn(const ReturnStatement *ret) {\n  const Expr *arg = ret->argument();\n\n  if (arg == nullptr) {\n    return StmtEvalResult::returns(RT_NOTHING);\n  }\n\n  return StmtEvalResult::returns(evalExpr(arg));\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalThrow(const ThrowStatement *thrw) {\n  return StmtEvalResult::returns(RT_THROW);\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalIf(const IfStatement *ifStmt) {\n  StmtEvalResult thenResult = evalStmt(ifStmt->thenBranch());\n\n  if (!ifStmt->elseBranch()) {\n    return StmtEvalResult::fallsThrough(thenResult.flags);\n  }\n\n  StmtEvalResult elseResult = evalStmt(ifStmt->elseBranch());\n\n  unsigned combinedFlags = thenResult.flags | elseResult.flags;\n  bool allReturn = thenResult.allPathsReturn && elseResult.allPathsReturn;\n\n  return StmtEvalResult(combinedFlags, allReturn);\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalLoop(const LoopStatement *loop) {\n  StmtEvalResult bodyResult = evalStmt(loop->body());\n  // Loop may not execute at all, so it never guarantees return\n  return StmtEvalResult::fallsThrough(bodyResult.flags);\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalBlock(const Block *block) {\n  unsigned accumulatedFlags = 0;\n  bool lastReturns = false;\n\n  for (const Statement *stmt : block->statements()) {\n    if (stmt->op() == TO_EMPTY)\n      continue;\n    StmtEvalResult result = evalStmt(stmt);\n    accumulatedFlags |= result.flags;\n    lastReturns = result.allPathsReturn;\n  }\n\n  return StmtEvalResult(accumulatedFlags, lastReturns);\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalSwitch(const SwitchStatement *swtch) {\n  unsigned accumulatedFlags = 0;\n  bool allCasesReturn = true;\n\n  for (auto &c : swtch->cases()) {\n    StmtEvalResult caseResult = evalStmt(c.stmt);\n    accumulatedFlags |= caseResult.flags;\n\n    if (!caseResult.allPathsReturn) {\n      const Statement *last = unwrapLastStatement(c.stmt);\n      if (!last || last->op() != TO_BREAK) // fall through\n        continue;\n    }\n    allCasesReturn &= caseResult.allPathsReturn;\n  }\n\n  if (swtch->defaultCase().stmt) {\n    StmtEvalResult defaultResult = evalStmt(swtch->defaultCase().stmt);\n    accumulatedFlags |= defaultResult.flags;\n    allCasesReturn &= defaultResult.allPathsReturn;\n  }\n  else {\n    allCasesReturn = false;\n  }\n\n  return StmtEvalResult(accumulatedFlags, allCasesReturn);\n}\n\nStmtEvalResult FunctionReturnTypeEvaluator::evalTry(const TryStatement *stmt) {\n  StmtEvalResult tryResult = evalStmt(stmt->tryStatement());\n  StmtEvalResult catchResult = evalStmt(stmt->catchStatement());\n\n  unsigned combinedFlags = tryResult.flags | catchResult.flags;\n  bool allReturn = tryResult.allPathsReturn && catchResult.allPathsReturn;\n\n  return StmtEvalResult(combinedFlags, allReturn);\n}\n\nunsigned FunctionReturnTypeEvaluator::evalCompoundBin(const BinExpr *expr) {\n  TreeOp op = expr->op();\n\n  assert(op == TO_ANDAND || op == TO_OROR || op == TO_NULLC);\n\n  unsigned lhsFlags = evalExpr(expr->lhs());\n  unsigned rhsFlags = evalExpr(expr->rhs());\n\n  lhsFlags &= ~RT_UNRECOGNIZED;\n  rhsFlags &= ~RT_UNRECOGNIZED;\n\n  bool hasFuncCall = (lhsFlags | rhsFlags) & RT_FUNCTION_CALL;\n\n  lhsFlags &= ~RT_FUNCTION_CALL;\n  rhsFlags &= ~RT_FUNCTION_CALL;\n\n  unsigned resultFlags = 0;\n\n  if (op != TO_NULLC && (((lhsFlags & RT_BOOL) && (rhsFlags & RT_NUMBER)) || ((rhsFlags & RT_BOOL) && (lhsFlags & RT_NUMBER))))\n    resultFlags = RT_BOOL;\n  else if (rhsFlags & RT_NULL)\n    resultFlags = RT_NULL;\n  else if ((lhsFlags | rhsFlags) & RT_STRING)\n    resultFlags = RT_STRING;\n  else\n    resultFlags = rhsFlags;\n\n  if (hasFuncCall)\n    resultFlags |= RT_FUNCTION_CALL;\n\n  return resultFlags;\n}\n\nunsigned FunctionReturnTypeEvaluator::evalId(const Id *id) {\n  if (nameLooksLikeResultMustBeBoolean(id->name()))\n    return RT_BOOL;\n  else\n    return RT_UNRECOGNIZED;\n}\n\nunsigned FunctionReturnTypeEvaluator::evalGetField(const GetFieldExpr *gf) {\n  if (nameLooksLikeResultMustBeBoolean(gf->fieldName()))\n    return RT_BOOL;\n  else\n    return RT_UNRECOGNIZED;\n}\n\n\nunsigned FunctionReturnTypeEvaluator::evalCall(const CallExpr *call) {\n  unsigned flags = 0;\n\n  if (canBeString(call)) {\n    flags |= RT_STRING;\n  }\n\n  const char *fn = checker->extractFunctionName(call);\n\n  if (nameLooksLikeResultMustBeBoolean(fn)) {\n    flags |= RT_BOOL;\n  }\n\n  if (call->isNullable())\n    flags |= RT_NULL;\n\n  flags |= RT_FUNCTION_CALL;\n\n  return flags;\n}\n\nbool FunctionReturnTypeEvaluator::canBeString(const Expr *e) {\n  return checker->couldBeString(e);\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/function_ret_type_eval.h",
    "content": "#pragma once\n\n#include \"compiler/ast.h\"\n#include \"analyzer_internal.h\"\n\n\nnamespace SQCompilation\n{\n\nclass CheckerVisitor;\n\n\nstruct StmtEvalResult\n{\n  unsigned flags;\n  bool allPathsReturn;\n\n  StmtEvalResult(unsigned f, bool r) : flags(f), allPathsReturn(r) {}\n\n  static StmtEvalResult returns(unsigned f) { return StmtEvalResult(f, true); }\n  static StmtEvalResult fallsThrough(unsigned f) { return StmtEvalResult(f, false); }\n  static StmtEvalResult fallsThrough() { return StmtEvalResult(0, false); }\n};\n\n\nclass FunctionReturnTypeEvaluator\n{\n  unsigned evalLiteral(const LiteralExpr *l);\n  unsigned evalAddExpr(const BinExpr *expr);\n  unsigned evalExpr(const Expr *expr);\n  unsigned evalCall(const CallExpr *expr);\n  unsigned evalId(const Id *id);\n  unsigned evalGetField(const GetFieldExpr *gf);\n  unsigned evalCompoundBin(const BinExpr *expr);\n\n  StmtEvalResult evalStmt(const Statement *node);\n\n  StmtEvalResult evalBlock(const Block *b);\n  StmtEvalResult evalIf(const IfStatement *stmt);\n  StmtEvalResult evalLoop(const LoopStatement *loop);\n  StmtEvalResult evalSwitch(const SwitchStatement *swtch);\n  StmtEvalResult evalReturn(const ReturnStatement *ret);\n  StmtEvalResult evalTry(const TryStatement *trstmt);\n  StmtEvalResult evalThrow(const ThrowStatement *thrw);\n\n  const Statement *unwrapLastStatement(const Statement *stmt) {\n    if (stmt->op() == TO_BLOCK) {\n      const Block *b = stmt->asBlock();\n      auto &stmts = b->statements();\n      return stmts.empty() ? nullptr : unwrapLastStatement(stmts.back());\n    }\n\n    return stmt;\n  }\n\n  CheckerVisitor *checker;\n\n  bool canBeString(const Expr *e);\n\npublic:\n\n  FunctionReturnTypeEvaluator(CheckerVisitor *c) : checker(c) {}\n\n  unsigned compute(const Statement *n, bool &allPathsReturn) {\n    StmtEvalResult result = evalStmt(n);\n    allPathsReturn = result.allPathsReturn;\n\n    unsigned flags = result.flags;\n    if (!allPathsReturn) {\n      flags |= RT_NOTHING;\n    }\n\n    return flags;\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/global_state.cpp",
    "content": "#include <assert.h>\n#include \"global_state.h\"\n\nnamespace SQCompilation\n{\n\nstd::unordered_set<std::string> knownBindings;\nstd::unordered_set<std::string> fileNames;\nstd::unordered_map<std::string, std::vector<IdLocation>> declaredGlobals;\nstd::unordered_map<std::string, std::vector<IdLocation>> usedGlobals;\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/global_state.h",
    "content": "#pragma once\n\n#include <string>\n#include <vector>\n#include <unordered_map>\n#include <unordered_set>\n\n#include \"checker_visitor.h\"\n\nnamespace SQCompilation\n{\n\nextern std::unordered_set<std::string> knownBindings;\nextern std::unordered_set<std::string> fileNames;\nextern std::unordered_map<std::string, std::vector<IdLocation>> declaredGlobals;\nextern std::unordered_map<std::string, std::vector<IdLocation>> usedGlobals;\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/loop_terminator_collector.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\n\nclass LoopTerminatorCollector : public Visitor {\n  bool _firstLevel; // means not under some condition, if or switch\n  bool _inSwitch;\n  bool _inTry;\n\n  void setTerminator(const Statement *t) {\n    if (terminator == nullptr)\n      terminator = t;\n  }\n\npublic:\n\n  bool hasCondBreak;\n  bool hasCondContinue;\n  bool hasCondReturn;\n  bool hasCondThrow;\n\n  bool hasUnconditionalTerm;\n  bool hasUnconditionalContinue;\n\n  const Statement *terminator;\n\n  LoopTerminatorCollector(bool firstLevel)\n    : _firstLevel(firstLevel)\n    , _inSwitch(false)\n    , _inTry(false)\n    , hasCondBreak(false)\n    , hasCondContinue(false)\n    , hasCondReturn(false)\n    , hasCondThrow(false)\n    , hasUnconditionalTerm(false)\n    , hasUnconditionalContinue(false)\n    , terminator(nullptr) {}\n\n  void visitReturnStatement(ReturnStatement *stmt) override {\n    if (_firstLevel) {\n      hasUnconditionalTerm = true;\n      setTerminator(stmt);\n    }\n    else if (!hasUnconditionalTerm)\n      hasCondReturn = true;\n  }\n\n  void visitThrowStatement(ThrowStatement *stmt) override {\n    if (_firstLevel && !_inTry) {\n      hasUnconditionalTerm = true;\n      setTerminator(stmt);\n    }\n    else if(!hasUnconditionalTerm)\n      hasCondThrow = true;\n  }\n\n  void visitBreakStatement(BreakStatement *stmt) override {\n    if (_firstLevel) {\n      hasUnconditionalTerm = true;\n      setTerminator(stmt);\n    }\n    else if (!_inSwitch && !hasUnconditionalTerm)\n      hasCondBreak = true;\n  }\n\n  void visitContinueStatement(ContinueStatement *stmt) override {\n    if (_firstLevel) {\n      hasUnconditionalTerm = true;\n      hasUnconditionalContinue = true;\n      setTerminator(stmt);\n    }\n    else if (!hasUnconditionalTerm)\n      hasCondContinue = true;\n  }\n\n  void visitIfStatement(IfStatement *stmt) override {\n    bool old = _firstLevel;\n    _firstLevel = false;\n    Visitor::visitIfStatement(stmt);\n    _firstLevel = old;\n  }\n\n  void visitLoopStatement(LoopStatement *loop) override {\n    // skip - nested loops have their own break/continue/return semantics\n  }\n\n  void visitFunctionExpr(FunctionExpr *f) override {\n    // skip - function expressions have their own return semantics\n  }\n\n  void visitDecl(Decl *d) override {\n    // skip\n  }\n\n  void visitTryStatement(TryStatement *stmt) override {\n    bool old = _inTry;\n    _inTry = true;\n    stmt->tryStatement()->visit(this);\n    _inTry = old;\n    stmt->catchStatement()->visit(this);\n  }\n\n  void visitSwitchStatement(SwitchStatement *stmt) override {\n    bool oldL = _firstLevel;\n    bool oldS = _inSwitch;\n    _firstLevel = false;\n    _inSwitch = true;\n    Visitor::visitSwitchStatement(stmt);\n    _inSwitch = oldS;\n    _firstLevel = oldL;\n  }\n\n  bool hasUnconditionalTerminator() const {\n    if (hasCondContinue)\n      return false;\n    return hasUnconditionalTerm;\n  }\n};\n\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/modification_checker.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\n\nclass ModificationChecker : public Visitor\n{\n  bool result = false;\npublic:\n\n  void visitNode(Node *n) override {\n    TreeOp op = n->op();\n\n    switch (op)\n    {\n    case TO_INC:\n    case TO_ASSIGN:\n    case TO_PLUSEQ:\n    case TO_MINUSEQ:\n    case TO_MULEQ:\n    case TO_DIVEQ:\n    case TO_MODEQ:\n      result = true;\n      return;\n    default:\n      n->visitChildren(this);\n      break;\n    }\n  }\n\n  bool check(Node *n) {\n    result = false;\n    n->visit(this);\n    return result;\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/name_shadowing_checker.cpp",
    "content": "#include \"compiler/ast.h\"\n#include \"compiler/compilationcontext.h\"\n#include \"name_shadowing_checker.h\"\n#include \"symbol_info.h\"\n\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqclass.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n\n\nnamespace SQCompilation\n{\n\n\nvoid NameShadowingChecker::loadBindings(const HSQOBJECT *bindings) {\n  if (bindings && sq_istable(*bindings)) {\n    SQTable *table = _table(*bindings);\n\n    SQInteger idx = 0;\n    SQObjectPtr pos(idx), key, val;\n\n    while ((idx = table->Next(false, pos, key, val)) >= 0) {\n      if (sq_isstring(key)) {\n        const char *s = _string(key)->_val;\n        SymbolInfo *info = newSymbolInfo(SK_EXTERNAL_BINDING);\n        declareSymbol(s, info);\n      }\n      pos._unVal.nInteger = idx;\n    }\n  }\n}\n\nconst Node *NameShadowingChecker::extractPointedNode(const SymbolInfo *info) {\n  switch (info->kind)\n  {\n  case SK_EXCEPTION:\n    return info->declaration.x;\n  case SK_FUNCTION:\n    return info->declaration.f;\n  case SK_CLASS:\n    return info->declaration.k;\n  case SK_TABLE:\n    return info->declaration.t;\n  case SK_VAR:\n  case SK_BINDING:\n  case SK_FOREACH:\n    return info->declaration.v;\n  case SK_CONST:\n    return info->declaration.c;\n  case SK_ENUM:\n    return info->declaration.e;\n  case SK_ENUM_CONST:\n    return info->declaration.ec->val;\n  case SK_PARAM:\n    return info->declaration.p;\n  case SK_EXTERNAL_BINDING:\n    return &rootPointerNode;\n  default:\n    assert(0);\n    return nullptr;\n  }\n}\n\nvoid NameShadowingChecker::declareSymbol(const char *name, SymbolInfo *info) {\n  const SymbolInfo *existedInfo = scope->findSymbol(name);\n  if (existedInfo) {\n    bool warn = name[0] != '_' && name[0] != '@';\n    if (strcmp(name, \"this\") == 0) {\n      warn = false;\n    }\n\n    if (existedInfo->ownerScope == info->ownerScope) { // something like `let foo = expr<function foo() { .. }>`\n      if ((info->kind == SK_BINDING || info->kind == SK_VAR) && existedInfo->kind == SK_FUNCTION) {\n        const VarDecl *vardecl = info->declaration.v;\n        const FunctionExpr *funcdecl = existedInfo->declaration.f;\n        const Expr *varinit = vardecl->initializer();\n\n        if (varinit == funcdecl) {\n          warn = false;\n        }\n      }\n    }\n\n    if (existedInfo->kind == SK_FUNCTION && info->kind == SK_FUNCTION) {\n      const FunctionExpr *existed = existedInfo->declaration.f;\n      const FunctionExpr *_new = info->declaration.f;\n      if (existed->name()[0] == '(' && _new->name()[0] == '(') {\n        warn = false;\n      }\n    }\n\n    if (info->kind == SK_PARAM && existedInfo->kind == SK_PARAM && warn) {\n      const ParamDecl *p1 = info->declaration.p;\n      const ParamDecl *p2 = existedInfo->declaration.p;\n      if (p1->isVararg() && p2->isVararg()) {\n        warn = false;\n      }\n    }\n\n    if (warn) {\n      report(extractPointedNode(info), DiagnosticsId::DI_ID_HIDES_ID,\n        symbolContextName(info->kind),\n        info->name,\n        symbolContextName(existedInfo->kind));\n    }\n  }\n\n  scope->symbols[name] = info;\n}\n\nNameShadowingChecker::SymbolInfo *NameShadowingChecker::Scope::findSymbol(const char *name) const {\n  auto it = symbols.find(name);\n  if (it != symbols.end()) {\n    return it->second;\n  }\n\n  return parent ? parent->findSymbol(name) : nullptr;\n}\n\nvoid NameShadowingChecker::visitNode(Node *n) {\n  nodeStack.push_back(n);\n  n->visitChildren(this);\n  nodeStack.pop_back();\n}\n\nvoid NameShadowingChecker::declareVar(enum SymbolKind k, const VarDecl *var) {\n  const FunctionExpr *f = nullptr;\n  if (k == SK_BINDING) {\n    const Expr *init = var->initializer();\n    if (init && init->op() == TO_FUNCTION) {\n      k = SK_FUNCTION;\n      f = init->asFunctionExpr();\n    }\n  }\n\n\n  SymbolInfo *info = newSymbolInfo(k);\n  if (f) {\n    info->declaration.f = f;\n  }\n  else {\n    info->declaration.v = var;\n  }\n  info->ownerScope = scope;\n  info->name = var->name();\n  declareSymbol(var->name(), info);\n}\n\nvoid NameShadowingChecker::visitVarDecl(VarDecl *var) {\n  Visitor::visitVarDecl(var);\n\n  declareVar(var->isAssignable() ? SK_VAR : SK_BINDING, var);\n}\n\nvoid NameShadowingChecker::visitParamDecl(ParamDecl *p) {\n  Visitor::visitParamDecl(p);\n\n  SymbolInfo *info = newSymbolInfo(SK_PARAM);\n  info->declaration.p = p;\n  info->ownerScope = scope;\n  info->name = p->name();\n  declareSymbol(p->name(), info);\n}\n\nvoid NameShadowingChecker::visitConstDecl(ConstDecl *c) {\n  SymbolInfo *info = newSymbolInfo(SK_CONST);\n  info->declaration.c = c;\n  info->ownerScope = scope;\n  info->name = c->name();\n  declareSymbol(c->name(), info);\n\n  Visitor::visitConstDecl(c);\n}\n\nvoid NameShadowingChecker::visitEnumDecl(EnumDecl *e) {\n  SymbolInfo *einfo = newSymbolInfo(SK_ENUM);\n  einfo->declaration.e = e;\n  einfo->ownerScope = scope;\n  einfo->name = e->name();\n  declareSymbol(e->name(), einfo);\n\n  for (auto &ec : e->consts()) {\n    SymbolInfo *cinfo = newSymbolInfo(SK_ENUM_CONST);\n    // Are these fully qualified names ever used?\n    const char *fqn = enumFqn(_ctx.arena(), e->name(), ec.id);\n\n    cinfo->declaration.ec = &ec;\n    cinfo->ownerScope = scope;\n    cinfo->name = fqn;\n\n    declareSymbol(fqn, cinfo);\n  }\n}\n\nvoid NameShadowingChecker::visitFunctionExpr(FunctionExpr *f) {\n  Scope *p = scope;\n\n  Scope funcScope(this, f);\n\n  bool tableScope = p->owner && (p->owner->op() == TO_CLASS || p->owner->op() == TO_TABLE);\n\n  if (!tableScope) {\n    SymbolInfo * info = newSymbolInfo(SK_FUNCTION);\n    info->declaration.f = f;\n    info->ownerScope = p;\n    info->name = f->name();\n    declareSymbol(f->name(), info);\n  }\n\n  Visitor::visitFunctionExpr(f);\n}\n\nvoid NameShadowingChecker::visitTableExpr(TableExpr *t) {\n  Scope tableScope(this, t);\n\n  nodeStack.push_back(t);\n  t->visitChildren(this);\n  nodeStack.pop_back();\n}\n\nvoid NameShadowingChecker::visitClassExpr(ClassExpr *k) {\n  Scope klassScope(this, k);\n\n  nodeStack.push_back(k);\n  k->visitChildren(this);\n  nodeStack.pop_back();\n}\n\nvoid NameShadowingChecker::visitBlock(Block *block) {\n  Scope blockScope(this, scope->owner);\n  Visitor::visitBlock(block);\n}\n\nvoid NameShadowingChecker::visitTryStatement(TryStatement *stmt) {\n\n  nodeStack.push_back(stmt);\n\n  stmt->tryStatement()->visit(this);\n\n  Scope catchScope(this, scope->owner);\n\n  SymbolInfo *info = newSymbolInfo(SK_EXCEPTION);\n  info->declaration.x = stmt->exceptionId();\n  info->ownerScope = scope;\n  info->name = stmt->exceptionId()->name();\n  declareSymbol(stmt->exceptionId()->name(), info);\n\n  stmt->catchStatement()->visit(this);\n\n  nodeStack.pop_back();\n}\n\nvoid NameShadowingChecker::visitForStatement(ForStatement *stmt) {\n  assert(scope);\n  Scope forScope(this, scope->owner);\n\n  Visitor::visitForStatement(stmt);\n}\n\nvoid NameShadowingChecker::visitForeachStatement(ForeachStatement *stmt) {\n\n  assert(scope);\n  Scope foreachScope(this, scope->owner);\n\n  VarDecl *idx = stmt->idx();\n  if (idx) {\n    declareVar(SK_FOREACH, idx);\n    assert(idx->initializer() == nullptr);\n  }\n  VarDecl *val = stmt->val();\n  if (val) {\n    declareVar(SK_FOREACH, val);\n    assert(val->initializer() == nullptr);\n  }\n\n  nodeStack.push_back(stmt);\n\n  stmt->container()->visit(this);\n  stmt->body()->visit(this);\n\n  nodeStack.pop_back();\n}\n\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/name_shadowing_checker.h",
    "content": "#pragma once\n\n#include \"analyzer_internal.h\"\n#include \"symbol_info.h\"\n\n\nnamespace SQCompilation\n{\n\nclass NameShadowingChecker : public Visitor {\n  SQCompilationContext _ctx;\n\n  std::vector<const Node *> nodeStack;\n\n  void report(const Node *n, int32_t id, ...) {\n    va_list vargs;\n    va_start(vargs, id);\n\n    _ctx.vreportDiagnostic((enum DiagnosticsId)id, n->lineStart(), n->columnStart(), n->textWidth(), vargs); //-V522\n\n    va_end(vargs);\n  }\n\n  struct Scope;\n\n  struct SymbolInfo {\n    union {\n      const Id *x;\n      const FunctionExpr *f;\n      const ClassExpr *k;\n      const VarDecl *v;\n      const TableExpr *t;\n      const ParamDecl *p;\n      const EnumDecl *e;\n      const ConstDecl *c;\n      const EnumConst *ec;\n    } declaration;\n\n    SymbolKind kind;\n\n    const struct Scope *ownerScope;\n    const char *name;\n\n    SymbolInfo(SymbolKind k) : kind(k), declaration(), name(nullptr), ownerScope(nullptr) {}\n  };\n\n  struct Scope {\n    NameShadowingChecker *checker;\n\n    Scope(NameShadowingChecker *chk, const Node *o) : checker(chk), owner(o), symbols() {\n      parent = checker->scope;\n      checker->scope = this;\n    }\n\n    ~Scope() {\n      checker->scope = parent;\n    }\n\n    struct Scope *parent;\n    std::unordered_map<const char *, SymbolInfo *, StringHasher, StringEqualer> symbols;\n    const Node *owner;\n\n    SymbolInfo *findSymbol(const char *name) const;\n  };\n\n  const Node *extractPointedNode(const SymbolInfo *info);\n\n  SymbolInfo *newSymbolInfo(SymbolKind k) {\n    void *mem = _ctx.arena()->allocate(sizeof(SymbolInfo));\n    return new(mem) SymbolInfo(k);\n  }\n\n  struct Scope rootScope;\n\n  struct Scope *scope;\n\n  void loadBindings(const HSQOBJECT *bindings);\n\n  void declareVar(SymbolKind k, const VarDecl *v);\n  void declareSymbol(const char *name, SymbolInfo *info);\n\n  Id rootPointerNode;\npublic:\n  NameShadowingChecker(SQCompilationContext &ctx, const HSQOBJECT *bindings)\n    : _ctx(ctx)\n    , rootScope(this, nullptr)\n    , scope(&rootScope)\n    , rootPointerNode(SourceSpan::invalid(), \"<root>\") {\n    rootScope.parent = nullptr;\n    loadBindings(bindings);\n  }\n\n  void visitNode(Node *n);\n\n  void visitVarDecl(VarDecl *var);\n  void visitFunctionExpr(FunctionExpr *f);\n  void visitParamDecl(ParamDecl *p);\n  void visitConstDecl(ConstDecl *c);\n  void visitEnumDecl(EnumDecl *e);\n  void visitClassExpr(ClassExpr *k);\n  void visitTableExpr(TableExpr *t);\n\n  void visitBlock(Block *block);\n  void visitTryStatement(TryStatement *stmt);\n  void visitForStatement(ForStatement *stmt);\n  void visitForeachStatement(ForeachStatement *stmt);\n\n  void analyze(RootBlock *root) {\n    root->visit(this);\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/naming.cpp",
    "content": "#include <assert.h>\n#include \"naming.h\"\n#include \"ast_helpers.h\"\n\n\nnamespace SQCompilation\n{\n\nbool looksLikeElementCount(const Expr *e) {\n  const char *checkee = nullptr;\n\n  if (e->op() == TO_ID)\n    checkee = e->asId()->name();\n  else if (e->op() == TO_GETFIELD) {\n    checkee = e->asGetField()->fieldName();\n  }\n  else if (e->op() == TO_GETSLOT) {\n    return looksLikeElementCount(deparenStatic(e->asGetSlot()->key()));\n  }\n  else if (e->op() == TO_CALL) {\n    return looksLikeElementCount(deparenStatic(e->asCallExpr()->callee()));\n  }\n\n  if (!checkee)\n    return false;\n\n  static const char * markers[] = { \"len\", \"Len\", \"length\", \"Length\", \"count\", \"Count\", \"cnt\", \"Cnt\", \"size\", \"Size\", \"Num\", \"Number\" };\n\n  for (const char *m : markers) {\n    const char *p = strstr(checkee, m);\n    if (!p)\n      continue;\n\n    if (p == checkee || p[-1] == '_' || (sq_islower(p[-1]) && sq_isupper(p[0]))) {\n      char next = p[strlen(m)];\n      if (!next || next == '_' || sq_isupper(next))\n        return true;\n    }\n  }\n\n  return false;\n}\n\n\nbool isUpperCaseIdentifier(const Expr *e) {\n  const char *id = nullptr;\n\n  if (e->op() == TO_GETFIELD) {\n    id = e->asGetField()->fieldName();\n  }\n\n  if (e->op() == TO_ID) {\n    id = e->asId()->name();\n  }\n  else if (e->op() == TO_LITERAL && e->asLiteral()->kind() == LK_STRING) {\n    id = e->asLiteral()->s();\n  }\n\n  if (!id)\n    return false;\n\n  while (*id) {\n    if (*id >= 'a' && *id <= 'z')\n      return false;\n    ++id;\n  }\n\n  return true;\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/naming.h",
    "content": "#pragma once\n\n#include <string>\n#include <algorithm>\n#include \"compiler/compilationcontext.h\"\n#include \"compiler/ast.h\"\n#include \"config.h\"\n#include <sq_char_class.h>\n\n\nnamespace SQCompilation\n{\n\n\ninline const char *terminatorOpToName(TreeOp op) {\n  switch (op)\n  {\n  case TO_BREAK: return \"break\";\n  case TO_CONTINUE: return \"continue\";\n  case TO_RETURN: return \"return\";\n  case TO_THROW: return \"throw\";\n  default:\n    assert(0);\n    return \"<unknown terminator>\";\n  }\n}\n\n\ninline bool isValidId(const char *id) {\n  assert(id != nullptr);\n\n  if (!sq_isalpha(id[0]) && id[0] != '_')\n    return false;\n\n  for (int i = 1; id[i]; ++i) {\n    char c = id[i];\n    if (!sq_isalpha(c) && !sq_isdigit(c) && c != '_')\n      return false;\n  }\n\n  return true;\n}\n\n\ninline bool hasAnyPrefix(const char *str, const std::vector<std::string> &prefixes) {\n  for (auto &prefix : prefixes) {\n    size_t length = prefix.length();\n    bool hasPrefix = strncmp(str, prefix.c_str(), length)==0;\n    if (hasPrefix) {\n      char c = str[length];\n      if (!c || c == '_' || c != tolower(c)) {\n        return true;\n      }\n    }\n  }\n\n  return false;\n}\n\ninline bool hasAnyEqual(const char *str, const std::vector<std::string> &candidates) {\n  for (auto &candidate : candidates) {\n    if (strcmp(str, candidate.c_str()) == 0) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\ninline bool hasAnySubstring(const char *str, const std::vector<std::string> &candidates) {\n  for (auto &candidate : candidates) {\n    if (strstr(str, candidate.c_str())) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\ninline bool nameLooksLikeResultMustBeBoolean(const char *funcName) {\n  if (!funcName)\n    return false;\n\n  return hasAnyPrefix(funcName, function_should_return_bool_prefix);\n}\n\ninline bool nameLooksLikeFunctionMustReturnResult(const char *funcName) {\n  if (!funcName)\n    return false;\n\n  bool nameInList = nameLooksLikeResultMustBeBoolean(funcName) ||\n    hasAnyPrefix(funcName, function_should_return_something_prefix);\n\n  if (!nameInList)\n    if ((strstr(funcName, \"_ctor\") || strstr(funcName, \"Ctor\")) && strstr(funcName, \"set\") != funcName)\n      nameInList = true;\n\n  return nameInList;\n}\n\ninline bool nameLooksLikeResultMustBeUtilized(const char *name) {\n  return hasAnyEqual(name, function_result_must_be_utilized);\n}\n\ninline bool nameLooksLikeResultMustBeString(const char *name) {\n  return hasAnyEqual(name, function_can_return_string);\n}\n\ninline bool canFunctionReturnNull(const char *n) {\n  return hasAnyEqual(n, function_can_return_null);\n}\n\ninline bool isForbiddenFunctionName(const char *n) {\n  return hasAnyEqual(n, function_forbidden);\n}\n\ninline bool nameLooksLikeMustBeCalledFromRoot(const char *n) {\n  return hasAnyEqual(n, function_must_be_called_from_root);\n}\n\ninline bool nameLooksLikeForbiddenParentDir(const char *n) {\n  return hasAnyEqual(n, function_forbidden_parent_dir);\n}\n\ninline bool nameLooksLikeFormatFunction(const char *n) {\n  std::string transformed(n);\n  std::transform(transformed.begin(), transformed.end(), transformed.begin(), ::tolower);\n\n  return hasAnySubstring(transformed.c_str(), format_function_name);\n}\n\ninline bool nameLooksLikeModifiesObject(const char *n) {\n  return hasAnyEqual(n, function_modifies_object);\n}\n\ninline bool nameLooksLikeFunctionTakeBooleanLambda(const char *n) {\n  return hasAnyEqual(n, function_takes_boolean_lambda);\n}\n\ninline bool nameLooksLikeRequiresResultFromCallback(const char *n) {\n  return hasAnyEqual(n, function_requires_result_from_callback);\n}\n\ninline bool nameLooksLikeIgnoresCallbackResult(const char *n) {\n  return hasAnyEqual(n, function_ignores_callback_result);\n}\n\nbool looksLikeElementCount(const Expr *e);\n\nbool isUpperCaseIdentifier(const Expr *e);\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/node_complexity_counter.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\n\nclass NodeComplexityComputer : public Visitor\n{\n  int32_t complexity;\n  const int32_t limit;\n\n  NodeComplexityComputer(int32_t l) : limit(l), complexity(0) {}\n\npublic:\n  void visitNode(Node *n) override {\n    if (complexity > limit)\n      return;\n\n    Visitor::visitNode(n);\n  }\n\n  // Expressions\n\n  void visitId(Id *id) {\n    complexity += 1;\n  }\n\n  void visitLiteralExpr(LiteralExpr *l) {\n  }\n\n  void visitUnExpr(UnExpr *u) {\n    if (u->op() != TO_PAREN)\n      complexity += 1;\n    Visitor::visitUnExpr(u);\n  }\n\n  void visitBinExpr(BinExpr *b) {\n    complexity += 3;\n    Visitor::visitBinExpr(b);\n  }\n\n  void visitTerExpr(TerExpr *t) {\n    complexity += 2;\n    Visitor::visitTerExpr(t);\n  }\n\n  void visitGetFieldExpr(GetFieldExpr *f) {\n    complexity += 1;\n    Visitor::visitGetFieldExpr(f);\n  }\n\n  void visitGetSlotExpr(GetSlotExpr *t) {\n    complexity += 2;\n    Visitor::visitGetSlotExpr(t);\n  }\n\n  void visitCallExpr(CallExpr *call) {\n    complexity += (call->arguments().size() - 1);\n    Visitor::visitCallExpr(call);\n  }\n\n  void visitIncExpr(IncExpr *inc) {\n    complexity += 1;\n    Visitor::visitIncExpr(inc);\n  }\n\n  void visitArrayExpr(ArrayExpr *arr) {\n    complexity += arr->initializers().size();\n    Visitor::visitArrayExpr(arr);\n  }\n\n  void visitCommaExpr(CommaExpr *comma) {\n    complexity += comma->expressions().size();\n    Visitor::visitCommaExpr(comma);\n  }\n\n  // Statements\n\n  void visitBlock(Block *b) {\n    complexity += b->statements().size();\n    Visitor::visitBlock(b);\n  }\n\n  void visitIfStatement(IfStatement *ifstmt) {\n    complexity += 2;\n    if (ifstmt->elseBranch())\n      complexity += 1;\n\n    Visitor::visitIfStatement(ifstmt);\n  }\n\n  void visitSwitchStatement(SwitchStatement *swtch) {\n    complexity += 1; // switch expr\n    complexity += (swtch->cases().size() * 2); // 2 due to label + body;\n    if (swtch->defaultCase().stmt)\n      complexity += 1;\n\n    Visitor::visitSwitchStatement(swtch);\n  }\n\n  void visitTryStatement(TryStatement *trystmt) {\n    complexity += 3; // try + ex + catch\n    Visitor::visitTryStatement(trystmt);\n  }\n\n  void visitTerminateStatement(TerminateStatement *t) {\n    if (t->argument())\n      complexity += 1;\n\n    Visitor::visitTerminateStatement(t);\n  }\n\n  void visitLoopStatement(LoopStatement *l) {\n    complexity += 1;\n    Visitor::visitLoopStatement(l);\n  }\n\n  void visitWhileStatement(WhileStatement *w) {\n    complexity += 1;\n\n    Visitor::visitWhileStatement(w);\n  }\n\n  void visitDoWhileStatement(DoWhileStatement *dw) {\n    complexity += 1;\n\n    Visitor::visitDoWhileStatement(dw);\n  }\n\n  void visitForStatement(ForStatement *f) {\n    if (f->initializer())\n      complexity += 1;\n\n    if (f->condition())\n      complexity += 1;\n\n    if (f->modifier())\n      complexity += 1;\n\n    Visitor::visitForStatement(f);\n  }\n\n  void visitForeachStatement(ForeachStatement *fe) {\n    if (fe->idx())\n      complexity += 1;\n\n    if (fe->val())\n      complexity += 1;\n\n    complexity += 1;\n\n    Visitor::visitForeachStatement(fe);\n  }\n\n  // Declarations\n\n  void visitValueDecl(ValueDecl *v) {\n    complexity += 1;\n\n    if (v->expression())\n      complexity += 1;\n\n    Visitor::visitValueDecl(v);\n  }\n\n  void visitTableExpr(TableExpr *t) {\n    complexity += (t->members().size() * 2); // key + value\n\n    Visitor::visitTableExpr(t);\n  }\n\n  void visitClassExpr(ClassExpr *c) {\n    if (c->classBase())\n      complexity += 1;\n\n    if (c->classKey())\n      complexity += 1;\n\n    Visitor::visitClassExpr(c);\n  }\n\n  void visitFunctionExpr(FunctionExpr *f) {\n    complexity += f->parameters().size();\n\n    Visitor::visitFunctionExpr(f);\n  }\n\n  void visitEnumDecl(EnumDecl *e) {\n    complexity += 1; //name\n    complexity += (e->consts().size() * 2);\n    Visitor::visitEnumDecl(e);\n  }\n\n  void visitConstDecl(ConstDecl *c) {\n    complexity += 2;\n    Visitor::visitConstDecl(c);\n  }\n\n  void visitDeclGroup(DeclGroup *g) {\n    complexity += g->declarations().size();\n    Visitor::visitDeclGroup(g);\n  }\n\n  void visitDestructuringDecl(DestructuringDecl *dd) {\n    complexity += 1;\n\n    Visitor::visitDestructuringDecl(dd);\n  }\n\n  static int32_t compute(const Node *n, int32_t limit) {\n    NodeComplexityComputer c(limit);\n    const_cast<Node *>(n)->visit(&c);\n    return c.complexity;\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/node_diff_computer.h",
    "content": "#pragma once\n\nnamespace SQCompilation\n{\n\n\nclass NodeDiffComputer\n{\n\n  const struct {\n    const int32_t OpDiffCost = 40;\n    const int32_t SizeDiffCost = 30;\n    const int32_t SizeDiffCoeff = 11;\n    const int32_t NullDiffCost = SizeDiffCost;\n    const int32_t IncFormDiffCost = 2;\n    const int32_t IncValDiffCost = 1;\n    const int32_t NameDiffCost = 1;\n    const int32_t LiteralDiffCost = 1;\n    const int32_t MutabilityDiffCost = 1;\n    const int32_t StaticMemberDiffCost = 2;\n    const int32_t NullabilityDiffCost = 3;\n  } DiffCosts;\n\n  const int32_t limit;\n\n  int32_t sizeDiff(const int32_t l, const int32_t r) const {\n    return DiffCosts.SizeDiffCost + std::abs(l - r) * DiffCosts.SizeDiffCoeff;\n  }\n\n  NodeDiffComputer(int32_t l) : limit(l) {}\n\n  int32_t average(int32_t total, int32_t size) const {\n    int32_t aver = size ? total / size : 0;\n\n    if (aver == 0)\n      aver = 1;\n\n    return aver;\n  }\n\n  int32_t diffBlock(const Block *lhs, const Block *rhs) {\n    const auto &l = lhs->statements();\n    const auto &r = rhs->statements();\n\n    if (l.size() != r.size())\n      return sizeDiff(l.size(), r.size());\n\n    int32_t total = 0;\n\n    for (int32_t i = 0; i < l.size(); ++i) {\n      int32_t tmp = diffNodes(l[i], r[i]);\n      if (tmp > limit)\n        return tmp;\n      total += tmp;\n    }\n\n    return total;\n  }\n\n  int32_t diffIf(const IfStatement *lhs, const IfStatement *rhs) {\n\n    int32_t condDiff = diffNodes(lhs->condition(), rhs->condition());\n\n    if (condDiff > limit)\n      return condDiff;\n\n    int32_t thenDiff = diffNodes(lhs->thenBranch(), rhs->thenBranch());\n\n    if (thenDiff > limit)\n      return thenDiff;\n\n    int32_t elseDiff = diffNodes(lhs->elseBranch(), rhs->elseBranch());\n\n    if (elseDiff > limit)\n      return elseDiff;\n\n    return condDiff + thenDiff + elseDiff;\n  }\n\n  int32_t diffWhile(const WhileStatement *lhs, const WhileStatement *rhs) {\n    int32_t condDiff = diffNodes(lhs->condition(), rhs->condition());\n\n    if (condDiff > limit)\n      return condDiff;\n\n    int32_t bodyDiff = diffNodes(lhs->body(), rhs->body());\n\n    if (bodyDiff > limit)\n      return bodyDiff;\n\n    return condDiff + bodyDiff;\n  }\n\n  int32_t diffDoWhile(const DoWhileStatement *lhs, const DoWhileStatement *rhs) {\n    int32_t bodyDiff = diffNodes(lhs->body(), rhs->body());\n\n    if (bodyDiff > limit)\n      return bodyDiff;\n\n    int32_t condDiff = diffNodes(lhs->condition(), rhs->condition());\n\n    if (condDiff > limit)\n      return condDiff;\n\n    return bodyDiff + condDiff;\n  }\n\n  int32_t diffFor(const ForStatement *lhs, const ForStatement *rhs) {\n    int32_t initDiff = diffNodes(lhs->initializer(), rhs->initializer());\n\n    if (initDiff > limit)\n      return initDiff;\n\n    int32_t condDiff = diffNodes(lhs->condition(), rhs->condition());\n\n    if (condDiff > limit)\n      return condDiff;\n\n    int32_t modDiff = diffNodes(lhs->modifier(), rhs->modifier());\n\n    if (modDiff > limit)\n      return modDiff;\n\n    int32_t bodyDiff = diffNodes(lhs->body(), rhs->body());\n\n    if (bodyDiff > limit)\n      return bodyDiff;\n\n    return initDiff + condDiff + modDiff + bodyDiff;\n  }\n\n  int32_t diffForeach(const ForeachStatement *lhs, const ForeachStatement *rhs) {\n    int32_t idxDiff = diffNodes(lhs->idx(), rhs->idx());\n\n    if (idxDiff > limit)\n      return idxDiff;\n\n    int32_t valDiff = diffNodes(lhs->val(), rhs->val());\n\n    if (valDiff > limit)\n      return valDiff;\n\n    int32_t contDiff = diffNodes(lhs->container(), rhs->container());\n\n    if (contDiff > limit)\n      return contDiff;\n\n    int32_t bodyDiff = diffNodes(lhs->body(), rhs->body());\n\n    if (bodyDiff > limit)\n      return bodyDiff;\n\n    return idxDiff + valDiff + contDiff + bodyDiff;\n  }\n\n  int32_t diffSwitch(const SwitchStatement *lhs, const SwitchStatement *rhs) {\n    int32_t exprDiff = diffNodes(lhs->expression(), rhs->expression());\n\n    if (exprDiff > limit)\n      return exprDiff;\n\n    const auto &casesLeft = lhs->cases();\n    const auto &casesRight = rhs->cases();\n\n    if (casesLeft.size() != casesRight.size())\n      return sizeDiff(casesLeft.size(), casesRight.size());\n\n    bool leftHasDefault = lhs->defaultCase().stmt != nullptr;\n    bool rightHasDefault = rhs->defaultCase().stmt != nullptr;\n\n    if (leftHasDefault != rightHasDefault) // shortcut\n      return DiffCosts.NullDiffCost;\n\n    int32_t casesDiff = 0;\n\n    for (int32_t i = 0; i < int32_t(casesLeft.size()); ++i) {\n      const auto &l = casesLeft[i];\n      const auto &r = casesRight[i];\n\n      int32_t valDiff = diffNodes(l.val, r.val);\n\n      if (valDiff > limit)\n        return valDiff;\n\n      int32_t bodyDiff = diffNodes(l.stmt, r.stmt);\n\n      if (bodyDiff > limit)\n        return bodyDiff;\n\n      casesDiff += (valDiff + bodyDiff);\n    }\n\n    int32_t defaultDiff = diffNodes(lhs->defaultCase().stmt, rhs->defaultCase().stmt);\n    if (defaultDiff > limit)\n      return defaultDiff;\n\n    return casesDiff + defaultDiff + exprDiff;\n  }\n\n  int32_t diffTerminator(const TerminateStatement *lhs, const TerminateStatement *rhs) {\n    assert(lhs->op() == rhs->op());\n\n    return diffNodes(lhs->argument(), rhs->argument());\n  }\n\n  int32_t diffTry(const TryStatement *lhs, const TryStatement *rhs) {\n    int32_t tryDiff = diffNodes(lhs->tryStatement(), rhs->tryStatement());\n\n    if (tryDiff > limit)\n      return tryDiff;\n\n    int32_t exIdDiff = diffNodes(lhs->exceptionId(), rhs->exceptionId());\n    int32_t catchDiff = diffNodes(lhs->catchStatement(), rhs->catchStatement());\n\n    if (catchDiff > limit)\n      return catchDiff;\n\n    return tryDiff + exIdDiff + catchDiff;\n  }\n\n  int32_t diffExprStmt(const ExprStatement *lhs, const ExprStatement *rhs) {\n    return diffNodes(lhs->expression(), rhs->expression());\n  }\n\n  int32_t diffId(const Id *lhs, const Id *rhs) {\n    return strcmp(lhs->name(), rhs->name()) != 0 ? DiffCosts.NameDiffCost : 0;\n  }\n\n  int32_t diffComma(const CommaExpr *lhs, const CommaExpr *rhs) {\n    const auto &leftExpressions = lhs->expressions();\n    const auto &rightExpression = rhs->expressions();\n\n    if (leftExpressions.size() != rightExpression.size())\n      return sizeDiff(leftExpressions.size(), rightExpression.size());\n\n    int32_t result = 0;\n\n    for (int32_t i = 0; i < leftExpressions.size(); ++i) {\n      const Expr *l = leftExpressions[i];\n      const Expr *r = rightExpression[i];\n\n      int32_t tmp = diffNodes(l, r);\n\n      if (tmp > limit)\n        return tmp;\n\n      result += tmp;\n    }\n\n    return result;\n  }\n\n  int32_t diffBinary(const BinExpr *lhs, const BinExpr *rhs) {\n    assert(lhs->op() == rhs->op());\n\n    int32_t diffLeft = diffNodes(lhs->lhs(), rhs->lhs());\n\n    if (diffLeft > limit)\n      return diffLeft;\n\n    int32_t diffRight = diffNodes(lhs->rhs(), rhs->rhs());\n\n    if (diffRight > limit)\n      return diffRight;\n\n    return diffLeft + diffRight;\n  }\n\n  int32_t diffUnary(const UnExpr *lhs, const UnExpr *rhs) {\n    assert(lhs->op() == rhs->op());\n\n    return diffNodes(lhs->argument(), rhs->argument());\n  }\n\n  int32_t diffLiterals(const LiteralExpr *lhs, const LiteralExpr *rhs) {\n    if (lhs->kind() != rhs->kind())\n      return DiffCosts.LiteralDiffCost;\n\n    switch (lhs->kind()) {\n    case LK_NULL: return 0;\n    case LK_BOOL: return lhs->b() != rhs->b() ? DiffCosts.LiteralDiffCost : 0;\n    case LK_INT: return lhs->i() != rhs->i() ? DiffCosts.LiteralDiffCost : 0;\n    case LK_FLOAT: return lhs->f() != rhs->f() ? DiffCosts.LiteralDiffCost : 0;\n    case LK_STRING: return strcmp(lhs->s(), rhs->s()) != 0 ? DiffCosts.LiteralDiffCost : 0;\n    default: assert(0); return -1000;\n    }\n  }\n\n  int32_t diffIncExpr(const IncExpr *lhs, const IncExpr *rhs) {\n    int32_t result = 0;\n    if (lhs->form() != rhs->form())\n      result += DiffCosts.IncFormDiffCost;\n\n    if (lhs->diff() != rhs->diff())\n      result += DiffCosts.IncValDiffCost;\n\n    int32_t argDiff = diffNodes(lhs->argument(), rhs->argument());\n\n    if (argDiff > limit)\n      return argDiff;\n\n    return result + argDiff;\n  }\n\n  int32_t diffArrayExpr(const ArrayExpr *lhs, const ArrayExpr *rhs) {\n    const auto &leftInits = lhs->initializers();\n    const auto &rightInits = rhs->initializers();\n\n    if (leftInits.size() != rightInits.size())\n      return sizeDiff(leftInits.size(), rightInits.size());\n\n    int32_t result = 0;\n\n    for (int32_t i = 0; i < leftInits.size(); ++i) {\n      const Expr *l = leftInits[i];\n      const Expr *r = rightInits[i];\n\n      int32_t tmp = diffNodes(l, r);\n\n      if (tmp > limit)\n        return tmp;\n\n      result += tmp;\n    }\n\n    return result;\n  }\n\n  int32_t diffGetField(const GetFieldExpr *lhs, const GetFieldExpr *rhs) {\n    int32_t receiverDiff = diffNodes(lhs->receiver(), rhs->receiver());\n\n    if (receiverDiff > limit)\n      return receiverDiff;\n\n    if (strcmp(lhs->fieldName(), rhs->fieldName()) != 0)\n      receiverDiff += DiffCosts.NameDiffCost;\n\n    if (lhs->isNullable() != rhs->isNullable())\n      receiverDiff += DiffCosts.NullabilityDiffCost;\n\n    return receiverDiff;\n  }\n\n  int32_t diffGetSlot(const GetSlotExpr *lhs, const GetSlotExpr *rhs) {\n    int32_t receiverDiff = diffNodes(lhs->receiver(), rhs->receiver());\n\n    if (receiverDiff > limit)\n      return receiverDiff;\n\n    int32_t keyDiff = diffNodes(lhs->key(), rhs->key());\n\n    if (keyDiff > limit)\n      return keyDiff;\n\n    if (lhs->isNullable() != rhs->isNullable())\n      receiverDiff += DiffCosts.NullabilityDiffCost;\n\n    return receiverDiff + keyDiff;\n  }\n\n  int32_t diffCallExpr(const CallExpr *lhs, const CallExpr *rhs) {\n    auto &leftArgs = lhs->arguments();\n    auto &rightArgs = rhs->arguments();\n\n    if (leftArgs.size() != rightArgs.size())\n      return sizeDiff(leftArgs.size(), rightArgs.size());\n\n    int32_t calleeDiff = diffNodes(lhs->callee(), rhs->callee());\n\n    if (calleeDiff > limit)\n      return calleeDiff;\n\n    int32_t argsDiff = 0;\n\n    for (int32_t i = 0; i < leftArgs.size(); ++i) {\n      const Expr *l = leftArgs[i];\n      const Expr *r = rightArgs[i];\n\n      int32_t tmp = diffNodes(l, r);\n\n      if (tmp > limit)\n        return tmp;\n\n      argsDiff += tmp;\n    }\n\n    if (lhs->isNullable() != rhs->isNullable())\n      calleeDiff += DiffCosts.NullabilityDiffCost;\n\n    return argsDiff + calleeDiff;\n  }\n\n  int32_t diffTernary(const TerExpr *lhs, const TerExpr *rhs) {\n    int32_t condDiff = diffNodes(lhs->a(), rhs->a());\n\n    if (condDiff > limit)\n      return condDiff;\n\n    int32_t tDiff = diffNodes(lhs->b(), rhs->b());\n\n    if (tDiff > limit)\n      return tDiff;\n\n    int32_t eDiff = diffNodes(lhs->c(), rhs->c());\n\n    if (eDiff > limit)\n      return eDiff;\n\n    return condDiff + tDiff + eDiff;\n  }\n\n  int32_t diffValueDecl(const ValueDecl *lhs, const ValueDecl *rhs) {\n    int32_t result = strcmp(lhs->name(), rhs->name()) != 0 ? DiffCosts.NameDiffCost : 0;\n\n    result += diffNodes(lhs->expression(), rhs->expression());\n\n    return result;\n  }\n\n  int32_t diffConst(const ConstDecl *lhs, const ConstDecl *rhs) {\n    int32_t nameDiff = strcmp(lhs->name(), rhs->name()) != 0 ? DiffCosts.NameDiffCost : 0;\n    int32_t valueDiff = diffNodes(lhs->value(), rhs->value());\n\n    return nameDiff + valueDiff;\n  }\n\n  int32_t diffVarDecl(const VarDecl *lhs, const VarDecl *rhs) {\n    int32_t diffV = diffValueDecl(lhs, rhs);\n\n    if (lhs->isAssignable() != rhs->isAssignable())\n      diffV += DiffCosts.MutabilityDiffCost;\n\n    return diffV;\n  }\n\n  int32_t diffDeclGroup(const DeclGroup *lhs, const DeclGroup *rhs) {\n    const auto &leftGroup = lhs->declarations();\n    const auto &rightGroup = rhs->declarations();\n\n    if (leftGroup.size() != rightGroup.size())\n      return sizeDiff(leftGroup.size(), rightGroup.size());\n\n    int32_t result = 0;\n\n    for (int32_t i = 0; i < leftGroup.size(); ++i) {\n      const VarDecl *l = leftGroup[i];\n      const VarDecl *r = rightGroup[i];\n\n      int32_t tmp = diffVarDecl(l, r);\n\n      if (tmp > limit)\n        return tmp;\n\n      result += tmp;\n    }\n\n    return result;\n  }\n\n  int32_t diffDestructDecl(const DestructuringDecl *lhs, const DestructuringDecl *rhs) {\n    int32_t valueDiff = diffNodes(lhs->initExpression(), rhs->initExpression());\n\n    if (valueDiff > limit)\n      return valueDiff;\n\n    int32_t groupDiff = diffDeclGroup(lhs, rhs);\n\n    if (groupDiff > limit)\n      return groupDiff;\n\n    return valueDiff + groupDiff;\n  }\n\n  const char *realFunctionName(const FunctionExpr *f) const {\n    const char *name = f->name();\n    assert(name);\n\n    if (name[0] == '(') // anonymous\n      return \"\";\n\n    return name;\n  }\n\n  int32_t diffDirective(const DirectiveStmt *lhs, const DirectiveStmt *rhs) {\n    if (lhs->setFlags == rhs->setFlags && lhs->clearFlags == rhs->clearFlags && lhs->applyToDefault == rhs->applyToDefault)\n      return 0;\n    else\n      return DiffCosts.OpDiffCost;\n  }\n\n  int32_t diffFunction(const FunctionExpr *lhs, const FunctionExpr *rhs) {\n    int32_t nameDiff = strcmp(realFunctionName(lhs), realFunctionName(rhs)) != 0 ? DiffCosts.NameDiffCost : 0;\n\n    const auto &leftParams = lhs->parameters();\n    const auto &rightParams = rhs->parameters();\n\n    if (leftParams.size() != rightParams.size())\n      return sizeDiff(leftParams.size(), rightParams.size());\n\n    int32_t paramDiff = 0;\n\n    for (int32_t i = 0; i < leftParams.size(); ++i) {\n      const ParamDecl *l = leftParams[i];\n      const ParamDecl *r = rightParams[i];\n\n      int32_t tmp = diffValueDecl(l, r);\n\n      if (tmp > limit)\n        return tmp;\n\n      paramDiff += tmp;\n    }\n\n    int32_t bodyDiff = diffNodes(lhs->body(), rhs->body());\n\n    if (bodyDiff > limit)\n      return bodyDiff;\n\n    return nameDiff + paramDiff + bodyDiff;\n  }\n\n  int32_t diffTable(const TableExpr *lhs, const TableExpr *rhs) {\n    const auto &leftMembers = lhs->members();\n    const auto &rightMembers = rhs->members();\n\n    if (leftMembers.size() != rightMembers.size())\n      return sizeDiff(leftMembers.size(), rightMembers.size());\n\n    int32_t tableDiff = 0;\n\n    for (int32_t i = 0; i < leftMembers.size(); ++i) {\n      const auto &l = leftMembers[i];\n      const auto &r = rightMembers[i];\n\n      int32_t keyDiff = diffNodes(l.key, r.key);\n\n      if (keyDiff > limit)\n        return keyDiff;\n\n      int32_t valueDiff = diffNodes(l.value, r.value);\n\n      if (valueDiff > limit)\n        return valueDiff;\n\n      tableDiff += (keyDiff + valueDiff);\n\n      if (l.isStatic() != r.isStatic())\n        tableDiff += DiffCosts.StaticMemberDiffCost;\n    }\n\n    return tableDiff;\n  }\n\n  int32_t diffClass(const ClassExpr *lhs, const ClassExpr *rhs) {\n    int32_t keyDiff = diffNodes(lhs->classKey(), rhs->classKey());\n\n    if (keyDiff > limit)\n      return keyDiff;\n\n    int32_t baseDiff = diffNodes(lhs->classBase(), rhs->classBase());\n\n    if (baseDiff > limit)\n      return baseDiff;\n\n    int32_t bodyDiff = diffTable(lhs, rhs);\n\n    if (bodyDiff > limit)\n      return bodyDiff;\n\n    return keyDiff + baseDiff + bodyDiff;\n  }\n\n  int32_t diffEnumDecl(const EnumDecl *lhs, const EnumDecl *rhs) {\n    int32_t nameDiff = strcmp(lhs->name(), rhs->name()) != 0 ? DiffCosts.NameDiffCost : 0;\n\n    const auto &leftValues = lhs->consts();\n    const auto &rightValues = rhs->consts();\n\n    if (leftValues.size() != rightValues.size())\n      return sizeDiff(leftValues.size(), rightValues.size());\n\n    int32_t valueDiff = 0;\n\n    for (int32_t i = 0; i < leftValues.size(); ++i) {\n      const auto &l = leftValues[i];\n      const auto &r = rightValues[i];\n\n      int32_t cNameDiff = strcmp(l.id, r.id) != 0 ? DiffCosts.NameDiffCost : 0;\n      int32_t cValueDiff = diffLiterals(l.val, r.val);\n\n      valueDiff += (cNameDiff + cValueDiff);\n    }\n\n    return nameDiff + valueDiff;\n  }\n\n  int32_t diffNodes(const Node *lhs, const Node *rhs) {\n    if (lhs == rhs)\n      return 0;\n\n    if (!lhs || !rhs) {\n      return DiffCosts.NullDiffCost;\n    }\n\n    if (lhs->op() != rhs->op()) {\n      return DiffCosts.OpDiffCost;\n    }\n\n    switch (lhs->op())\n    {\n    case TO_BLOCK:      return diffBlock((const Block *)lhs, (const Block *)rhs);\n    case TO_IF:         return diffIf((const IfStatement *)lhs, (const IfStatement *)rhs);\n    case TO_WHILE:      return diffWhile((const WhileStatement *)lhs, (const WhileStatement *)rhs);\n    case TO_DOWHILE:    return diffDoWhile((const DoWhileStatement *)lhs, (const DoWhileStatement *)rhs);\n    case TO_FOR:        return diffFor((const ForStatement *)lhs, (const ForStatement *)rhs);\n    case TO_FOREACH:    return diffForeach((const ForeachStatement *)lhs, (const ForeachStatement *)rhs);\n    case TO_SWITCH:     return diffSwitch((const SwitchStatement *)lhs, (const SwitchStatement *)rhs);\n    case TO_RETURN:\n    case TO_YIELD:\n    case TO_THROW:\n      return diffTerminator((const TerminateStatement *)lhs, (const TerminateStatement *)rhs);\n    case TO_TRY:\n      return diffTry((const TryStatement *)lhs, (const TryStatement *)rhs);\n    case TO_BREAK:\n    case TO_CONTINUE:\n    case TO_EMPTY:\n    case TO_BASE:\n    case TO_ROOT_TABLE_ACCESS:\n      return 0;\n    case TO_DIRECTIVE:\n      return diffDirective((const DirectiveStmt*)lhs, (const DirectiveStmt*)rhs);\n    case TO_EXPR_STMT:\n      return diffExprStmt((const ExprStatement *)lhs, (const ExprStatement *)rhs);\n\n      //case TO_STATEMENT_MARK:\n    case TO_ID:         return diffId((const Id *)lhs, (const Id *)rhs);\n    case TO_COMMA:      return diffComma((const CommaExpr *)lhs, (const CommaExpr *)rhs);\n    case TO_NULLC:\n    case TO_ASSIGN:\n    case TO_OROR:\n    case TO_ANDAND:\n    case TO_OR:\n    case TO_XOR:\n    case TO_AND:\n    case TO_NE:\n    case TO_EQ:\n    case TO_3CMP:\n    case TO_GE:\n    case TO_GT:\n    case TO_LE:\n    case TO_LT:\n    case TO_IN:\n    case TO_INSTANCEOF:\n    case TO_USHR:\n    case TO_SHR:\n    case TO_SHL:\n    case TO_MUL:\n    case TO_DIV:\n    case TO_MOD:\n    case TO_ADD:\n    case TO_SUB:\n    case TO_NEWSLOT:\n    case TO_PLUSEQ:\n    case TO_MINUSEQ:\n    case TO_MULEQ:\n    case TO_DIVEQ:\n    case TO_MODEQ:\n      return diffBinary((const BinExpr *)lhs, (const BinExpr *)rhs);\n    case TO_NOT:\n    case TO_BNOT:\n    case TO_NEG:\n    case TO_TYPEOF:\n    case TO_STATIC_MEMO:\n    case TO_INLINE_CONST:\n    case TO_RESUME:\n    case TO_CLONE:\n    case TO_PAREN:\n    case TO_DELETE:\n      return diffUnary((const UnExpr *)lhs, (const UnExpr *)rhs);\n    case TO_LITERAL:\n      return diffLiterals((const LiteralExpr *)lhs, (const LiteralExpr *)rhs);\n    case TO_INC:\n      return diffIncExpr((const IncExpr *)lhs, (const IncExpr *)rhs);\n    case TO_TABLE:\n      return diffTable((const TableExpr *)lhs, (const TableExpr *)rhs);\n    case TO_CLASS:\n      return diffClass((const ClassExpr *)lhs, (const ClassExpr *)rhs);\n    case TO_FUNCTION:\n      return diffFunction((const FunctionExpr *)lhs, (const FunctionExpr *)rhs);\n    case TO_ARRAY:\n      return diffArrayExpr((const ArrayExpr *)lhs, (const ArrayExpr *)rhs);\n    case TO_GETFIELD:\n      return diffGetField((const GetFieldExpr *)lhs, (const GetFieldExpr *)rhs);\n    case TO_GETSLOT:\n      return diffGetSlot((const GetSlotExpr *)lhs, (const GetSlotExpr *)rhs);\n    case TO_CALL:\n      return diffCallExpr((const CallExpr *)lhs, (const CallExpr *)rhs);\n    case TO_TERNARY:\n      return diffTernary((const TerExpr *)lhs, (const TerExpr *)rhs);\n      //case TO_EXPR_MARK:\n    case TO_VAR:\n      return diffVarDecl((const VarDecl *)lhs, (const VarDecl *)rhs);\n    case TO_PARAM:\n      return diffValueDecl((const ValueDecl *)lhs, (const ValueDecl *)rhs);\n    case TO_CONST:\n      return diffConst((const ConstDecl *)lhs, (const ConstDecl *)rhs);\n    case TO_DECL_GROUP:\n      return diffDeclGroup((const DeclGroup *)lhs, (const DeclGroup *)rhs);\n    case TO_DESTRUCTURE:\n      return diffDestructDecl((const DestructuringDecl *)lhs, (const DestructuringDecl *)rhs);\n    case TO_ENUM:\n      return diffEnumDecl((const EnumDecl *)lhs, (const EnumDecl *)rhs);\n    case TO_SETFIELD:\n    case TO_SETSLOT:\n    default:\n      assert(0);\n      return -1;\n    }\n  }\n\npublic:\n  static int32_t compute(const Node *lhs, const Node *rhs, int32_t limit) {\n    NodeDiffComputer c(limit);\n    return c.diffNodes(lhs, rhs);\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/node_equal_checker.h",
    "content": "#pragma once\n\n#include \"compiler/ast.h\"\n\n\nnamespace SQCompilation\n{\n\nclass NodeEqualChecker\n{\n  template<typename N>\n  bool cmpNodeVector(const ArenaVector<N *> &lhs, const ArenaVector<N *> &rhs) const {\n    if (lhs.size() != rhs.size())\n      return false;\n\n    for (int32_t i = 0; i < lhs.size(); ++i) {\n      if (!check(lhs[i], rhs[i]))\n        return false;\n    }\n\n    return true;\n  }\n\n  bool cmpId(const Id *l, const Id* r) const {\n    return strcmp(l->name(), r->name()) == 0;\n  }\n\n  bool cmpLiterals(const LiteralExpr *l, const LiteralExpr *r) const {\n    if (l->kind() != r->kind())\n      return false;\n\n    switch (l->kind())\n    {\n    case LK_STRING: return strcmp(l->s(), r->s()) == 0;\n    default: return l->raw() == r->raw();\n    }\n  }\n\n  bool cmpBinary(const BinExpr *l, const BinExpr *r) const {\n    return check(l->lhs(), r->lhs()) && check(l->rhs(), r->rhs());\n  }\n\n  bool cmpUnary(const UnExpr *l, const UnExpr *r) const {\n    return check(l->argument(), r->argument());\n  }\n\n  bool cmpTernary(const TerExpr *l, const TerExpr *r) const {\n    return check(l->a(), r->a()) && check(l->b(), r->b()) && check(l->c(), r->c());\n  }\n\n  bool cmpBlock(const Block *l, const Block *r) const {\n    if (l->isRoot() != r->isRoot())\n      return false;\n\n    if (l->isBody() != r->isBody())\n      return false;\n\n    return cmpNodeVector(l->statements(), r->statements());\n  }\n\n  bool cmpIf(const IfStatement *l, const IfStatement *r) const {\n    if (!check(l->condition(), r->condition()))\n      return false;\n\n    if (!check(l->thenBranch(), r->thenBranch()))\n      return false;\n\n    return check(l->elseBranch(), r->elseBranch());\n  }\n\n  bool cmpWhile(const WhileStatement *l, const WhileStatement *r) const {\n    if (!check(l->condition(), r->condition()))\n      return false;\n\n    return check(l->body(), r->body());\n  }\n\n  bool cmpDoWhile(const DoWhileStatement *l, const DoWhileStatement *r) const {\n    if (!check(l->body(), r->body()))\n      return false;\n\n    return check(l->condition(), r->condition());\n  }\n\n  bool cmpFor(const ForStatement *l, const ForStatement *r) const {\n    if (!check(l->initializer(), r->initializer()))\n      return false;\n\n    if (!check(l->condition(), r->condition()))\n      return false;\n\n    if (!check(l->modifier(), r->modifier()))\n      return false;\n\n    return check(l->body(), r->body());\n  }\n\n  bool cmpForeach(const ForeachStatement *l, const ForeachStatement *r) const {\n    if (!check(l->idx(), r->idx()))\n      return false;\n\n    if (!check(l->val(), r->val()))\n      return false;\n\n    if (!check(l->container(), r->container()))\n      return false;\n\n    return check(l->body(), r->body());\n  }\n\n  bool cmpSwitch(const SwitchStatement *l, const SwitchStatement *r) const {\n    if (!check(l->expression(), r->expression()))\n      return false;\n\n    const auto &lcases = l->cases();\n    const auto &rcases = r->cases();\n\n    if (lcases.size() != rcases.size())\n      return false;\n\n    for (int32_t i = 0; i < lcases.size(); ++i) {\n      const auto &lc = lcases[i];\n      const auto &rc = rcases[i];\n\n      if (!check(lc.val, rc.val))\n        return false;\n\n      if (!check(lc.stmt, rc.stmt))\n        return false;\n    }\n\n    return check(l->defaultCase().stmt, r->defaultCase().stmt);\n  }\n\n  bool cmpTry(const TryStatement *l, const TryStatement *r) const {\n    if (!check(l->tryStatement(), r->tryStatement()))\n      return false;\n\n    if (!check(l->exceptionId(), r->exceptionId()))\n      return false;\n\n    return check(l->catchStatement(), r->catchStatement());\n  }\n\n  bool cmpTerminate(const TerminateStatement *l, const TerminateStatement *r) const {\n    return check(l->argument(), r->argument());\n  }\n\n  bool cmpReturn(const ReturnStatement *l, const ReturnStatement *r) const {\n    return l->isLambdaReturn() == r->isLambdaReturn() && cmpTerminate(l, r);\n  }\n\n  bool cmpExprStmt(const ExprStatement *l, const ExprStatement *r) const {\n    return check(l->expression(), r->expression());\n  }\n\n  bool cmpComma(const CommaExpr *l, const CommaExpr *r) const {\n    return cmpNodeVector(l->expressions(), r->expressions());\n  }\n\n  bool cmpIncExpr(const IncExpr *l, const IncExpr *r) const {\n    if (l->form() != r->form())\n      return false;\n\n    if (l->diff() != r->diff())\n      return false;\n\n    return check(l->argument(), r->argument());\n  }\n\n  bool cmpCallExpr(const CallExpr *l, const CallExpr *r) const {\n    if (l->isNullable() != r->isNullable())\n      return false;\n\n    if (!check(l->callee(), r->callee()))\n      return false;\n\n    return cmpNodeVector(l->arguments(), r->arguments());\n  }\n\n  bool cmpArrayExpr(const ArrayExpr *l, const ArrayExpr *r) const {\n    return cmpNodeVector(l->initializers(), r->initializers());\n  }\n\n  bool cmpGetField(const GetFieldExpr *l, const GetFieldExpr *r) const {\n    if (l->isNullable() != r->isNullable())\n      return false;\n\n    if (strcmp(l->fieldName(), r->fieldName()) != 0)\n      return false;\n\n    return check(l->receiver(), r->receiver());\n  }\n\n  bool cmpGetSlot(const GetSlotExpr *l, const GetSlotExpr *r) const {\n    if (l->isNullable() != r->isNullable())\n      return false;\n\n    if (!check(l->key(), r->key()))\n      return false;\n\n    return check(l->receiver(), r->receiver());\n  }\n\n  bool cmpValueDecl(const ValueDecl *l, const ValueDecl *r) const {\n    if (!check(l->expression(), r->expression()))\n      return false;\n\n    return strcmp(l->name(), r->name()) == 0;\n  }\n\n  bool cmpVarDecl(const VarDecl *l, const VarDecl *r) const {\n    return l->isAssignable() == r->isAssignable() && cmpValueDecl(l, r);\n  }\n\n  bool cmpConst(const ConstDecl *l, const ConstDecl *r) const {\n    if (l->isGlobal() != r->isGlobal())\n      return false;\n\n    if (strcmp(l->name(), r->name()) != 0)\n      return false;\n\n    return check(l->value(), r->value());\n  }\n\n  bool cmpDeclGroup(const DeclGroup *l, const DeclGroup *r) const {\n    return cmpNodeVector(l->declarations(), r->declarations());\n  }\n\n  bool cmpDestructDecl(const DestructuringDecl *l, const DestructuringDecl *r) const {\n    return l->type() == r->type() && check(l->initExpression(), r->initExpression());\n  }\n\n  bool cmpFunction(const FunctionExpr *l, const FunctionExpr *r) const {\n    if (l->isVararg() != r->isVararg())\n      return false;\n\n    if (l->isLambda() != r->isLambda())\n      return false;\n\n    if (strcmp(l->name(), r->name()) != 0)\n      return false;\n\n    if (!cmpNodeVector(l->parameters(), r->parameters()))\n      return false;\n\n    return check(l->body(), r->body());\n  }\n\n  bool cmpTable(const TableExpr *l, const TableExpr *r) const {\n    const auto &lmems = l->members();\n    const auto &rmems = r->members();\n\n    if (lmems.size() != rmems.size())\n      return false;\n\n    for (int32_t i = 0; i < lmems.size(); ++i) {\n      const auto &lm = lmems[i];\n      const auto &rm = rmems[i];\n\n      if (!check(lm.key, rm.key))\n        return false;\n\n      if (!check(lm.value, rm.value))\n        return false;\n\n      if (lm.flags != rm.flags)\n        return false;\n    }\n\n    return true;\n  }\n\n  bool cmpClass(const ClassExpr *l, const ClassExpr *r) const {\n    if (!check(l->classBase(), r->classBase()))\n      return false;\n\n    if (!check(l->classKey(), r->classKey()))\n      return false;\n\n    return cmpTable(l, r);\n  }\n\n  bool cmpEnumDecl(const EnumDecl *l, const EnumDecl *r) const {\n    if (l->isGlobal() != r->isGlobal())\n      return false;\n\n    if (strcmp(l->name(), r->name()) != 0)\n      return false;\n\n    const auto &lcs = l->consts();\n    const auto &rcs = r->consts();\n\n    if (lcs.size() != rcs.size())\n      return false;\n\n    for (int32_t i = 0; i < lcs.size(); ++i) {\n      const auto &lc = lcs[i];\n      const auto &rc = rcs[i];\n\n      if (strcmp(lc.id, rc.id) != 0)\n        return false;\n\n      if (!cmpLiterals(lc.val, rc.val))\n        return false;\n    }\n\n    return true;\n  }\n\npublic:\n\n  bool check(const Node *lhs, const Node *rhs) const {\n\n    if (lhs == rhs)\n      return true;\n\n    if (!lhs || !rhs)\n      return false;\n\n    if (lhs->op() != rhs->op())\n      return false;\n\n    switch (lhs->op())\n    {\n    case TO_BLOCK:      return cmpBlock((const Block *)lhs, (const Block *)rhs);\n    case TO_IF:         return cmpIf((const IfStatement *)lhs, (const IfStatement *)rhs);\n    case TO_WHILE:      return cmpWhile((const WhileStatement *)lhs, (const WhileStatement *)rhs);\n    case TO_DOWHILE:    return cmpDoWhile((const DoWhileStatement *)lhs, (const DoWhileStatement *)rhs);\n    case TO_FOR:        return cmpFor((const ForStatement *)lhs, (const ForStatement *)rhs);\n    case TO_FOREACH:    return cmpForeach((const ForeachStatement *)lhs, (const ForeachStatement *)rhs);\n    case TO_SWITCH:     return cmpSwitch((const SwitchStatement *)lhs, (const SwitchStatement *)rhs);\n    case TO_RETURN:\n      return cmpReturn((const ReturnStatement *)lhs, (const ReturnStatement *)rhs);\n    case TO_YIELD:\n    case TO_THROW:\n      return cmpTerminate((const TerminateStatement *)lhs, (const TerminateStatement *)rhs);\n    case TO_TRY:\n      return cmpTry((const TryStatement *)lhs, (const TryStatement *)rhs);\n    case TO_BREAK:\n    case TO_CONTINUE:\n    case TO_EMPTY:\n    case TO_BASE:\n    case TO_ROOT_TABLE_ACCESS:\n      return true;\n    case TO_EXPR_STMT:\n      return cmpExprStmt((const ExprStatement *)lhs, (const ExprStatement *)rhs);\n\n      //case TO_STATEMENT_MARK:\n    case TO_ID:         return cmpId((const Id *)lhs, (const Id *)rhs);\n    case TO_COMMA:      return cmpComma((const CommaExpr *)lhs, (const CommaExpr *)rhs);\n    case TO_NULLC:\n    case TO_ASSIGN:\n    case TO_OROR:\n    case TO_ANDAND:\n    case TO_OR:\n    case TO_XOR:\n    case TO_AND:\n    case TO_NE:\n    case TO_EQ:\n    case TO_3CMP:\n    case TO_GE:\n    case TO_GT:\n    case TO_LE:\n    case TO_LT:\n    case TO_IN:\n    case TO_INSTANCEOF:\n    case TO_USHR:\n    case TO_SHR:\n    case TO_SHL:\n    case TO_MUL:\n    case TO_DIV:\n    case TO_MOD:\n    case TO_ADD:\n    case TO_SUB:\n    case TO_NEWSLOT:\n    case TO_PLUSEQ:\n    case TO_MINUSEQ:\n    case TO_MULEQ:\n    case TO_DIVEQ:\n    case TO_MODEQ:\n      return cmpBinary((const BinExpr *)lhs, (const BinExpr *)rhs);\n    case TO_NOT:\n    case TO_BNOT:\n    case TO_NEG:\n    case TO_TYPEOF:\n    case TO_STATIC_MEMO:\n    case TO_INLINE_CONST:\n    case TO_RESUME:\n    case TO_CLONE:\n    case TO_PAREN:\n    case TO_DELETE:\n      return cmpUnary((const UnExpr *)lhs, (const UnExpr *)rhs);\n    case TO_LITERAL:\n      return cmpLiterals((const LiteralExpr *)lhs, (const LiteralExpr *)rhs);\n    case TO_INC:\n      return cmpIncExpr((const IncExpr *)lhs, (const IncExpr *)rhs);\n    case TO_TABLE:\n      return cmpTable((const TableExpr *)lhs, (const TableExpr *)rhs);\n    case TO_CLASS:\n      return cmpClass((const ClassExpr *)lhs, (const ClassExpr *)rhs);\n    case TO_FUNCTION:\n      return cmpFunction((const FunctionExpr *)lhs, (const FunctionExpr *)rhs);\n    case TO_ARRAY:\n      return cmpArrayExpr((const ArrayExpr *)lhs, (const ArrayExpr *)rhs);\n    case TO_GETFIELD:\n      return cmpGetField((const GetFieldExpr *)lhs, (const GetFieldExpr *)rhs);\n    case TO_GETSLOT:\n      return cmpGetSlot((const GetSlotExpr *)lhs, (const GetSlotExpr *)rhs);\n    case TO_CALL:\n      return cmpCallExpr((const CallExpr *)lhs, (const CallExpr *)rhs);\n    case TO_TERNARY:\n      return cmpTernary((const TerExpr *)lhs, (const TerExpr *)rhs);\n      //case TO_EXPR_MARK:\n    case TO_VAR:\n      return cmpVarDecl((const VarDecl *)lhs, (const VarDecl *)rhs);\n    case TO_PARAM:\n      return cmpValueDecl((const ValueDecl *)lhs, (const ValueDecl *)rhs);\n    case TO_CONST:\n      return cmpConst((const ConstDecl *)lhs, (const ConstDecl *)rhs);\n    case TO_DECL_GROUP:\n      return cmpDeclGroup((const DeclGroup *)lhs, (const DeclGroup *)rhs);\n    case TO_DESTRUCTURE:\n      return cmpDestructDecl((const DestructuringDecl *)lhs, (const DestructuringDecl *)rhs);\n    case TO_ENUM:\n      return cmpEnumDecl((const EnumDecl *)lhs, (const EnumDecl *)rhs);\n    case TO_SETFIELD:\n    case TO_SETSLOT:\n    default:\n      assert(0);\n      return false;\n    }\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/operator_classification.h",
    "content": "#pragma once\n\n#include \"compiler/ast.h\"\n\nnamespace SQCompilation\n{\n\ninline bool isSuspiciousNeighborOfNullCoalescing(TreeOp op) {\n  return (op == TO_3CMP || op == TO_ANDAND || op == TO_OROR || op == TO_IN || /*op == TO_NOTIN ||*/ op == TO_EQ || op == TO_NE || op == TO_LE ||\n    op == TO_LT || op == TO_GT || op == TO_GE /*|| op == TO_NOT*/ || op == TO_BNOT || op == TO_AND || op == TO_OR ||\n    op == TO_XOR || op == TO_DIV || op == TO_MOD || op == TO_INSTANCEOF || /*op == TO_QMARK ||*/ /*op == TO_NEG ||*/\n    op == TO_ADD || op == TO_MUL || op == TO_SHL || op == TO_SHR || op == TO_USHR);\n}\n\ninline bool isSuspiciousTernaryConditionOp(TreeOp op) {\n  return op == TO_ADD || op == TO_SUB || op == TO_MUL || op == TO_DIV || op == TO_MOD ||\n    op == TO_AND || op == TO_OR || op == TO_SHL || op == TO_SHR || op == TO_USHR || op == TO_3CMP || op == TO_NULLC;\n}\n\ninline bool isSuspiciousSameOperandsBinaryOp(TreeOp op) {\n  return op == TO_EQ || op == TO_LE || op == TO_LT || op == TO_GE || op == TO_GT || op == TO_NE ||\n    op == TO_ANDAND || op == TO_OROR || op == TO_SUB || op == TO_3CMP || op == TO_DIV || op == TO_MOD ||\n    op == TO_OR || op == TO_AND || op == TO_XOR || op == TO_SHL || op == TO_SHR || op == TO_USHR;\n}\n\ninline bool isBlockTerminatorStatement(TreeOp op) {\n  return op == TO_RETURN || op == TO_THROW || op == TO_BREAK || op == TO_CONTINUE;\n}\n\ninline bool isBooleanBinaryResultOperator(TreeOp op) {\n  return op == TO_NE || op == TO_EQ || (TO_GE <= op && op <= TO_IN);\n}\n\ninline bool isBooleanResultOperator(TreeOp op) {\n  return isBooleanBinaryResultOperator(op) || op == TO_NOT;\n}\n\ninline bool isArithOperator(TreeOp op) {\n  return op == TO_OROR || op == TO_ANDAND\n    || (TO_3CMP <= op && op <= TO_LT)\n    || (TO_USHR <= op && op <= TO_SUB)\n    || (TO_PLUSEQ <= op && op <= TO_MODEQ)\n    || op == TO_BNOT || op == TO_NEG || op == TO_INC;\n}\n\ninline bool isDivOperator(TreeOp op) {\n  return op == TO_DIV || op == TO_MOD || op == TO_DIVEQ || op == TO_MODEQ;\n}\n\ninline bool isPureArithOperator(TreeOp op) {\n  return (TO_USHR <= op && op <= TO_SUB) || (TO_PLUSEQ <= op && op <= TO_MODEQ);\n}\n\ninline bool isRelationOperator(TreeOp op) {\n  return TO_3CMP <= op && op <= TO_LT;\n}\n\ninline bool isBoolRelationOperator(TreeOp op) {\n  return TO_GE <= op && op <= TO_LT;\n}\n\ninline bool isBitwiseOperator(TreeOp op) {\n  return op == TO_OR || op == TO_AND || op == TO_XOR;\n}\n\ninline bool isBoolCompareOperator(TreeOp op) {\n  return op == TO_NE || op == TO_EQ || isBoolRelationOperator(op);\n}\n\ninline bool isCompareOperator(TreeOp op) {\n  return TO_NE <= op && op <= TO_LT;\n}\n\ninline bool isShiftOperator(TreeOp op) {\n  return op == TO_SHL || op == TO_SHR || op == TO_USHR;\n}\n\ninline bool isHigherShiftPriority(TreeOp op) {\n  return TO_MUL <= op && op <= TO_SUB;\n}\n\ninline bool isAssignOp(TreeOp op) {\n  return op == TO_ASSIGN || (TO_PLUSEQ <= op && op <= TO_MODEQ);\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/symbol_info.h",
    "content": "#pragma once\n\n#include \"compiler/ast.h\"\n\n\nnamespace SQCompilation\n{\n\nstruct ImportInfo {\n  int line;\n  int column;\n  const char *name;\n};\n\nenum SymbolKind {\n  SK_EXCEPTION,\n  SK_FUNCTION,\n  SK_CLASS,\n  SK_TABLE,\n  SK_VAR,\n  SK_BINDING,\n  SK_CONST,\n  SK_ENUM,\n  SK_ENUM_CONST,\n  SK_PARAM,\n  SK_FOREACH,\n  SK_EXTERNAL_BINDING,\n  SK_IMPORT\n};\n\nconst char *symbolContextName(SymbolKind k);\n\n\nstruct SymbolInfo {\n  union {\n    const Id *x;\n    const FunctionExpr *f;\n    const ClassExpr *k;\n    const TableMember *m;\n    const VarDecl *v;\n    const TableExpr *t;\n    const ParamDecl *p;\n    const EnumDecl *e;\n    const ConstDecl *c;\n    const EnumConst *ec;\n    const ExternalValueExpr *ev;\n    const ImportInfo *imp;\n  } declarator;\n\n  SymbolKind kind;\n\n  bool declared;\n  bool used;\n  bool usedAfterAssign;\n\n  const struct VarScope *ownedScope;\n\n  SymbolInfo(SymbolKind k) : kind(k), declarator() {\n    declared = true;\n    used = usedAfterAssign = false;\n    ownedScope = nullptr;\n  }\n\n  bool isConstant() const {\n    return kind != SK_VAR;\n  }\n\n  const Node *extractPointedNode() const {\n    switch (kind)\n    {\n    case SK_EXCEPTION:\n      return declarator.x;\n    case SK_FUNCTION:\n      // Return the Id node if available (points to identifier for diagnostics)\n      if (declarator.f && declarator.f->nameId())\n        return declarator.f->nameId();\n      return declarator.f;\n    case SK_CLASS:\n      return declarator.k;\n    case SK_TABLE:\n      return declarator.t;\n    case SK_VAR:\n    case SK_BINDING:\n    case SK_FOREACH:\n      // Return the Id node if available (points to identifier for diagnostics)\n      if (declarator.v && declarator.v->nameId())\n        return declarator.v->nameId();\n      return declarator.v;\n    case SK_CONST:\n      return declarator.c;\n    case SK_ENUM:\n      return declarator.e;\n    case SK_ENUM_CONST:\n      return declarator.ec->val;\n    case SK_PARAM:\n      return declarator.p;\n    case SK_EXTERNAL_BINDING:\n      return declarator.ev;\n    case SK_IMPORT:\n      return nullptr; // Import slots don't have a Node representation\n    default:\n      assert(0);\n      return nullptr;\n    }\n  }\n\n  const char *contextName() const {\n    return symbolContextName(kind);\n  }\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/value_ref.cpp",
    "content": "#include <assert.h>\n\n#include \"value_ref.h\"\n#include \"node_equal_checker.h\"\n\n\nnamespace SQCompilation\n{\n\nstatic const ValueRefState mergeMatrix[VRS_NUM_OF_STATES][VRS_NUM_OF_STATES] = {\n // VRS_EXPRESSION  VRS_INITIALIZED  VRS_MULTIPLE   VRS_UNKNOWN    VRS_DECLARED\n  { VRS_EXPRESSION, VRS_MULTIPLE,    VRS_MULTIPLE,  VRS_UNKNOWN,   VRS_MULTIPLE  }, // VRS_EXPRESSION\n  { VRS_MULTIPLE,   VRS_INITIALIZED, VRS_MULTIPLE,  VRS_UNKNOWN,   VRS_MULTIPLE  }, // VRS_INITIALIZED\n  { VRS_MULTIPLE,   VRS_MULTIPLE,    VRS_MULTIPLE,  VRS_UNKNOWN,   VRS_MULTIPLE  }, // VRS_MULTIPLE\n  { VRS_UNKNOWN,    VRS_UNKNOWN,     VRS_UNKNOWN,   VRS_UNKNOWN,   VRS_UNKNOWN   }, // VRS_UNKNOWN\n  { VRS_MULTIPLE,   VRS_MULTIPLE,    VRS_MULTIPLE,  VRS_UNKNOWN,   VRS_DECLARED  }  // VRS_DECLARED\n};\n\n\nvoid ValueRef::intersectValue(const ValueRef *other) {\n  assert(info == other->info);\n\n  flagsPositive &= other->flagsPositive;\n  flagsNegative &= other->flagsNegative;\n\n  assert((flagsNegative & flagsPositive) == 0);\n\n  assigned &= other->assigned;\n  if (lastAssigneeScope) {\n    if (other->lastAssigneeScope && other->lastAssigneeScope->depth > lastAssigneeScope->depth) {\n      lastAssigneeScope = other->lastAssigneeScope;\n    }\n  }\n  else {\n    lastAssigneeScope = other->lastAssigneeScope;\n  }\n\n  // TODO: intersect bounds\n\n  if (isConstant())\n    return;\n\n  if (!NodeEqualChecker().check(expression, other->expression)) {\n    kill(VRS_MULTIPLE, false);\n  }\n}\n\nvoid ValueRef::merge(const ValueRef *other) {\n  assert(info == other->info);\n\n  assigned &= other->assigned;\n  if (lastAssigneeScope) {\n    if (other->lastAssigneeScope && other->lastAssigneeScope->depth > lastAssigneeScope->depth) {\n      lastAssigneeScope = other->lastAssigneeScope;\n    }\n  }\n  else {\n    lastAssigneeScope = other->lastAssigneeScope;\n  }\n\n  if (state != other->state) {\n    ValueRefState k = mergeMatrix[other->state][state];\n    kill(k);\n    return;\n  }\n\n  if (isConstant()) {\n    assert(other->isConstant());\n    return;\n  }\n\n  if (!NodeEqualChecker().check(expression, other->expression)) {\n    kill(VRS_MULTIPLE);\n  }\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/value_ref.h",
    "content": "#pragma once\n\n#include <squirrel.h>\n#include \"var_scope.h\"\n#include \"symbol_info.h\"\n\n\nnamespace SQCompilation\n{\n\nstruct SymbolInfo;\nclass Expr;\n\nenum ValueRefState {\n  VRS_EXPRESSION,\n  VRS_INITIALIZED,\n  VRS_MULTIPLE,\n  VRS_UNKNOWN,\n  VRS_DECLARED,\n  VRS_NUM_OF_STATES\n};\n\n\nstruct ValueRef {\n\n  SymbolInfo *info;\n  enum ValueRefState state;\n  const Expr *expression;\n\n  /*\n    used to track mixed assignments\n    local x = 10 // eid = 1\n    let y = x    // eid = 2\n    x = 20       // eid = 3\n  */\n  int32_t evalIndex;\n\n  // Track aliasing: if this variable was initialized from another variable,\n  // store a reference to it so we can check its current flags dynamically.\n  const ValueRef *origin;\n  int32_t originEvalIndex;  // origin's evalIndex at the time of this declaration\n\n  ValueRef(SymbolInfo *i, int32_t eid)\n    : info(i), evalIndex(eid), state(), expression(nullptr)\n  {\n    assigned = false;\n    lastAssigneeScope = nullptr;\n    flagsPositive = flagsNegative = 0;\n    origin = nullptr;\n    originEvalIndex = -1;\n  }\n\n  bool hasValue() const {\n    return state == VRS_EXPRESSION || state == VRS_INITIALIZED;\n  }\n\n  bool isConstant() const {\n    return info->isConstant();\n  }\n\n  bool assigned;\n  const VarScope *lastAssigneeScope;\n\n  unsigned flagsPositive, flagsNegative;\n\n  void kill(ValueRefState k = VRS_UNKNOWN, bool clearFlags = true) {\n    if (!isConstant()) {\n      state = k;\n      expression = nullptr;\n    }\n    if (clearFlags) {\n      flagsPositive = 0;\n      flagsNegative = 0;\n    }\n  }\n\n  void intersectValue(const ValueRef *other);\n\n  void merge(const ValueRef *other);\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/var_scope.cpp",
    "content": "#include <assert.h>\n#include <vector>\n#include <algorithm>\n\n#include \"var_scope.h\"\n#include \"value_ref.h\"\n#include \"symbol_info.h\"\n#include \"naming.h\"\n#include \"checker_visitor.h\"\n#include \"compiler/compilationcontext.h\"\n#include \"compiler/sourceloc.h\"\n\nnamespace SQCompilation\n{\n\n\nvoid VarScope::copyFrom(const VarScope *other) {\n  VarScope *l = this;\n  const VarScope *r = other;\n\n  while (l) {\n    assert(l->owner == r->owner && \"Scope corruption\");\n\n    auto &thisSymbols = l->symbols;\n    auto &otherSymbols = r->symbols;\n    auto it = otherSymbols.begin();\n    auto ie = otherSymbols.end();\n\n    while (it != ie) {\n      thisSymbols[it->first] = it->second;\n      ++it;\n    }\n\n    l = l->parent;\n    r = r->parent;\n  }\n}\n\nvoid VarScope::intersectScopes(const VarScope *other) {\n  VarScope *l = this;\n  const VarScope *r = other;\n\n  while (l) {\n    assert(l->owner == r->owner && \"Scope corruption\");\n\n    auto &thisSymbols = l->symbols;\n    auto &otherSymbols = r->symbols;\n    auto it = otherSymbols.begin();\n    auto ie = otherSymbols.end();\n    auto te = thisSymbols.end();\n\n    while (it != ie) {\n      auto f = thisSymbols.find(it->first);\n      if (f != te) {\n        if (it->second->info == f->second->info)\n          f->second->intersectValue(it->second);\n      }\n      ++it;\n    }\n\n    l = l->parent;\n    r = r->parent;\n  }\n  evalId = std::max(evalId, other->evalId) + 1; // -V522\n}\n\n\nvoid VarScope::mergeUnbalanced(const VarScope *other) {\n  VarScope *lhs = this;\n  const VarScope *rhs = other;\n\n  while (lhs->depth > rhs->depth) {\n    lhs = lhs->parent;\n  }\n\n  while (rhs->depth > lhs->depth) {\n    rhs = rhs->parent;\n  }\n\n  lhs->merge(rhs);\n}\n\nvoid VarScope::merge(const VarScope *other) {\n  VarScope *l = this;\n  const VarScope *r = other;\n\n  while (l) {\n    assert(l->depth == r->depth && \"Scope corruption\");\n    assert(l->owner == r->owner && \"Scope corruption\");\n\n    auto &originSymbols = l->symbols;\n    const auto &branchSymbols = r->symbols;\n\n    for (const auto &kv : branchSymbols) {\n      auto it = originSymbols.find(kv.first);\n      if (it != originSymbols.end()) {\n        // Lambdas declared on the same line could have same names\n        if (it->second->info == kv.second->info) {\n          it->second->merge(kv.second);\n        }\n      }\n      // Otherwise (would be under `else`) the symbol only exists in branch\n      // (e.g., lambda created in ternary) - it's local to that branch,\n      // don't propagate to origin scope\n    }\n\n    l = l->parent;\n    r = r->parent;\n  }\n\n  evalId = std::max(evalId, other->evalId) + 1;\n}\n\nVarScope *VarScope::findScope(const FunctionExpr *own) {\n  VarScope *s = this;\n\n  while (s) {\n    if (s->owner == own) {\n      return s;\n    }\n    s = s->parent;\n  }\n\n  return nullptr;\n}\n\nVarScope *VarScope::copy(Arena *a, bool forClosure) const {\n  VarScope *parentCopy = parent ? parent->copy(a, forClosure) : nullptr;\n  void *mem = a->allocate(sizeof(VarScope));\n  VarScope *thisCopy = new(mem) VarScope(owner, parentCopy);\n\n  for (auto &kv : symbols) {\n    const char *k = kv.first;\n    ValueRef *v = kv.second;\n    void *mem = a->allocate(sizeof(ValueRef));\n    ValueRef *vcopy = new(mem) ValueRef(v->info, v->evalIndex);\n\n    if (!v->isConstant() && forClosure) {\n      // if we analyze closure we cannot rely on existed assignable values\n      vcopy->state = VRS_UNKNOWN;\n      vcopy->expression = nullptr;\n      vcopy->flagsNegative = vcopy->flagsPositive = 0;\n      vcopy->assigned = v->assigned;\n      vcopy->lastAssigneeScope = v->lastAssigneeScope;\n    }\n    else {\n      memcpy(vcopy, v, sizeof(ValueRef));\n      vcopy->assigned = false;\n      vcopy->lastAssigneeScope = nullptr;\n    }\n    thisCopy->symbols[k] = vcopy;\n  }\n\n  return thisCopy;\n}\n\n\nstatic SourceLoc getSymbolLocation(const SymbolInfo *info) {\n  if (info->kind == SK_IMPORT) {\n    const ImportInfo *imp = info->declarator.imp;\n    return {imp->line, imp->column};\n  }\n  const Node *node = info->extractPointedNode();\n  return {node->lineStart(), node->columnStart()}; //-V522\n}\n\nvoid VarScope::checkUnusedSymbols(CheckerVisitor *checker) {\n  std::vector<std::pair<const char *, ValueRef *>> sorted(symbols.begin(), symbols.end());\n  std::sort(sorted.begin(), sorted.end(), [](const auto &a, const auto &b) {\n    SourceLoc locA = getSymbolLocation(a.second->info);\n    SourceLoc locB = getSymbolLocation(b.second->info);\n    if (locA.line != locB.line)\n      return locA.line < locB.line;\n    return locA.column < locB.column;\n  });\n\n  for (auto &s : sorted) {\n    const char *n = s.first;\n    const ValueRef *v = s.second;\n\n    if (strcmp(n, \"this\") == 0 || n[0] == '@')\n      continue;\n\n    SymbolInfo *info = v->info;\n\n    if (info->kind == SK_ENUM_CONST)\n      continue;\n\n    if (!info->used && n[0] != '_') {\n      if (info->kind == SK_IMPORT) {\n        const ImportInfo *import = info->declarator.imp;\n        checker->reportImportSlot(import->line, import->column, import->name);\n      }\n      else {\n        checker->report(info->extractPointedNode(), DiagnosticsId::DI_DECLARED_NEVER_USED, info->contextName(), n);\n        // TODO: add hint for param/exception name about silencing it with '_' prefix\n      }\n    }\n    else if (info->used && n[0] == '_') {\n      if (info->kind == SK_PARAM || info->kind == SK_FOREACH)\n        checker->report(info->extractPointedNode(), DiagnosticsId::DI_INVALID_UNDERSCORE, info->contextName(), n);\n    }\n  }\n}\n\n}\n"
  },
  {
    "path": "squirrel/compiler/static_analyzer/var_scope.h",
    "content": "#pragma once\n\n#include \"compiler/ast.h\"\n#include \"analyzer_internal.h\"\n\n\nnamespace SQCompilation\n{\n\nstruct ValueRef;\nclass CheckerVisitor;\n\n\nstruct VarScope\n{\n  VarScope(const FunctionExpr *o, VarScope *p = nullptr)\n    : owner(o), parent(p), depth(p ? p->depth + 1 : 0), evalId(p ? p->evalId + 1 : 0)\n  {}\n\n  ~VarScope()\n  {\n    if (parent)\n      parent->~VarScope();\n    symbols.clear();\n  }\n\n\n  int32_t evalId;\n  const int32_t depth;\n  const FunctionExpr *owner;\n  VarScope *parent;\n  std::unordered_map<const char *, ValueRef *, StringHasher, StringEqualer> symbols;\n\n  void intersectScopes(const VarScope *other);\n\n  void merge(const VarScope *other);\n  VarScope *copy(Arena *a, bool forClosure = false) const;\n  void copyFrom(const VarScope *other);\n\n  void mergeUnbalanced(const VarScope *other);\n\n  VarScope *findScope(const FunctionExpr *own);\n  void checkUnusedSymbols(CheckerVisitor *v);\n};\n\n}\n"
  },
  {
    "path": "squirrel/compiler/typeinference.cpp",
    "content": "#include \"sqpcheader.h\"\n#ifndef NO_COMPILER\n#include \"opcodes.h\"\n#include \"sqstring.h\"\n#include \"sqfuncproto.h\"\n#include \"sqfuncstate.h\"\n#include \"codegen.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"sqclass.h\"\n#include \"sqclosure.h\"\n#include \"sqtypeparser.h\"\n\n\nnamespace SQCompilation {\n\n\nExpr *CodeGenVisitor::deparen(Expr *e) const {\n    if (e->op() == TO_PAREN)\n        return deparen(((UnExpr *)e)->argument());\n    else\n        return e;\n}\n\n\nunsigned CodeGenVisitor::inferExprTypeMask(Expr *expr) {\n    if (expr->isTypeInferred())\n        return expr->getTypeMask();\n\n    unsigned mask = inferExprTypeMaskImpl(expr);\n    expr->setTypeMask(mask);\n    expr->setTypeInferred();\n    return mask;\n}\n\n\nunsigned CodeGenVisitor::inferExprTypeMaskImpl(Expr *expr) {\n    switch (expr->op()) {\n    case TO_LITERAL: {\n        LiteralExpr *lit = expr->asLiteral();\n        switch (lit->kind()) {\n        case LK_INT:    return _RT_INTEGER;\n        case LK_FLOAT:  return _RT_FLOAT;\n        case LK_STRING: return _RT_STRING;\n        case LK_BOOL:   return _RT_BOOL;\n        case LK_NULL:   return _RT_NULL;\n        }\n        return ~0u;\n    }\n\n    case TO_TYPEOF:\n        return _RT_STRING;\n\n    case TO_NEG: {\n        unsigned argMask = inferExprTypeMask(static_cast<UnExpr *>(expr)->argument());\n        if (argMask == ~0u) return ~0u;\n        if (argMask & _RT_INSTANCE) return ~0u; // _unm metamethod\n        return argMask & (_RT_INTEGER | _RT_FLOAT);\n    }\n\n    case TO_INC: {\n        unsigned argMask = inferExprTypeMask(static_cast<IncExpr *>(expr)->argument());\n        if (argMask == ~0u) return ~0u;\n        if (argMask & _RT_INSTANCE) return ~0u; // metamethods\n        return argMask & (_RT_INTEGER | _RT_FLOAT);\n    }\n\n    // Comparisons -> bool\n    case TO_EQ:\n    case TO_NE:\n    case TO_GT:\n    case TO_GE:\n    case TO_LT:\n    case TO_LE:\n    case TO_INSTANCEOF:\n    case TO_IN:\n    case TO_NOT:\n        return _RT_BOOL;\n\n    case TO_3CMP:\n    // Bitwise -> integer\n    case TO_AND: case TO_OR: case TO_XOR:\n    case TO_SHL: case TO_SHR: case TO_USHR:\n    case TO_BNOT:\n        return _RT_INTEGER;\n\n    // Arithmetic\n    case TO_MUL: case TO_DIV: case TO_SUB: case TO_MOD: {\n        BinExpr *bin = expr->asBinExpr();\n        unsigned lm = inferExprTypeMask(bin->lhs());\n        unsigned rm = inferExprTypeMask(bin->rhs());\n        if (lm == ~0u || rm == ~0u) return ~0u;\n        if ((lm | rm) & _RT_INSTANCE) return ~0u; // _mul/_div/_sub/_modulo metamethods\n        if ((lm & ~(_RT_INTEGER | _RT_FLOAT)) || (rm & ~(_RT_INTEGER | _RT_FLOAT)))\n            return ~0u; // non-numeric operands\n        if (lm == _RT_INTEGER && rm == _RT_INTEGER)\n            return _RT_INTEGER;\n        if ((lm & (_RT_INTEGER | _RT_FLOAT)) && (rm & (_RT_INTEGER | _RT_FLOAT))) {\n            if ((lm & _RT_FLOAT) || (rm & _RT_FLOAT))\n                return _RT_FLOAT;\n            return _RT_INTEGER | _RT_FLOAT;\n        }\n        return _RT_INTEGER | _RT_FLOAT;\n    }\n\n    case TO_ADD: {\n        BinExpr *bin = expr->asBinExpr();\n        unsigned lm = inferExprTypeMask(bin->lhs());\n        unsigned rm = inferExprTypeMask(bin->rhs());\n        if (lm == ~0u || rm == ~0u) return ~0u;\n        if ((lm | rm) & _RT_INSTANCE) return ~0u; // _add metamethod\n        // String concat: if either side is definitely string, result is string\n        if (lm == _RT_STRING || rm == _RT_STRING)\n            return _RT_STRING;\n        if ((lm & ~(_RT_INTEGER | _RT_FLOAT)) || (rm & ~(_RT_INTEGER | _RT_FLOAT)))\n            return ~0u; // non-numeric/non-string operands\n        if (lm == _RT_INTEGER && rm == _RT_INTEGER)\n            return _RT_INTEGER;\n        if ((lm & _RT_FLOAT) || (rm & _RT_FLOAT))\n            return _RT_FLOAT;\n        return _RT_INTEGER | _RT_FLOAT;\n    }\n\n\n    // Logical: short-circuit, result is one of the operands\n    case TO_OROR: case TO_ANDAND: {\n        BinExpr *bin = expr->asBinExpr();\n        unsigned lm = inferExprTypeMask(bin->lhs());\n        unsigned rm = inferExprTypeMask(bin->rhs());\n        if (lm == ~0u || rm == ~0u) return ~0u;\n        return lm | rm;\n    }\n\n    // Null-coalesce: lhs if non-null, else rhs\n    case TO_NULLC: {\n        BinExpr *bin = expr->asBinExpr();\n        unsigned lm = inferExprTypeMask(bin->lhs());\n        unsigned rm = inferExprTypeMask(bin->rhs());\n        if (lm == ~0u || rm == ~0u) return ~0u;\n        return (lm & ~_RT_NULL) | rm;\n    }\n\n    // Ternary\n    case TO_TERNARY: {\n        TerExpr *ter = static_cast<TerExpr *>(expr);\n        unsigned bm = inferExprTypeMask(ter->b());\n        unsigned cm = inferExprTypeMask(ter->c());\n        if (bm == ~0u || cm == ~0u) return ~0u;\n        // Null-check narrowing: strip _RT_NULL from the appropriate branch\n        // to avoid false positives with patterns like `x != null ? x : default`\n        Expr *cond = deparen(ter->a());\n        if (cond->op() == TO_NE) {\n            BinExpr *bin = cond->asBinExpr();\n            if ((bin->lhs()->op() == TO_LITERAL && bin->lhs()->asLiteral()->kind() == LK_NULL) ||\n                (bin->rhs()->op() == TO_LITERAL && bin->rhs()->asLiteral()->kind() == LK_NULL))\n                bm &= ~_RT_NULL;\n        } else if (cond->op() == TO_EQ) {\n            BinExpr *bin = cond->asBinExpr();\n            if ((bin->lhs()->op() == TO_LITERAL && bin->lhs()->asLiteral()->kind() == LK_NULL) ||\n                (bin->rhs()->op() == TO_LITERAL && bin->rhs()->asLiteral()->kind() == LK_NULL))\n                cm &= ~_RT_NULL;\n        }\n        return bm | cm;\n    }\n\n    // Identifiers: look up declared type\n    case TO_ID: {\n        Id *id = expr->asId();\n        SQObjectPtr nameObj(_fs->CreateString(id->name()));\n        SQCompiletimeVarInfo varInfo;\n        if (_fs->GetLocalVariable(nameObj, varInfo) != -1 ||\n            _fs->GetOuterVariable(nameObj, varInfo) != -1) {\n            // If the variable was initialized with a known-type expression, use that\n            if (varInfo.initializer && (varInfo.var_flags & (VF_ASSIGNABLE | VF_PARAM)) == 0) {\n                unsigned initMask = inferExprTypeMask(varInfo.initializer);\n                if (initMask != ~0u) {\n                    return initMask;\n                }\n            }\n            // For functions initialized with pure calls, check the initializer\n            if (varInfo.initializer && (varInfo.var_flags & VF_INIT_WITH_PURE)) {\n                if (varInfo.initializer->op() == TO_CALL) {\n                    CallExpr *call = varInfo.initializer->asCallExpr();\n                    Expr *callee = call->callee();\n                    if (callee->op() == TO_ID) {\n                        SQObjectPtr calleeName(_fs->CreateString(callee->asId()->name()));\n                        SQCompiletimeVarInfo calleeInfo;\n                        if ((_fs->GetLocalVariable(calleeName, calleeInfo) != -1 ||\n                             _fs->GetOuterVariable(calleeName, calleeInfo) != -1) &&\n                            calleeInfo.initializer && calleeInfo.initializer->op() == TO_FUNCTION) {\n                            return calleeInfo.initializer->asFunctionExpr()->getResultTypeMask();\n                        }\n                    }\n                }\n            }\n            return varInfo.type_mask;\n        }\n        // Check named constants (const s = \"err\")\n        SQObjectPtr constant;\n        if (IsConstant(nameObj, constant)) {\n            SQObjectType ctype = sq_type(constant);\n            switch (ctype) {\n            case OT_INTEGER:       return _RT_INTEGER;\n            case OT_FLOAT:         return _RT_FLOAT;\n            case OT_STRING:        return _RT_STRING;\n            case OT_BOOL:          return _RT_BOOL;\n            case OT_NULL:          return _RT_NULL;\n            case OT_ARRAY:         return _RT_ARRAY;\n            case OT_TABLE:         return _RT_TABLE;\n            case OT_CLOSURE:       return _RT_CLOSURE;\n            case OT_NATIVECLOSURE: return _RT_NATIVECLOSURE;\n            case OT_CLASS:         return _RT_CLASS;\n            case OT_INSTANCE:      return _RT_INSTANCE;\n            default:               return ~0u;\n            }\n        }\n        return ~0u;\n    }\n\n    // Function call: try to determine return type\n    case TO_CALL: {\n        CallExpr *call = expr->asCallExpr();\n        Expr *callee = call->callee();\n\n        // freeze(x) returns the same type as x\n        if (isFreezeCall(expr))\n            return inferExprTypeMask(call->arguments()[0]);\n\n        unsigned retMask = ~0u;\n\n        if (callee->op() == TO_ID) {\n            SQObjectPtr calleeName(_fs->CreateString(callee->asId()->name()));\n            SQCompiletimeVarInfo calleeInfo;\n            if ((_fs->GetLocalVariable(calleeName, calleeInfo) != -1 ||\n                 _fs->GetOuterVariable(calleeName, calleeInfo) != -1) &&\n                calleeInfo.initializer) {\n                if (calleeInfo.initializer->op() == TO_FUNCTION) {\n                    retMask = calleeInfo.initializer->asFunctionExpr()->getResultTypeMask();\n                } else if (calleeInfo.initializer->op() == TO_CLASS) {\n                    retMask = _RT_INSTANCE;\n                }\n            }\n            // Check named constants (const function [pure] ...)\n            if (retMask == ~0u) {\n                SQObjectPtr constant;\n                if (IsConstant(calleeName, constant)) {\n                    if (sq_type(constant) == OT_CLOSURE) {\n                        SQClosure *cls = _closure(constant);\n                        if (cls->_function)\n                            retMask = cls->_function->_result_type_mask;\n                    } else if (sq_type(constant) == OT_NATIVECLOSURE) {\n                        SQNativeClosure *nc = _nativeclosure(constant);\n                        retMask = nc->_result_type_mask;\n                    }\n                }\n            }\n        }\n        else if (callee->op() == TO_FUNCTION) {\n            retMask = callee->asFunctionExpr()->getResultTypeMask();\n        }\n\n        if (call->isNullable() && retMask != ~0u)\n            retMask |= _RT_NULL;\n        return retMask;\n    }\n\n    // Container/type literals\n    case TO_ARRAY:\n        return _RT_ARRAY;\n\n    case TO_CLASS:\n        return _RT_CLASS;\n\n    case TO_FUNCTION:\n        return _RT_CLOSURE | _RT_NATIVECLOSURE;\n\n    case TO_TABLE:\n    case TO_ROOT_TABLE_ACCESS:\n        return _RT_TABLE;\n\n\n    case TO_PAREN:\n    case TO_CLONE:\n    // Static memo wraps an expression\n    case TO_STATIC_MEMO:\n    // Inline const wraps a literal\n    case TO_INLINE_CONST:\n        return inferExprTypeMask(static_cast<UnExpr *>(expr)->argument());\n\n    // Comma expression returns last value\n    case TO_COMMA: {\n        CommaExpr *comma = static_cast<CommaExpr *>(expr);\n        const auto &exprs = comma->expressions();\n        if (!exprs.empty())\n            return inferExprTypeMask(exprs.back());\n        return ~0u;\n    }\n\n\n    case TO_DELETE:\n    case TO_RESUME:\n    // Compound assign are complex; fall through to runtime\n    case TO_PLUSEQ:\n    case TO_MINUSEQ:\n    case TO_MULEQ:\n    case TO_DIVEQ:\n    case TO_MODEQ:\n    // Unknown at compile time\n    case TO_GETFIELD:\n    case TO_GETSLOT:\n    case TO_SETFIELD:\n    case TO_SETSLOT:\n    case TO_BASE:\n    case TO_ASSIGN: case TO_NEWSLOT:\n    case TO_EXTERNAL_VALUE:\n    case TO_CODE_BLOCK_EXPR:\n    default:\n        return ~0u;\n    }\n}\n\n\nbool CodeGenVisitor::checkInferredType(Node *reportNode, Expr *expr, unsigned declaredMask) {\n#if SQ_RUNTIME_TYPE_CHECK\n    if (declaredMask == ~0u)\n        return false;\n\n    unsigned inferredMask = inferExprTypeMask(expr);\n    if (inferredMask != ~0u && (inferredMask & ~declaredMask) != 0) {\n        char inferredBuf[160], declaredBuf[160];\n        sq_stringify_type_mask(inferredBuf, sizeof(inferredBuf), inferredMask);\n        sq_stringify_type_mask(declaredBuf, sizeof(declaredBuf), declaredMask);\n        reportDiagnostic(reportNode, DiagnosticsId::DI_INFERRED_TYPE_MISMATCH,\n                         inferredBuf, declaredBuf);\n        return false;\n    }\n    return inferredMask != ~0u;\n#else\n    (void)reportNode;\n    (void)expr;\n    (void)declaredMask;\n    return false;\n#endif\n}\n\n\n} // namespace SQCompilation\n\n#endif // NO_COMPILER\n"
  },
  {
    "path": "squirrel/opcodes.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQOPCODES_H_\n#define _SQOPCODES_H_\n\n#define MAX_FUNC_STACKSIZE 0xFF\n#define MAX_LITERALS ((SQInteger)0x7FFFFFFF)\n\n#define STATIC_MEMO_AUTO_FLAG  0x8000\n#define STATIC_MEMO_IDX_MASK   0x7FFF\n\nenum BitWiseOP {\n    BW_AND = 0,\n    BW_OR = 2,\n    BW_XOR = 3,\n    BW_SHIFTL = 4,\n    BW_SHIFTR = 5,\n    BW_USHIFTR = 6\n};\n\nenum CmpOP {\n    CMP_G = 0,\n    CMP_GE = 2,\n    CMP_L = 3,\n    CMP_LE = 4,\n    CMP_3W = 5\n};\n\nenum NewObjectType {\n    NEWOBJ_TABLE = 0,\n    NEWOBJ_ARRAY = 1,\n    NEWOBJ_CLASS = 2\n};\n\nenum AppendArrayType {\n    AAT_STACK = 0,\n    AAT_LITERAL = 1,\n    AAT_INT = 2,\n    AAT_FLOAT = 3,\n    AAT_BOOL = 4\n};\n\n\n#define SQ_OPCODES_LIST \\\n    SQ_OPCODE(_OP_DATA_NOP) \\\n    SQ_OPCODE(_OP_LOAD) \\\n    SQ_OPCODE(_OP_LOADINT) \\\n    SQ_OPCODE(_OP_LOADFLOAT) \\\n    SQ_OPCODE(_OP_DLOAD) \\\n    SQ_OPCODE(_OP_TAILCALL) \\\n    SQ_OPCODE(_OP_CALL) \\\n    SQ_OPCODE(_OP_PREPCALL) \\\n    SQ_OPCODE(_OP_PREPCALLK) \\\n    SQ_OPCODE(_OP_GETK) \\\n    SQ_OPCODE(_OP_MOVE) \\\n    SQ_OPCODE(_OP_NEWSLOT) \\\n    SQ_OPCODE(_OP_NEWSLOTK) \\\n    SQ_OPCODE(_OP_DELETE) \\\n    SQ_OPCODE(_OP_SET) \\\n    SQ_OPCODE(_OP_SETK)\\\n    SQ_OPCODE(_OP_SETI)\\\n    SQ_OPCODE(_OP_GET) \\\n    SQ_OPCODE(_OP_SET_LITERAL) \\\n    SQ_OPCODE(_OP_GET_LITERAL) \\\n    SQ_OPCODE(_OP_EQ) \\\n    SQ_OPCODE(_OP_NE) \\\n    SQ_OPCODE(_OP_ADD) \\\n    SQ_OPCODE(_OP_ADDI) \\\n    SQ_OPCODE(_OP_SUB) \\\n    SQ_OPCODE(_OP_MUL) \\\n    SQ_OPCODE(_OP_DIV) \\\n    SQ_OPCODE(_OP_MOD) \\\n    SQ_OPCODE(_OP_BITW) \\\n    SQ_OPCODE(_OP_RETURN) \\\n    SQ_OPCODE(_OP_LOADNULLS) \\\n    SQ_OPCODE(_OP_LOADROOT) \\\n    SQ_OPCODE(_OP_LOADBOOL) \\\n    SQ_OPCODE(_OP_DMOVE) \\\n    SQ_OPCODE(_OP_JMP) \\\n    SQ_OPCODE(_OP_JCMP) \\\n    SQ_OPCODE(_OP_JCMPI) \\\n    SQ_OPCODE(_OP_JCMPF) \\\n    SQ_OPCODE(_OP_JCMPK) \\\n    SQ_OPCODE(_OP_JZ) \\\n    SQ_OPCODE(_OP_SETOUTER) \\\n    SQ_OPCODE(_OP_GETOUTER) \\\n    SQ_OPCODE(_OP_NEWOBJ) \\\n    SQ_OPCODE(_OP_APPENDARRAY) \\\n    SQ_OPCODE(_OP_COMPARITH) \\\n    SQ_OPCODE(_OP_COMPARITH_K) \\\n    SQ_OPCODE(_OP_INC) \\\n    SQ_OPCODE(_OP_INCL) \\\n    SQ_OPCODE(_OP_PINC) \\\n    SQ_OPCODE(_OP_PINCL) \\\n    SQ_OPCODE(_OP_CMP) \\\n    SQ_OPCODE(_OP_EXISTS) \\\n    SQ_OPCODE(_OP_INSTANCEOF) \\\n    SQ_OPCODE(_OP_AND) \\\n    SQ_OPCODE(_OP_OR) \\\n    SQ_OPCODE(_OP_NEG) \\\n    SQ_OPCODE(_OP_NOT) \\\n    SQ_OPCODE(_OP_BWNOT) \\\n    SQ_OPCODE(_OP_CLOSURE) \\\n    SQ_OPCODE(_OP_YIELD) \\\n    SQ_OPCODE(_OP_RESUME) \\\n    SQ_OPCODE(_OP_PREFOREACH) \\\n    SQ_OPCODE(_OP_POSTFOREACH) \\\n    SQ_OPCODE(_OP_FOREACH) \\\n    SQ_OPCODE(_OP_CLONE) \\\n    SQ_OPCODE(_OP_TYPEOF) \\\n    SQ_OPCODE(_OP_PUSHTRAP) \\\n    SQ_OPCODE(_OP_POPTRAP) \\\n    SQ_OPCODE(_OP_THROW) \\\n    SQ_OPCODE(_OP_NEWSLOTA) \\\n    SQ_OPCODE(_OP_GETBASE) \\\n    SQ_OPCODE(_OP_CLOSE) \\\n    SQ_OPCODE(_OP_NULLCOALESCE) \\\n    SQ_OPCODE(_OP_NULLCALL) \\\n    SQ_OPCODE(_OP_LOADCALLEE) \\\n    SQ_OPCODE(_OP_PATCH_DOCOBJ) \\\n    SQ_OPCODE(_OP_LOAD_STATIC_MEMO) \\\n    SQ_OPCODE(_OP_SAVE_STATIC_MEMO) \\\n    SQ_OPCODE(_OP_FREEZE) \\\n    SQ_OPCODE(_OP_CHECK_TYPE) \\\n\n\n#define SQ_OPCODE(id) id,\n\nenum SQOpcode\n{\n    SQ_OPCODES_LIST\n};\n\n#undef SQ_OPCODE\n\nstruct SQInstructionDesc {\n    const char *name;\n};\n\nstruct SQInstruction\n{\n    SQInstruction(){}; //-V730\n    SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0)\n    {   op = (unsigned char)_op;\n        _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1;\n        _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3;\n    }\n\n    SQInstruction(SQOpcode _op,SQInteger a0,float a1=0,SQInteger a2=0,SQInteger a3=0)\n    {   op = (unsigned char)_op;\n        _arg0 = (unsigned char)a0;_farg1 = a1;\n        _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3;\n    }\n\n    union {\n        SQInt32 _arg1;\n        float _farg1;\n    };\n    unsigned char op;\n    unsigned char _arg0;\n    unsigned char _arg2;\n    unsigned char _arg3;\n    int _sarg0() const {return (signed char)_arg0;}\n    int _sarg2() const {return (signed char)_arg2;}\n    int _sarg3() const {return (signed char)_arg3;}\n};\n\n#include \"squtils.h\"\ntypedef sqvector<SQInstruction> SQInstructionVec;\n\n#define NEW_SLOT_STATIC_FLAG        0x02\n\n#define OP_GET_FLAG_ALLOW_TYPE_METHODS  0x01\n#define OP_GET_FLAG_NO_ERROR            0x02\n#define OP_GET_FLAG_KEEP_VAL            0x04 //< only used with OP_GET_FLAG_NO_ERROR\n#define OP_GET_FLAG_TYPE_METHODS_ONLY   0x08\n\ninline int sq_opcode_length(int op) {\n    return (op == _OP_SET_LITERAL || op == _OP_GET_LITERAL) ? 2 : 1;\n}\n\ninline bool sq_is_pure_op(int op) {\n    return\n        op != _OP_SETOUTER &&\n        op != _OP_GETOUTER &&\n        op != _OP_SET_LITERAL &&\n        op != _OP_SET &&\n        op != _OP_SETI &&\n        op != _OP_SETK &&\n        op != _OP_CLOSURE &&\n        op != _OP_TAILCALL &&\n        op != _OP_CALL &&\n        op != _OP_NULLCALL &&\n        op != _OP_PREPCALL &&\n        op != _OP_PREPCALLK &&\n        op != _OP_NEWOBJ &&\n        op != _OP_APPENDARRAY &&\n        op != _OP_NEWSLOT &&\n        op != _OP_NEWSLOTK &&\n        op != _OP_NEWSLOTA &&\n        op != _OP_DELETE &&\n        op != _OP_YIELD &&\n        op != _OP_RESUME &&\n        op != _OP_CLONE &&\n        op != _OP_PUSHTRAP &&\n        op != _OP_POPTRAP &&\n        op != _OP_THROW &&\n        op != _OP_CLOSE &&\n        op != _OP_GETBASE;\n}\n\n#endif // _SQOPCODES_H_\n"
  },
  {
    "path": "squirrel/sqapi.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"squserdata.h\"\n#include \"sqclass.h\"\n#include \"compiler/sqtypeparser.h\"\n#include \"compiler/compiler.h\"\n#include \"compiler/sqfuncstate.h\"\n#include \"compiler/arena.h\"\n#include \"compiler/ast.h\"\n#include \"ast_tools/ast_indent_render.h\"\n#include \"compiler/static_analyzer/analyzer.h\"\n#include \"compiler/static_analyzer/config.h\"\n\nstatic_assert(sizeof(SQObject) == sizeof(SQObjectPtr),\n    \"SQObjectPtr must not add data members beyond SQObject\");\n\nSQUIRREL_API SQBool sq_tracevar(HSQUIRRELVM v, const HSQOBJECT *container, const HSQOBJECT * key, char * buf, int buf_size)\n{\n  return v->GetVarTrace(SQObjectPtr(*container), SQObjectPtr(*key), buf, buf_size);\n}\n\nstatic bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o)\n{\n    *o = &stack_get(v,idx);\n    if(sq_type(**o) != type){\n        SQObjectPtr oval(v->PrintObjVal(**o));\n        v->Raise_Error(\"wrong argument type, expected '%s' got '%s'\",IdType2Name(type),_stringval(oval));\n        return false;\n    }\n    return true;\n}\n\n#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; }\n\n#define sq_aux_paramscheck(v,count) \\\n{ \\\n    if(sq_gettop(v) < count){ v->Raise_Error(\"not enough params in the stack\"); return SQ_ERROR; }\\\n}\n\nusing namespace SQCompilation;\n\nSQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)\n{\n    SQUnsignedInteger buf_size = 100 *sizeof(char);\n    scsprintf(_ss(v)->GetScratchPad(buf_size), buf_size, \"unexpected type %s\", IdType2Name(type));\n    return sq_throwerror(v, _ss(v)->GetScratchPad(-1));\n}\n\nHSQUIRRELVM sq_open(SQInteger initialstacksize)\n{\n    SQAllocContext allocctx = nullptr;\n    sq_vm_init_alloc_context(&allocctx);\n\n    SQSharedState *ss = (SQSharedState *)SQ_MALLOC(allocctx, sizeof(SQSharedState));\n    new (ss) SQSharedState(allocctx);\n    ss->Init();\n\n    SQVM *v = (SQVM *)SQ_MALLOC(allocctx, sizeof(SQVM));\n    new (v) SQVM(ss);\n    ss->_root_vm = v;\n    sq_vm_assign_to_alloc_context(allocctx, v);\n    if(v->Init(NULL, initialstacksize)) {\n        return v;\n    }\n    sq_delete(allocctx, v, SQVM);\n    sq_vm_destroy_alloc_context(&allocctx);\n    return NULL;\n}\n\nHSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)\n{\n    SQSharedState *ss;\n    SQVM *v;\n    ss=_ss(friendvm);\n\n    v= (SQVM *)SQ_MALLOC(ss->_alloc_ctx, sizeof(SQVM));\n    new (v) SQVM(ss);\n\n    if(v->Init(friendvm, initialstacksize)) {\n        friendvm->Push(SQObjectPtr(v));\n        return v;\n    } else {\n        sq_delete(ss->_alloc_ctx, v, SQVM);\n        return NULL;\n    }\n}\n\nSQInteger sq_getvmstate(HSQUIRRELVM v)\n{\n    if(v->_suspended)\n        return SQ_VMSTATE_SUSPENDED;\n    else {\n        if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING;\n        else return SQ_VMSTATE_IDLE;\n    }\n}\n\nvoid sq_seterrorhandler(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v, -1);\n    if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {\n        v->_errorhandler = o;\n        v->Pop();\n    }\n}\n\nHSQOBJECT sq_geterrorhandler(HSQUIRRELVM v)\n{\n  return v->_errorhandler;\n}\n\n\nSQGETTHREAD sq_set_thread_id_function(HSQUIRRELVM v, SQGETTHREAD func)\n{\n    SQGETTHREAD res = v->_get_current_thread_id_func;\n    v->_get_current_thread_id_func = func;\n    return res;\n}\n\nSQSQCALLHOOK sq_set_sq_call_hook(HSQUIRRELVM v, SQSQCALLHOOK hook)\n{\n    SQSQCALLHOOK res = v->_sq_call_hook;\n    v->_sq_call_hook = hook;\n    return res;\n}\n\nSQWATCHDOGHOOK sq_set_watchdog_hook(HSQUIRRELVM v, SQWATCHDOGHOOK hook)\n{\n    SQWATCHDOGHOOK res = v->_watchdog_hook;\n    v->_watchdog_hook = hook;\n    return res;\n}\n\nvoid sq_kick_watchdog(HSQUIRRELVM v)\n{\n    if (v->_watchdog_hook)\n        v->_watchdog_hook(v, true);\n}\n\nSQInteger sq_set_watchdog_timeout_msec(HSQUIRRELVM v, SQInteger timeout)\n{\n    SQInteger prevTimeout = _ss(v)->watchdog_threshold_msec;\n    _ss(v)->watchdog_threshold_msec = SQUnsignedInteger32(timeout < 0 ? 0 : timeout);\n    sq_kick_watchdog(v);\n    return prevTimeout;\n}\n\n\n\nvoid sq_forbidglobalconstrewrite(HSQUIRRELVM v, SQBool on)\n{\n    if (on)\n        _ss(v)->defaultLangFeatures |= LF_FORBID_GLOBAL_CONST_REWRITE;\n    else\n        _ss(v)->defaultLangFeatures &= ~LF_FORBID_GLOBAL_CONST_REWRITE;\n}\n\nvoid sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook)\n{\n    v->_debughook_native = hook;\n    v->_debughook_closure.Null();\n    v->_debughook = hook?true:false;\n}\n\nvoid sq_setdebughook(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v,-1);\n    if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {\n        v->_debughook_closure = o;\n        v->_debughook_native = NULL;\n        v->_debughook = !sq_isnull(o);\n        v->Pop();\n    }\n}\n\nSQCOMPILELINEHOOK sq_set_compile_line_hook(HSQUIRRELVM v, SQCOMPILELINEHOOK hook)\n{\n    SQCOMPILELINEHOOK res = v->_compile_line_hook;\n    v->_compile_line_hook = hook;\n    return res;\n}\n\nvoid sq_close(HSQUIRRELVM v)\n{\n    SQSharedState *ss = _ss(v);\n    _thread(ss->_root_vm)->Finalize();\n    SQAllocContext allocctx = ss->_alloc_ctx;\n    sq_delete(allocctx, ss, SQSharedState);\n    sq_vm_destroy_alloc_context(&allocctx);\n}\n\nSQRESULT sq_compile(HSQUIRRELVM v, const char *s, SQInteger size, const char *sourcename, SQBool raiseerror, const HSQOBJECT *bindings)\n{\n    SQObjectPtr o;\n#ifndef NO_COMPILER\n    if (Compile(v, s, size, bindings, sourcename, o, raiseerror ? true : false)) {\n        v->Push(SQObjectPtr(SQClosure::Create(_ss(v), _funcproto(o))));\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n#else\n    return sq_throwerror(v,\"this is a no compiler build\");\n#endif\n}\n\nvoid sq_lineinfo_in_expressions(HSQUIRRELVM v, SQBool enable)\n{\n    _ss(v)->_lineInfoInExpressions = enable ? true : false;\n}\n\nvoid sq_enablevartrace(HSQUIRRELVM v, SQBool enable)\n{\n    _ss(v)->_varTraceEnabled = enable ? true : false;\n}\n\nSQBool sq_isvartracesupported()\n{\n#if SQ_VAR_TRACE_ENABLED == 1\n    return SQTrue;\n#else\n    return SQFalse;\n#endif\n}\n\nvoid sq_setcompilationoption(HSQUIRRELVM v, enum CompilationOptions co, bool value) {\n  if (value)\n    _ss(v)->enableCompilationOption(co);\n  else\n    _ss(v)->disableCompilationOption(co);\n}\n\nbool sq_checkcompilationoption(HSQUIRRELVM v, enum CompilationOptions co) {\n  return _ss(v)->checkCompilationOption(co);\n}\n\nvoid sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)\n{\n    _ss(v)->_notifyallexceptions = enable?true:false;\n}\n\nvoid sq_addref_refcounted(HSQUIRRELVM v,HSQOBJECT *po)\n{\n    assert(ISREFCOUNTED(sq_type(*po)));\n#ifdef NO_GARBAGE_COLLECTOR\n    __AddRef(po->_type,po->_unVal);\n#else\n    _ss(v)->_refs_table.AddRef(*po);\n#endif\n}\n\nSQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po)\n{\n    if(!ISREFCOUNTED(sq_type(*po))) return 0;\n#ifdef NO_GARBAGE_COLLECTOR\n   return po->_unVal.pRefCounted->_uiRef;\n#else\n   return _ss(v)->_refs_table.GetRefCount(*po);\n#endif\n}\n\nSQBool sq_release_refcounted(HSQUIRRELVM v,HSQOBJECT *po)\n{\n    assert(ISREFCOUNTED(sq_type(*po)));\n#ifdef NO_GARBAGE_COLLECTOR\n    bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? SQTrue : SQFalse;\n    __Release(po->_type,po->_unVal);\n    return ret; //the ret val doesn't work(and cannot be fixed)\n#else\n    return _ss(v)->_refs_table.Release(*po);\n#endif\n}\n\nSQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM SQ_UNUSED_ARG(v), const HSQOBJECT *po)\n{\n    if (!ISREFCOUNTED(sq_type(*po))) return 0;\n    return po->_unVal.pRefCounted->_uiRef;\n}\n\nconst char *sq_objtostring(const HSQOBJECT *o)\n{\n    if(sq_type(*o) == OT_STRING) {\n        return _stringval(*o);\n    }\n    return NULL;\n}\n\nSQInteger sq_objtointeger(const HSQOBJECT *o)\n{\n    if(sq_isnumeric(*o)) {\n        return tointeger(*o);\n    }\n    return 0;\n}\n\nSQFloat sq_objtofloat(const HSQOBJECT *o)\n{\n    if(sq_isnumeric(*o)) {\n        return tofloat(*o);\n    }\n    return 0;\n}\n\nSQBool sq_objtobool(const HSQOBJECT *o)\n{\n    if(sq_isbool(*o)) {\n        return _integer(*o);\n    }\n    return SQFalse;\n}\n\nSQBool sq_obj_is_true(const HSQOBJECT *o)\n{\n    const SQObjectPtr &objPtr = static_cast<const SQObjectPtr &>(*o);\n    return SQVM::IsFalse(objPtr) ? SQFalse : SQTrue;\n}\n\nSQUserPointer sq_objtouserpointer(const HSQOBJECT *o)\n{\n    if(sq_isuserpointer(*o)) {\n        return _userpointer(*o);\n    }\n    return 0;\n}\n\nSQRESULT sq_obj_getuserdata(const HSQOBJECT *obj, SQUserPointer *p, SQUserPointer *typetag)\n{\n    if (obj->_type != OT_USERDATA)\n      return SQ_ERROR;\n\n    (*p) = _userdataval(*obj);\n    if(typetag) *typetag = _userdata(*obj)->_typetag;\n    return SQ_OK;\n}\n\nconst char* sq_objtypestr(SQObjectType tp)\n{\n    const char* s = IdType2Name(tp);\n    return s ? s : \"<unknown>\";\n}\n\nvoid sq_getregistrytableobj(HSQUIRRELVM v, HSQOBJECT *out)\n{\n    *out = _ss(v)->_registry;\n}\n\nSQRESULT sq_obj_get(HSQUIRRELVM v, const HSQOBJECT *obj, const HSQOBJECT *slot,\n                      HSQOBJECT *out, bool raw)\n{\n    v->ValidateThreadAccess();\n    const SQObjectPtr &selfPtr = static_cast<const SQObjectPtr &>(*obj);\n    const SQObjectPtr &slotPtr = static_cast<const SQObjectPtr &>(*slot);\n    SQObjectPtr outPtr;\n\n    SQUnsignedInteger getFlags = raw ?\n      (GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW) : GET_FLAG_DO_NOT_RAISE_ERROR;\n\n    bool res = v->Get(selfPtr, slotPtr, outPtr, getFlags);\n    if (res) {\n        *out = outPtr;\n        v->Push(outPtr);  // keep result alive on VM stack; caller must sq_poptop()\n    }\n    return res ? SQ_OK : SQ_ERROR;\n}\n\nSQBool sq_obj_cmp(HSQUIRRELVM v, const HSQOBJECT *a, const HSQOBJECT *b, SQInteger *res)\n{\n    const SQObjectPtr &aPtr = static_cast<const SQObjectPtr &>(*a);\n    const SQObjectPtr &bPtr = static_cast<const SQObjectPtr &>(*b);\n\n    return v->ObjCmp(aPtr, bPtr, *res);\n}\n\nbool sq_obj_is_equal(HSQUIRRELVM v, const HSQOBJECT *a, const HSQOBJECT *b)\n{\n    return v->IsEqual(*a, *b);\n}\n\nSQInteger sq_obj_getsize(const HSQOBJECT *obj)\n{\n    switch (obj->_type) {\n    case OT_TABLE:    return _table(*obj)->CountUsed();\n    case OT_ARRAY:    return _array(*obj)->Size();\n    case OT_STRING:   return _string(*obj)->_len;\n    case OT_USERDATA: return _userdata(*obj)->_size;\n    case OT_INSTANCE: return _instance(*obj)->_class->_udsize;\n    case OT_CLASS:    return _class(*obj)->_udsize;\n    default:          return SQ_ERROR;\n    }\n}\n\nstatic SQRESULT getinstanceup_impl(SQInstance *inst, SQUserPointer *p,\n                                   SQUserPointer typetag)\n{\n    *p = inst->_userpointer;\n    if (typetag != 0) {\n        SQClass *cl = inst->_class;\n        do {\n            if (cl->_typetag == typetag)\n                return SQ_OK;\n            cl = cl->_base;\n        } while (cl != NULL);\n        return SQ_ERROR;\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_obj_getinstanceup(const HSQOBJECT *obj, SQUserPointer *p,\n                              SQUserPointer typetag)\n{\n    if (obj->_type != OT_INSTANCE)\n        return SQ_ERROR;\n    return getinstanceup_impl(_instance(*obj), p, typetag);\n}\n\n// Shared raw-set logic for sq_rawset and sq_obj_set(raw=true).\n// Does NOT check immutability - callers handle that with their own error reporting.\nstatic SQRESULT rawset_impl(HSQUIRRELVM v, const SQObjectPtr &self,\n                            const SQObjectPtr &key, const SQObjectPtr &val)\n{\n    switch (sq_type(self)) {\n    case OT_TABLE:\n        _table(self)->NewSlot(key, val);\n        return SQ_OK;\n    case OT_CLASS:\n        _class(self)->NewSlot(_ss(v), key, val, false);\n        return SQ_OK;\n    case OT_INSTANCE:\n        return _instance(self)->Set(key, val) == SLOT_STATUS_OK ? SQ_OK : SQ_ERROR;\n    case OT_ARRAY:\n        if (sq_isnumeric(key))\n            return _array(self)->Set(tointeger(key), val) ? SQ_OK : SQ_ERROR;\n        return SQ_ERROR;\n    default:\n        return SQ_ERROR;\n    }\n}\n\nSQRESULT sq_obj_set(HSQUIRRELVM v, const HSQOBJECT *obj,\n                    const HSQOBJECT *key, const HSQOBJECT *val,\n                    bool raw)\n{\n    v->ValidateThreadAccess();\n    const SQObjectPtr &selfPtr = static_cast<const SQObjectPtr &>(*obj);\n    const SQObjectPtr &keyPtr  = static_cast<const SQObjectPtr &>(*key);\n    const SQObjectPtr &valPtr  = static_cast<const SQObjectPtr &>(*val);\n\n    if (raw) {\n        if (obj->_flags & SQOBJ_FLAG_IMMUTABLE)\n            return SQ_ERROR;\n        return rawset_impl(v, selfPtr, keyPtr, valPtr);\n    }\n    return v->Set(selfPtr, keyPtr, valPtr) ? SQ_OK : SQ_ERROR;\n}\n\nSQRESULT sq_obj_newslot(HSQUIRRELVM v, const HSQOBJECT *obj,\n                        const HSQOBJECT *key, const HSQOBJECT *val,\n                        bool bstatic)\n{\n    v->ValidateThreadAccess();\n    SQObjectType tp = sq_type(*obj);\n    if (tp != OT_TABLE && tp != OT_CLASS && tp != OT_INSTANCE)\n        return SQ_ERROR;\n\n    const SQObjectPtr &selfPtr = static_cast<const SQObjectPtr &>(*obj);\n    const SQObjectPtr &keyPtr  = static_cast<const SQObjectPtr &>(*key);\n    const SQObjectPtr &valPtr  = static_cast<const SQObjectPtr &>(*val);\n\n    if (!v->NewSlot(selfPtr, keyPtr, valPtr, bstatic))\n        return SQ_ERROR;\n    return SQ_OK;\n}\n\n#define MAX_FAST_COMPARE_SIZE 1024\n\nstatic bool fastEqualByValue(const SQObjectPtr &a, const SQObjectPtr &b, int depth)\n{\n    if (sq_type(a) != sq_type(b))\n    {\n      if (!sq_isnumeric(a) || !sq_isnumeric(b))\n          return false;\n      return tofloat(a) == tofloat(b);\n    }\n\n    // same type\n    if (_rawval(a) == _rawval(b))\n        return true;\n\n    if (depth <= 0)\n        return false;\n\n    if (sq_isarray(a))\n    {\n        auto aa = _array(a);\n        auto ab = _array(b);\n        if (aa->Size() != ab->Size())\n            return false;\n\n        if (aa->Size() > MAX_FAST_COMPARE_SIZE)\n            return false;\n\n        for (SQInteger i = 0; i < aa->Size(); i++)\n            if (!fastEqualByValue(aa->_values[i], ab->_values[i], depth - 1))\n                return false;\n\n        return true;\n    }\n    else if (sq_istable(a))\n    {\n        auto ta = _table(a);\n        auto tb = _table(b);\n        if (ta->CountUsed() != tb->CountUsed())\n            return false;\n\n        if (ta->CountUsed() > MAX_FAST_COMPARE_SIZE)\n            return false;\n\n        SQObjectPtr iter;\n        while (true)\n        {\n            SQObjectPtr key, va, vb;\n            iter._unVal.nInteger = ta->Next(true, iter, key, va);\n            iter._type = OT_INTEGER;\n            if (_integer(iter) < 0)\n                break;\n\n            if (!tb->Get(key, vb))\n                return false;\n            if (!fastEqualByValue(va, vb, depth - 1))\n                return false;\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\n\nbool sq_fast_equal_by_value_deep(const HSQOBJECT *a, const HSQOBJECT *b, int depth)\n{\n    return fastEqualByValue(\n        static_cast<const SQObjectPtr&>(*a),\n        static_cast<const SQObjectPtr&>(*b),\n        depth);\n}\n\n\nvoid sq_pushnull(HSQUIRRELVM v)\n{\n    v->PushNull();\n}\n\nvoid sq_pushstring(HSQUIRRELVM v,const char *s,SQInteger len)\n{\n    if(s || len==0)\n        v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len)));\n    else v->PushNull();\n}\n\nvoid sq_pushinteger(HSQUIRRELVM v,SQInteger n)\n{\n    v->Push(SQObjectPtr(n));\n}\n\nvoid sq_pushbool(HSQUIRRELVM v,SQBool b)\n{\n    v->Push(SQObjectPtr(b?true:false));\n}\n\nvoid sq_pushfloat(HSQUIRRELVM v,SQFloat n)\n{\n    v->Push(SQObjectPtr(n));\n}\n\nvoid sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)\n{\n    v->Push(SQObjectPtr(p));\n}\n\nvoid sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread)\n{\n    v->Push(SQObjectPtr(thread));\n}\n\nSQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size)\n{\n    v->ValidateThreadAccess();\n    SQUserData *ud = SQUserData::Create(_ss(v), size + SQ_ALIGNMENT);\n    v->Push(SQObjectPtr(ud));\n    return (SQUserPointer)sq_aligning(ud + 1);\n}\n\nvoid sq_newtable(HSQUIRRELVM v)\n{\n    v->ValidateThreadAccess();\n    v->Push(SQObjectPtr(SQTable::Create(_ss(v), 0)));\n}\n\nvoid sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity)\n{\n    v->Push(SQObjectPtr(SQTable::Create(_ss(v), initialcapacity)));\n}\n\nvoid sq_newarray(HSQUIRRELVM v,SQInteger size)\n{\n    v->Push(SQObjectPtr(SQArray::Create(_ss(v), size)));\n}\n\nSQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase)\n{\n    SQClass *baseclass = NULL;\n    if(hasbase) {\n        SQObjectPtr &base = stack_get(v,-1);\n        if(sq_type(base) != OT_CLASS)\n            return sq_throwerror(v,\"invalid base type\");\n        baseclass = _class(base);\n    }\n    SQClass *newclass = SQClass::Create(v, baseclass);\n    if(baseclass) v->Pop();\n    if (newclass) {\n        v->Push(SQObjectPtr(newclass));\n        return SQ_OK;\n    }\n    else\n        return SQ_ERROR; // propagate the raised error\n}\n\nSQBool sq_instanceof(HSQUIRRELVM v)\n{\n    SQObjectPtr &obj = stack_get(v,-1);\n    SQObjectPtr &cl = stack_get(v,-2);\n    if(sq_type(cl) != OT_CLASS)\n        return sq_throwerror(v,\"invalid param type\");\n\n    SQClass *cls = _class(cl);\n    bool result = false;\n\n    if (sq_type(obj) == OT_INSTANCE) {\n        result = _instance(obj)->InstanceOf(cls);\n    } else if (cls->_is_builtin_type) {\n        SQObjectType obj_type = sq_type(obj);\n        // both closures and native closures map to Function class\n        if (cls->_builtin_type_id == OT_CLOSURE && (obj_type == OT_CLOSURE || obj_type == OT_NATIVECLOSURE)) {\n            result = true;\n        } else {\n            result = (obj_type == cls->_builtin_type_id);\n        }\n    }\n\n    return result ? SQTrue : SQFalse;\n}\n\nSQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v,2);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    _array(*arr)->Append(v->GetUp(-1));\n    v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    if(_array(*arr)->Size() > 0) {\n        if(pushval != 0){ v->Push(_array(*arr)->Top()); }\n        _array(*arr)->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, \"empty array\");\n}\n\nSQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v,1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    if(newsize >= 0) {\n        _array(*arr)->Resize(newsize);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"negative size\");\n}\n\n\nSQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *o;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,o);\n    SQArray *arr = _array(*o);\n    if(arr->Size() > 0) {\n        SQObjectPtr t;\n        SQInteger size = arr->Size();\n        SQInteger n = size >> 1; size -= 1;\n        for(SQInteger i = 0; i < n; i++) {\n            t = arr->_values[i];\n            arr->_values[i] = arr->_values[size-i];\n            arr->_values[size-i] = t;\n        }\n        return SQ_OK;\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,\"index out of range\");\n}\n\nSQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos)\n{\n    sq_aux_paramscheck(v, 1);\n    SQObjectPtr *arr;\n    _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\n    SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,\"index out of range\");\n    v->Pop();\n    return ret;\n}\n\nvoid sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars)\n{\n    SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func,nfreevars);\n    nc->_nparamscheck = 0;\n    for(SQUnsignedInteger i = 0; i < nfreevars; i++) {\n        nc->_outervalues[i] = v->Top();\n        v->Pop();\n    }\n    v->Push(SQObjectPtr(nc));\n}\n\nSQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars)\n{\n    SQObject o = stack_get(v, idx);\n    if(sq_type(o) == OT_CLOSURE) {\n        SQClosure *c = _closure(o);\n        SQFunctionProto *proto = c->_function;\n        *nparams = proto->_nparameters;\n        *nfreevars = proto->_noutervalues;\n        return SQ_OK;\n    }\n    else if(sq_type(o) == OT_NATIVECLOSURE)\n    {\n        SQNativeClosure *c = _nativeclosure(o);\n        *nparams = c->_nparamscheck;\n        *nfreevars = (SQInteger)c->_noutervalues;\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"the object is not a closure\");\n}\n\nSQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const char *name)\n{\n    SQObject o = stack_get(v, idx);\n    if(sq_isnativeclosure(o)) {\n        SQNativeClosure *nc = _nativeclosure(o);\n        nc->_name = SQString::Create(_ss(v),name);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"the object is not a nativeclosure\");\n}\n\nSQRESULT sq_setnativeclosuredocstring(HSQUIRRELVM v,SQInteger idx,const char *docstring)\n{\n    assert(docstring);\n    SQObject o = stack_get(v, idx);\n    if(sq_isnativeclosure(o)) {\n        SQObjectPtr docValue(SQString::Create(_ss(v), docstring));\n        SQObjectPtr docKey;\n        docKey._type = OT_USERPOINTER;\n        docKey._unVal.pUserPointer = (void *)_nativeclosure(o)->_function;\n        _table(_ss(v)->doc_objects)->NewSlot(docKey, docValue);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"the object is not a nativeclosure\");\n}\n\nSQRESULT sq_setobjectdocstring(HSQUIRRELVM v, const HSQOBJECT *obj, const char *docstring)\n{\n    assert(obj);\n    assert(docstring);\n    if (sq_isclass(*obj) || sq_istable(*obj) || sq_isnativeclosure(*obj) || sq_isclosure(*obj)) {\n        SQObjectPtr docValue(SQString::Create(_ss(v), docstring));\n        SQObjectPtr docKey;\n        docKey._type = OT_USERPOINTER;\n        docKey._unVal.pUserPointer =\n            sq_isclass(*obj) || sq_istable(*obj) ? (void *)_userpointer(*obj) :\n            sq_isnativeclosure(*obj) ? (void *)_nativeclosure(*obj)->_function :\n            sq_isclosure(*obj) ? (void *)_closure(*obj)->_function : NULL;\n        _table(_ss(v)->doc_objects)->NewSlot(docKey, docValue);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"the object is not a table, class or function\");\n}\n\nSQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const char *typemask)\n{\n    SQObject o = stack_get(v, -1);\n    if(!sq_isnativeclosure(o))\n        return sq_throwerror(v, \"native closure expected\");\n    SQNativeClosure *nc = _nativeclosure(o);\n    nc->_nparamscheck = nparamscheck;\n    if(typemask) {\n        SQIntVec res(_ss(v)->_alloc_ctx);\n        if(!CompileTypemask(res, typemask))\n            return sq_throwerror(v, \"invalid typemask\");\n        nc->_typecheck.copy(res);\n    }\n    else {\n        nc->_typecheck.resize(0);\n    }\n    if(nparamscheck == SQ_MATCHTYPEMASKSTRING) {\n        nc->_nparamscheck = nc->_typecheck.size();\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_new_closure_slot_from_decl_string(HSQUIRRELVM v, SQFUNCTION func, SQUnsignedInteger nfreevars, const char *function_decl,\n    const char *docstring)\n{\n//  instead of:\n//  sq_pushstring(v, function_name, -1);\n//  sq_newclosure(v, func_ptr,0);\n//  sq_setparamscheck(v, nparamscheck, typemask);\n//  sq_setnativeclosurename(v, -1, name);\n//  sq_newslot(v, -3, SQFalse);\n\n    SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func, nfreevars);\n\n    for(SQUnsignedInteger i = 0; i < nfreevars; i++) {\n        nc->_outervalues[i] = v->Top();\n        v->Pop();\n    }\n\n    SQFunctionType ft(_ss(v));\n    SQInteger error_pos = 0;\n    SQObjectPtr error_string;\n    if (!sq_parse_function_type_string(v, function_decl, ft, error_pos, error_string)) {\n        SQPRINTFUNCTION printErrorFunc = sq_geterrorfunc(v);\n        assert(printErrorFunc && \"set 'print error function' using sq_setprintfunc()\");\n        if (printErrorFunc) {\n            printErrorFunc(v, \"%s at position %d of type '%s'\\n\",\n                _stringval(error_string), int(error_pos), function_decl);\n        }\n        assert(0 && \"Invalid function type string, see error message in the log\");\n        return sq_throwerror(v, \"invalid function type string\");\n    }\n\n    sq_pushstring(v, _stringval(ft.functionName), -1);\n\n    nc->_name = ft.functionName;\n    nc->_purefunction = ft.pure;\n    nc->_nodiscard = ft.nodiscard;\n\n    nc->_typecheck.resize(ft.argTypeMask.size() + 1);\n    nc->_typecheck[0] = ft.objectTypeMask;\n\n    for (SQInteger i = 0; i < ft.argTypeMask.size(); i++)\n        nc->_typecheck[i + 1] = ft.argTypeMask[i];\n\n    if (ft.ellipsisArgTypeMask != 0 || ft.requiredArgs != ft.argTypeMask.size())\n        nc->_nparamscheck = -ft.requiredArgs - 1;\n    else\n        nc->_nparamscheck = ft.requiredArgs + 1;\n\n    nc->_result_type_mask = ft.returnTypeMask;\n\n#if SQ_STORE_DOC_OBJECTS\n    if (docstring) {\n        SQObjectPtr docValue(SQString::Create(_ss(v), docstring));\n        SQObjectPtr docKey;\n        docKey._type = OT_USERPOINTER;\n        docKey._unVal.pUserPointer = (void *)func;\n        _table(_ss(v)->doc_objects)->NewSlot(docKey, docValue);\n    }\n\n    {\n        SQObjectPtr declValue(SQString::Create(_ss(v), function_decl));\n        SQObjectPtr declKey;\n        declKey._type = OT_USERPOINTER;\n        declKey._unVal.pUserPointer = (void *)(((size_t)(void *)func) ^ ~size_t(0));\n        _table(_ss(v)->doc_objects)->NewSlot(declKey, declValue);\n    }\n#else\n    (void)(docstring);\n#endif\n\n    v->Push(SQObjectPtr(nc));\n\n    //printf(\"%s: typecheck.size() = %d, nparamscheck = %d\\n\", function_decl,\n    //    int(nc->_typecheck.size()), int(nc->_nparamscheck));\n\n    return sq_newslot(v, -3, SQFalse);\n}\n\n\nSQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(!sq_isnativeclosure(o) &&\n        !sq_isclosure(o))\n        return sq_throwerror(v,\"the target is not a closure\");\n    SQObjectPtr &env = stack_get(v,-1);\n    if(!sq_istable(env) &&\n        !sq_isarray(env) &&\n        !sq_isclass(env) &&\n        !sq_isinstance(env))\n        return sq_throwerror(v,\"invalid environment\");\n    SQWeakRef *w = _refcounted(env)->GetWeakRef(_ss(v)->_alloc_ctx, sq_type(env), env._flags);\n    SQObjectPtr ret;\n    if(sq_isclosure(o)) {\n        SQClosure *c = _closure(o)->Clone();\n        __ObjRelease(c->_env);\n        c->_env = w;\n        __ObjAddRef(c->_env);\n        if(_closure(o)->_base) {\n            c->_base = _closure(o)->_base;\n            __ObjAddRef(c->_base);\n        }\n        ret = c;\n    }\n    else { //then must be a native closure\n        SQNativeClosure *c = _nativeclosure(o)->Clone();\n        __ObjRelease(c->_env);\n        c->_env = w;\n        __ObjAddRef(c->_env);\n        ret = c;\n    }\n    v->Pop();\n    v->Push(ret);\n    return SQ_OK;\n}\n\nSQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(!sq_isnativeclosure(o) &&\n        !sq_isclosure(o))\n        return sq_throwerror(v,\"the target is not a closure\");\n    if(sq_isnativeclosure(o))\n    {\n        v->Push(_nativeclosure(o)->_name);\n    }\n    else { //closure\n        v->Push(_closure(o)->_function->_name);\n    }\n    return SQ_OK;\n}\n\n\nSQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx, SQBool freemem)\n{\n    SQObject &o=stack_get(v,idx);\n    switch(sq_type(o)) {\n        case OT_TABLE: _table(o)->Clear(freemem);  break;\n        case OT_ARRAY: _array(o)->Resize(0, freemem); break;\n        default:\n            return sq_throwerror(v, \"clear only works on table and array\");\n        break;\n\n    }\n    return SQ_OK;\n}\n\nvoid sq_pushroottable(HSQUIRRELVM v)\n{\n    v->Push(v->_roottable);\n}\n\nvoid sq_pushregistrytable(HSQUIRRELVM v)\n{\n    v->Push(_ss(v)->_registry);\n}\n\nvoid sq_pushconsttable(HSQUIRRELVM v)\n{\n    v->Push(_ss(v)->_consts);\n}\n\nSQRESULT sq_setroottable(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v, -1);\n    if(sq_istable(o) || sq_isnull(o)) {\n        v->_roottable = o;\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, \"invalid type\");\n}\n\nSQRESULT sq_setconsttable(HSQUIRRELVM v)\n{\n    SQObject o = stack_get(v, -1);\n    if(sq_istable(o)) {\n        _ss(v)->_consts = o;\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v, \"invalid type, expected table\");\n}\n\nvoid sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p)\n{\n    v->_foreignptr = p;\n}\n\nSQUserPointer sq_getforeignptr(HSQUIRRELVM v)\n{\n    return v->_foreignptr;\n}\n\nvoid sq_setsharedforeignptr(HSQUIRRELVM v,SQUserPointer p)\n{\n    _ss(v)->_foreignptr = p;\n}\n\nSQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v)\n{\n    return _ss(v)->_foreignptr;\n}\n\nvoid sq_setvmreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook)\n{\n    v->_releasehook = hook;\n}\n\nSQRELEASEHOOK sq_getvmreleasehook(HSQUIRRELVM v)\n{\n    return v->_releasehook;\n}\n\nvoid sq_setsharedreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook)\n{\n    _ss(v)->_releasehook = hook;\n}\n\nSQRELEASEHOOK sq_getsharedreleasehook(HSQUIRRELVM v)\n{\n    return _ss(v)->_releasehook;\n}\n\nvoid sq_push(HSQUIRRELVM v,SQInteger idx)\n{\n    v->Push(stack_get(v, idx));\n}\n\nSQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx)\n{\n    return sq_type(stack_get(v, idx));\n}\n\nSQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQObjectPtr res;\n    if(!v->TypeOf(o,res)) {\n        return SQ_ERROR;\n    }\n    v->Push(res);\n    return SQ_OK;\n}\n\nSQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQObjectPtr res;\n    if(!v->ToString(o,res)) {\n        return SQ_ERROR;\n    }\n    v->Push(res);\n    return SQ_OK;\n}\n\nvoid sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    *b = SQVM::IsFalse(o)?SQFalse:SQTrue;\n}\n\nSQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if(sq_isnumeric(o)) {\n        *i = tointeger(o);\n        return SQ_OK;\n    }\n    if(sq_isbool(o)) {\n        *i = SQVM::IsFalse(o)?SQFalse:SQTrue;\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if(sq_isnumeric(o)) {\n        *f = tofloat(o);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if(sq_isbool(o)) {\n        *b = _integer(o);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const char **c,SQInteger *size)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_STRING,o);\n    *c = _stringval(*o);\n    *size = _string(*o)->_len;\n    return SQ_OK;\n}\n\nSQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const char **c)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_STRING,o);\n    *c = _stringval(*o);\n    return SQ_OK;\n}\n\nSQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_THREAD,o);\n    *thread = _thread(*o);\n    return SQ_OK;\n}\n\nSQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    v->PushNull();\n    if(!v->Clone(o, stack_get(v, -1))){\n        v->Pop();\n        return SQ_ERROR;\n    }\n    return SQ_OK;\n}\n\nSQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQInteger res = sq_obj_getsize(&o);\n    if (res == SQ_ERROR)\n        return sq_aux_invalidtype(v, sq_type(o));\n    return res;\n}\n\nSQHash sq_gethash(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    return HashObj(o);\n}\n\nSQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_USERDATA,o);\n    (*p) = _userdataval(*o);\n    if(typetag) *typetag = _userdata(*o)->_typetag;\n    return SQ_OK;\n}\n\nSQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    switch(sq_type(o)) {\n        case OT_USERDATA:   _userdata(o)->_typetag = typetag;   break;\n        case OT_CLASS:      _class(o)->_typetag = typetag;      break;\n        default:            return sq_throwerror(v,\"invalid object type\");\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag)\n{\n  switch(sq_type(*o)) {\n    case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break;\n    case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break;\n    case OT_CLASS:    *typetag = _class(*o)->_typetag; break;\n    default: return SQ_ERROR;\n  }\n  return SQ_OK;\n}\n\nSQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if (SQ_FAILED(sq_getobjtypetag(&o, typetag)))\n        return SQ_ERROR;// this is not an error it should be a bool but would break backward compatibility\n    return SQ_OK;\n}\n\nSQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o);\n    (*p) = _userpointer(*o);\n    return SQ_OK;\n}\n\nSQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,\"the object is not a class instance\");\n    _instance(o)->_userpointer = p;\n    return SQ_OK;\n}\n\nSQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)\n{\n    SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_CLASS) return sq_throwerror(v,\"the object is not a class\");\n    if(_class(o)->isLocked()) return sq_throwerror(v,\"the class is locked\");\n    _class(o)->_udsize = udsize;\n    return SQ_OK;\n}\n\nSQRESULT sq_registernativefield(HSQUIRRELVM v, SQInteger classidx,\n    const char *name, SQInteger offset, SQInteger fieldtype)\n{\n    SQObjectPtr &o = stack_get(v, classidx);\n\n    if (sq_type(o) != OT_CLASS)\n        return sq_throwerror(v, \"the object is not a class\");\n\n    if (fieldtype < 0 || fieldtype > SQNFT_BOOL)\n        return sq_throwerror(v, \"invalid native field type\");\n\n    if (offset < 0 || offset > 0xFFFF)\n        return sq_throwerror(v, \"native field offset out of range\");\n\n    SQClass *cls = _class(o);\n\n    if (cls->isLocked())\n        return sq_throwerror(v, \"native field cannot be registered on a locked class\");\n\n    if (cls->_udsize <= 0)\n        return sq_throwerror(v, \"native field requires inline userdata (call sq_setclassudsize first)\");\n\n    SQObjectPtr key(SQString::Create(_ss(v), name));\n    if (!cls->RegisterNativeField(_ss(v), key, (uint16_t)offset, (uint8_t)fieldtype))\n        return sq_throwerror(v, \"failed to register native field\");\n\n    return SQ_OK;\n}\n\nSQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p, SQUserPointer typetag)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if (sq_type(o) != OT_INSTANCE)\n        return sq_throwerror(v, \"the object is not a class instance\");\n    if (SQ_FAILED(getinstanceup_impl(_instance(o), p, typetag)))\n        return sq_throwerror(v, \"invalid type tag\");\n    return SQ_OK;\n}\n\nSQInteger sq_gettop(HSQUIRRELVM v)\n{\n    return (v->_top) - v->_stackbase;\n}\n\nvoid sq_settop(HSQUIRRELVM v, SQInteger newtop)\n{\n    SQInteger top = sq_gettop(v);\n    if(top > newtop)\n        sq_pop(v, top - newtop);\n    else\n        while(top++ < newtop) sq_pushnull(v);\n}\n\nvoid sq_pop(HSQUIRRELVM v, SQInteger nelemstopop)\n{\n    assert(v->_top >= nelemstopop);\n    v->Pop(nelemstopop);\n}\n\nvoid sq_poptop(HSQUIRRELVM v)\n{\n    assert(v->_top >= 1);\n    v->Pop();\n}\n\n\nvoid sq_remove(HSQUIRRELVM v, SQInteger idx)\n{\n    v->Remove(idx);\n}\n\nSQInteger sq_cmp(HSQUIRRELVM v)\n{\n    SQInteger res;\n    v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);\n    return res;\n}\n\nbool sq_cmpraw(HSQUIRRELVM v, HSQOBJECT &lhs, HSQOBJECT &rhs, SQInteger &res)\n{\n  return v->ObjCmp(SQObjectPtr(lhs), SQObjectPtr(rhs), res);\n}\n\n\nSQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v, 3);\n    SQObjectPtr &self = stack_get(v, idx);\n    if(sq_type(self) == OT_TABLE || sq_type(self) == OT_CLASS) {\n        SQObjectPtr &key = v->GetUp(-2);\n        if (!v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false))\n            return SQ_ERROR;\n        v->Pop(2);\n        return SQ_OK;\n    }\n    else {\n        v->Raise_Error(\"cannot add slot to '%s'\", GetTypeName(self));\n        return SQ_ERROR;\n    }\n}\n\nSQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v, 2);\n    SQObjectPtr *self;\n    _GETSAFE_OBJ(v, idx, OT_TABLE,self);\n    SQObjectPtr &key = v->GetUp(-1);\n    SQObjectPtr res;\n    if(!v->DeleteSlot(*self, key, res)){\n        v->Pop();\n        return SQ_ERROR;\n    }\n    if(pushval) v->GetUp(-1) = res;\n    else v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_set(HSQUIRRELVM v,SQInteger idx)\n{\n    v->ValidateThreadAccess();\n\n    SQObjectPtr &self = stack_get(v, idx);\n    if(v->Set(self, v->GetUp(-2), v->GetUp(-1))) {\n        v->Pop(2);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)\n{\n    v->ValidateThreadAccess();\n\n    SQObjectPtr &self = stack_get(v, idx);\n\n    if (self._flags & SQOBJ_FLAG_IMMUTABLE) {\n        v->Raise_Error(\"trying to modify immutable '%s'\",GetTypeName(self));\n        return SQ_ERROR;\n    }\n\n    if (SQ_SUCCEEDED(rawset_impl(v, self, v->GetUp(-2), v->GetUp(-1)))) {\n        v->Pop(2);\n        return SQ_OK;\n    }\n\n    SQObjectType tp = sq_type(self);\n    if (tp == OT_TABLE || tp == OT_CLASS || tp == OT_INSTANCE || tp == OT_ARRAY) {\n        v->Raise_IdxError(v->GetUp(-2));\n        return SQ_ERROR;\n    }\n    v->Pop(2);\n    return sq_throwerror(v, \"rawset works only on array/table/class and instance\");\n}\n\nSQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)\n{\n    v->ValidateThreadAccess();\n\n    SQObjectPtr &self = stack_get(v, idx);\n    if(sq_type(self) != OT_CLASS) return sq_throwerror(v, \"new member only works with classes\");\n    SQObjectPtr &key = v->GetUp(-2);\n    if(!v->NewSlot(self,key,v->GetUp(-1),bstatic?true:false)) {\n        v->Pop(2);\n        return SQ_ERROR;\n    }\n    v->Pop(2);\n    return SQ_OK;\n}\n\n\nSQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &self = stack_get(v, idx);\n    SQObjectPtr &mt = v->GetUp(-1);\n    SQObjectType type = sq_type(self);\n    switch(type) {\n    case OT_TABLE:\n        if(sq_type(mt) == OT_TABLE) {\n            if(!_table(self)->SetDelegate(_table(mt))) {\n                return sq_throwerror(v, \"delagate cycle\");\n            }\n            v->Pop();\n        }\n        else if(sq_type(mt)==OT_NULL) {\n            _table(self)->SetDelegate(NULL); v->Pop(); }\n        else return sq_aux_invalidtype(v,type);\n        break;\n    case OT_USERDATA:\n        if(sq_type(mt)==OT_TABLE) {\n            _userdata(self)->SetDelegate(_table(mt)); v->Pop(); }\n        else if(sq_type(mt)==OT_NULL) {\n            _userdata(self)->SetDelegate(NULL); v->Pop(); }\n        else return sq_aux_invalidtype(v, type);\n        break;\n    default:\n            return sq_aux_invalidtype(v, type);\n        break;\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\n{\n    v->ValidateThreadAccess();\n\n    sq_aux_paramscheck(v, 2);\n    SQObjectPtr *self;\n    _GETSAFE_OBJ(v, idx, OT_TABLE,self);\n\n    if (self->_flags & SQOBJ_FLAG_IMMUTABLE) {\n        v->Raise_Error(\"trying to modify immutable '%s'\",GetTypeName(*self));\n        return SQ_ERROR;\n    }\n\n    SQObjectPtr &key = v->GetUp(-1);\n    SQObjectPtr t;\n    if(_table(*self)->Get(key,t)) {\n        _table(*self)->Remove(key);\n    }\n    if(pushval != 0)\n        v->GetUp(-1) = t;\n    else\n        v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)\n{\n    v->ValidateThreadAccess();\n\n    SQObjectPtr &self=stack_get(v,idx);\n    switch(sq_type(self)){\n    case OT_TABLE:\n    case OT_USERDATA:\n        if(!_delegable(self)->_delegate){\n            v->PushNull();\n            break;\n        }\n        v->Push(SQObjectPtr(_delegable(self)->_delegate));\n        break;\n    default: return sq_throwerror(v,\"wrong type\"); break;\n    }\n    return SQ_OK;\n\n}\n\nSQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)\n{\n    const SQObjectPtr &self = stack_get(v,idx);\n    SQObjectPtr &obj = v->GetUp(-1);\n    if (v->Get(self,obj,obj,GET_FLAG_DO_NOT_RAISE_ERROR))\n        return SQ_OK;\n    v->Pop();\n    return SQ_ERROR;\n}\n\nstatic inline void propagate_immutable(const SQObject &obj, SQObject &slot_val)\n{\n    if (sq_objflags(obj) & SQOBJ_FLAG_IMMUTABLE)\n        slot_val._flags |= SQOBJ_FLAG_IMMUTABLE;\n}\n\nSQRESULT sq_rawget(HSQUIRRELVM v, SQInteger idx)\n{\n    v->ValidateThreadAccess();\n\n    const SQObjectPtr &self = stack_get(v, idx);\n    SQObjectPtr &obj = v->GetUp(-1);\n    if (v->Get(self, obj, obj, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW))\n        return SQ_OK;\n    v->Pop();\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po)\n{\n    *po=stack_get(v,idx);\n    return SQ_OK;\n}\n\nconst char *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx)\n{\n    SQUnsignedInteger cstksize=v->_callsstacksize;\n    SQUnsignedInteger lvl=(cstksize-level)-1;\n    SQInteger stackbase=v->_stackbase;\n    if(lvl<cstksize){\n        for(SQUnsignedInteger i=0;i<level;i++){\n            SQVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1];\n            stackbase-=ci._prevstkbase;\n        }\n        SQVM::CallInfo &ci=v->_callsstack[lvl];\n        if(sq_type(ci._closure)!=OT_CLOSURE)\n            return NULL;\n        SQClosure *c=_closure(ci._closure);\n        SQFunctionProto *func=c->_function;\n        if(func->_noutervalues > (SQInteger)idx) {\n            v->Push(*_outer(c->_outervalues[idx])->_valptr);\n            return _stringval(func->_outervalues[idx]._name);\n        }\n        idx -= func->_noutervalues;\n        return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions));\n    }\n    return NULL;\n}\n\nvoid sq_pushobj(HSQUIRRELVM v,const HSQOBJECT *po)\n{\n    v->Push(SQObjectPtr(*po));\n}\n\nvoid sq_throwparamtypeerror(HSQUIRRELVM v, SQInteger nparam, SQInteger typemask, SQInteger type)\n{\n    v->Raise_ParamTypeError(nparam, typemask, type);\n}\n\nSQRESULT sq_throwerror(HSQUIRRELVM v,const char *err)\n{\n    v->_lasterror=SQString::Create(_ss(v),err);\n    return SQ_ERROR;\n}\n\nSQRESULT sq_throwobject(HSQUIRRELVM v)\n{\n    v->_lasterror = v->GetUp(-1);\n    v->Pop();\n    return SQ_ERROR;\n}\n\n\nvoid sq_reseterror(HSQUIRRELVM v)\n{\n    v->_lasterror.Null();\n}\n\nvoid sq_getlasterror(HSQUIRRELVM v)\n{\n    v->Push(v->_lasterror);\n}\n\nSQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize)\n{\n    if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) {\n        if(v->_nmetamethodscall) {\n            return sq_throwerror(v,\"cannot resize stack while in a metamethod\");\n        }\n        v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size()));\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool invoke_err_handler)\n{\n    if (sq_type(v->GetUp(-1)) == OT_GENERATOR)\n    {\n        v->PushNull(); //retval\n        bool res = v->_debughook ?\n            v->Execute<true>(v->GetUp(-2), 0, v->_top, v->GetUp(-1), invoke_err_handler, SQVM::ET_RESUME_GENERATOR) :\n            v->Execute<false>(v->GetUp(-2), 0, v->_top, v->GetUp(-1), invoke_err_handler, SQVM::ET_RESUME_GENERATOR);\n\n        if (!res)\n        {\n            v->Raise_Error(v->_lasterror);\n            return SQ_ERROR;\n        }\n        if(!retval)\n            v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"only generators can be resumed\");\n}\n\nSQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool invoke_err_handler)\n{\n    v->ValidateThreadAccess();\n    if (v->_sq_call_hook)\n        v->_sq_call_hook(v);\n\n    SQObjectPtr res;\n    if(!v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,invoke_err_handler?true:false)){\n        v->Pop(params); //pop args\n        return SQ_ERROR;\n    }\n    if(!v->_suspended)\n        v->Pop(params); //pop args\n    if(retval)\n        v->Push(res); // push result\n    return SQ_OK;\n}\n\nSQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)\n{\n    v->ValidateThreadAccess();\n\n    SQObjectPtr &res = v->GetUp(-(nparams + 1));\n    if (sq_type(res) != OT_CLOSURE) {\n        return sq_throwerror(v, \"only closure can be tail called\");\n    }\n    SQClosure *clo = _closure(res);\n    if (clo->_function->_bgenerator)\n    {\n        return sq_throwerror(v, \"generators cannot be tail called\");\n    }\n\n    SQInteger stackbase = (v->_top - nparams) - v->_stackbase;\n    if (!v->TailCall(clo, stackbase, nparams)) {\n        return SQ_ERROR;\n    }\n    return SQ_TAILCALL_FLAG;\n}\n\nSQRESULT sq_suspendvm(HSQUIRRELVM v)\n{\n    return v->Suspend();\n}\n\nSQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool invoke_err_handler,SQBool throwerror)\n{\n    SQObjectPtr ret;\n    if(!v->_suspended)\n        return sq_throwerror(v,\"cannot resume a vm that is not running any code\");\n    SQInteger target = v->_suspended_target;\n    if(wakeupret) {\n        if(target != -1) {\n            v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval\n        }\n        v->Pop();\n    } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); }\n    SQObjectPtr dummy;\n\n    bool res = v->_debughook ?\n        v->Execute<true>(dummy,-1,-1,ret,invoke_err_handler,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM) :\n        v->Execute<false>(dummy,-1,-1,ret,invoke_err_handler,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM);\n\n    if(!res)\n        return SQ_ERROR;\n\n    if(retval)\n        v->Push(ret);\n    return SQ_OK;\n}\n\nvoid sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)\n{\n    SQObjectPtr &ud=stack_get(v,idx);\n    switch(sq_type(ud) ) {\n    case OT_USERDATA:   _userdata(ud)->_hook = hook;    break;\n    case OT_INSTANCE:   _instance(ud)->_hook = hook;    break;\n    case OT_CLASS:      _class(ud)->_hook = hook;       break;\n    default: return;\n    }\n}\n\nSQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr &ud=stack_get(v,idx);\n    switch(sq_type(ud) ) {\n    case OT_USERDATA:   return _userdata(ud)->_hook;    break;\n    case OT_INSTANCE:   return _instance(ud)->_hook;    break;\n    case OT_CLASS:      return _class(ud)->_hook;       break;\n    default: return NULL;\n    }\n}\n\nvoid sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)\n{\n    _ss(v)->_compilererrorhandler = f;\n}\n\nSQCOMPILERERROR sq_getcompilererrorhandler(HSQUIRRELVM v)\n{\n    return _ss(v)->_compilererrorhandler;\n}\n\nvoid sq_setcompilerdiaghandler(HSQUIRRELVM v, SQ_COMPILER_DIAG_CB f)\n{\n    _ss(v)->_compilerdiaghandler = f;\n}\n\n\nSQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);\n    unsigned short tag = SQ_BYTECODE_STREAM_TAG;\n    if(_closure(*o)->_function->_noutervalues)\n        return sq_throwerror(v,\"a closure with free variables bound cannot be serialized\");\n    if(w(up,&tag,2) != 2)\n        return sq_throwerror(v,\"io error\");\n    if(!_closure(*o)->Save(v,up,w))\n        return SQ_ERROR;\n    return SQ_OK;\n}\n\nSQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up)\n{\n    SQObjectPtr closure;\n\n    unsigned short tag;\n    if(r(up,&tag,2) != 2)\n        return sq_throwerror(v,\"io error\");\n    if(tag != SQ_BYTECODE_STREAM_TAG)\n        return sq_throwerror(v,\"invalid stream\");\n    if(!SQClosure::Load(v,up,r,closure))\n        return SQ_ERROR;\n    v->Push(closure);\n    return SQ_OK;\n}\n\nchar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize)\n{\n    return _ss(v)->GetScratchPad(minsize);\n}\n\nSQRESULT sq_resurrectunreachable(HSQUIRRELVM v)\n{\n#ifndef NO_GARBAGE_COLLECTOR\n    _ss(v)->ResurrectUnreachable(v);\n    return SQ_OK;\n#else\n    return sq_throwerror(v,\"sq_resurrectunreachable requires a garbage collector build\");\n#endif\n}\n\nSQInteger sq_collectgarbage(HSQUIRRELVM v)\n{\n#ifndef NO_GARBAGE_COLLECTOR\n    return _ss(v)->CollectGarbage(v);\n#else\n    return -1;\n#endif\n}\n\nSQRESULT sq_getcallee(HSQUIRRELVM v)\n{\n    if(v->_callsstacksize > 1)\n    {\n        v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"no closure in the calls stack\");\n}\n\nconst char *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    const char *name = NULL;\n    switch(sq_type(self))\n    {\n    case OT_CLOSURE:{\n        SQClosure *clo = _closure(self);\n        SQFunctionProto *fp = clo->_function;\n        if(((SQUnsignedInteger)fp->_noutervalues) > nval) {\n            v->Push(*(_outer(clo->_outervalues[nval])->_valptr));\n            SQOuterVar &ov = fp->_outervalues[nval];\n            name = _stringval(ov._name);\n        }\n                    }\n        break;\n    case OT_NATIVECLOSURE:{\n        SQNativeClosure *clo = _nativeclosure(self);\n        if(clo->_noutervalues > nval) {\n            v->Push(clo->_outervalues[nval]);\n            name = \"@NATIVE\";\n        }\n                          }\n        break;\n    default: break; //shutup compiler\n    }\n    return name;\n}\n\nSQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)\n{\n    SQObjectPtr &self=stack_get(v,idx);\n    switch(sq_type(self))\n    {\n    case OT_CLOSURE:{\n        SQFunctionProto *fp = _closure(self)->_function;\n        if(((SQUnsignedInteger)fp->_noutervalues) > nval){\n            *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1);\n        }\n        else return sq_throwerror(v,\"invalid free var index\");\n                    }\n        break;\n    case OT_NATIVECLOSURE:\n        if(_nativeclosure(self)->_noutervalues > nval){\n            _nativeclosure(self)->_outervalues[nval] = stack_get(v,-1);\n        }\n        else return sq_throwerror(v,\"invalid free var index\");\n        break;\n    default:\n        return sq_aux_invalidtype(v, sq_type(self));\n    }\n    v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    SQObjectPtr &key = stack_get(v,-1);\n    SQTable *m = _class(*o)->_members;\n    SQObjectPtr val;\n    if(m->Get(key,val)) {\n        handle->_static = !(_isfield(val) || _isnativefield(val));\n        handle->_isNativeField = _isnativefield(val);\n        handle->_index = _member_idx(val);\n        v->Pop();\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"wrong index\");\n}\n\n// Handles field and method access. Native fields are handled directly\n// in sq_getbyhandle/sq_setbyhandle before calling this.\nSQRESULT _getmemberbyhandle(HSQUIRRELVM v,SQObjectPtr &self,const HSQMEMBERHANDLE *handle,SQObjectPtr *&val)\n{\n    switch(sq_type(self)) {\n        case OT_INSTANCE: {\n                SQInstance *i = _instance(self);\n                if(handle->_static) {\n                    SQClass *c = i->_class;\n                    val = &c->_methods[handle->_index].val;\n                }\n                else {\n                    val = &i->_values[handle->_index];\n                }\n            }\n            break;\n        case OT_CLASS: {\n                SQClass *c = _class(self);\n                if(handle->_static) {\n                    val = &c->_methods[handle->_index].val;\n                }\n                else {\n                    val = &c->_defaultvalues[handle->_index].val;\n                }\n            }\n            break;\n        default:\n            return sq_throwerror(v,\"wrong type(expected class or instance)\");\n    }\n    return SQ_OK;\n}\n\nSQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle)\n{\n    SQObjectPtr &self = stack_get(v,idx);\n    if (handle->_isNativeField) {\n        if (sq_type(self) != OT_INSTANCE)\n            return sq_throwerror(v, \"expected instance for native field\");\n        SQObjectPtr tmp;\n        _instance(self)->GetNativeField(handle->_index, tmp);\n        propagate_immutable(self, tmp);\n        v->Push(tmp);\n        return SQ_OK;\n    }\n    else {\n        SQObjectPtr *val = NULL;\n        if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) {\n            return SQ_ERROR;\n        }\n        SQObjectPtr res(_realval(*val));\n        propagate_immutable(self, res);\n        v->Push(res);\n        return SQ_OK;\n    }\n}\n\nSQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle)\n{\n    if (handle->_isNativeField) {\n        SQObjectPtr &self = stack_get(v,idx);\n        SQObjectPtr &newval = stack_get(v,-1);\n        if (sq_type(self) != OT_INSTANCE)\n            return sq_throwerror(v,\"expected instance for native field\");\n        if (!_instance(self)->SetNativeField(handle->_index, newval))\n            return sq_throwerror(v,\"type mismatch in native field assignment\");\n        v->Pop();\n        return SQ_OK;\n    }\n    SQObjectPtr &self = stack_get(v,idx);\n    SQObjectPtr &newval = stack_get(v,-1);\n    SQObjectPtr *val = NULL;\n    if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) {\n        return SQ_ERROR;\n    }\n    *val = newval;\n    v->Pop();\n    return SQ_OK;\n}\n\nSQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    if(_class(*o)->_base)\n        v->Push(SQObjectPtr(_class(*o)->_base));\n    else\n        v->PushNull();\n    return SQ_OK;\n}\n\nSQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_INSTANCE,o);\n    v->Push(SQObjectPtr(_instance(*o)->_class));\n    return SQ_OK;\n}\n\nSQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr *o = NULL;\n    _GETSAFE_OBJ(v, idx, OT_CLASS,o);\n    SQInstance *inst = _class(*o)->CreateInstance(v);\n    if (!inst)\n        return SQ_ERROR;\n    v->Push(SQObjectPtr(inst));\n    return SQ_OK;\n}\n\nvoid sq_weakref(HSQUIRRELVM v,SQInteger idx)\n{\n    const SQObjectPtr &o=stack_get(v,idx);\n    if(ISREFCOUNTED(sq_type(o))) {\n        v->Push(SQObjectPtr(_refcounted(o)->GetWeakRef(_ss(v)->_alloc_ctx, sq_type(o), o._flags)));\n        return;\n    }\n    v->Push(o);\n}\n\nSQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx)\n{\n    const SQObjectPtr &o = stack_get(v,idx);\n    if(sq_type(o) != OT_WEAKREF) {\n        return sq_throwerror(v,\"the object must be a weakref\");\n    }\n    v->Push(SQObjectPtr(_weakref(o)->_obj));\n    return SQ_OK;\n}\n\n\nSQRESULT sq_next(HSQUIRRELVM v,SQInteger idx)\n{\n    SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;\n    if(sq_type(o) == OT_GENERATOR) {\n        return sq_throwerror(v,\"cannot iterate a generator\");\n    }\n    int faketojump;\n    if(!v->FOREACH_OP(o,realkey,val,refpos,666,faketojump))\n        return SQ_ERROR;\n    if(faketojump != 666) {\n        v->Push(realkey);\n        v->Push(val);\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQCompilation::SqASTData *sq_parsetoast(HSQUIRRELVM v, const char *s, SQInteger size, const char *sourcename, SQBool preserveComments, SQBool raiseerror)\n{\n    return ParseToAST(v, s, size, sourcename, preserveComments, raiseerror);\n}\n\nvoid sq_dumpast(HSQUIRRELVM v, SQCompilation::SqASTData *astData, bool nodesLocation, OutputStream *s)\n{\n    IndentedTreeRenderer rv(s);\n    rv.printNodesLocation = nodesLocation;\n    rv.render(astData->root);\n}\n\nvoid sq_dumpbytecode(HSQUIRRELVM v, HSQOBJECT obj, OutputStream *s, int instruction_index)\n{\n    if (sq_isfunction(obj)) {\n        Dump(s, _funcproto(obj), true, instruction_index);\n    }\n    else if (sq_isclosure(obj)) {\n        SQFunctionProto *proto = _closure(obj)->_function;\n        Dump(s, proto, true, instruction_index);\n    }\n    else {\n        s->writeString(\"Object is not a FunctionProto\");\n    }\n}\n\nvoid sq_reset_static_memos(HSQUIRRELVM v, HSQOBJECT func)\n{\n    if (sq_isfunction(func)) {\n        ResetStaticMemos(_funcproto(func), _ss(v));\n    }\n    else if (sq_isclosure(func)) {\n        ResetStaticMemos(_closure(func)->_function, _ss(v));\n    }\n}\n\nSQRESULT sq_translateasttobytecode(HSQUIRRELVM v, SQCompilation::SqASTData *astData, const HSQOBJECT *bindings, const char *s, SQInteger size, SQBool raiseerror)\n{\n    SQObjectPtr o;\n    if (TranslateASTToBytecode(v, astData, bindings, s, size, o, raiseerror))\n    {\n        v->Push(SQObjectPtr(SQClosure::Create(_ss(v), _funcproto(o))));\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nSQRESULT sq_getimports(HSQUIRRELVM v, SQCompilation::SqASTData *astData, SQInteger *num, SQModuleImport **imports)\n{\n    return AstGetImports(v, astData, num, imports) ? SQ_OK : SQ_ERROR;\n}\n\nvoid sq_freeimports(HSQUIRRELVM v, SQInteger num, SQModuleImport *imports)\n{\n    AstFreeImports(v, num, imports);\n}\n\n\nvoid sq_analyzeast(HSQUIRRELVM v, SQCompilation::SqASTData *astData, const HSQOBJECT *bindings, const char *s, SQInteger size)\n{\n    AnalyzeCode(v, astData, bindings, s, size);\n}\n\nvoid sq_checktrailingspaces(HSQUIRRELVM v, const char *sourceName, const char *s, SQInteger size)\n{\n    StaticAnalyzer::checkTrailingWhitespaces(v, sourceName, s, size);\n}\n\nSQCompilation::SqASTData *sq_allocateASTData(HSQUIRRELVM v)\n{\n    SqASTData *astData = (SqASTData *)sq_vm_malloc(_ss(v)->_alloc_ctx, sizeof(SqASTData));\n\n    void *arenaPtr = sq_vm_malloc(_ss(v)->_alloc_ctx, sizeof(Arena));\n    astData->astArena = new (arenaPtr) Arena(_ss(v)->_alloc_ctx, \"AST\");\n\n    void *commentsPtr = sq_vm_malloc(_ss(v)->_alloc_ctx, sizeof(Comments));\n    astData->comments = new (commentsPtr) Comments(_ss(v)->_alloc_ctx);\n\n    astData->root = nullptr;\n    astData->sourceName[0] = 0;\n\n    return astData;\n}\n\nvoid sq_releaseASTData(HSQUIRRELVM v, SQCompilation::SqASTData *astData)\n{\n    if (!astData)\n        return;\n\n    Comments *comments = astData->comments;\n    if (comments)\n    {\n        comments->~Comments();\n        sq_vm_free(_ss(v)->_alloc_ctx, comments, sizeof(Comments));\n    }\n\n    Arena *arena = astData->astArena;\n    arena->~Arena();\n    sq_vm_free(_ss(v)->_alloc_ctx, arena, sizeof(Arena));\n\n    sq_vm_free(_ss(v)->_alloc_ctx, astData, sizeof(SQCompilation::SqASTData));\n}\n\nvoid sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx)\n{\n    dest->Push(stack_get(src,idx));\n}\n\nstatic bool validate_freezable(HSQUIRRELVM v, SQObjectPtr &o)\n{\n    SQObjectType tp = sq_type(o);\n    if (tp != OT_ARRAY && tp != OT_TABLE && tp != OT_INSTANCE && tp != OT_CLASS && tp != OT_USERDATA) {\n        v->Raise_Error(\"Cannot freeze %s\", IdType2Name(tp));\n        return false;\n    }\n    return true;\n}\n\nSQRESULT sq_freeze(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if (!validate_freezable(v, o))\n        return SQ_ERROR;\n\n    SQObjectPtr dst = o;\n    dst._flags |= SQOBJ_FLAG_IMMUTABLE;\n    v->Push(dst);\n    return SQ_OK;\n}\n\nSQUIRREL_API SQRESULT sq_freeze_inplace(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    if (!validate_freezable(v, o))\n        return SQ_ERROR;\n\n    o._flags |= SQOBJ_FLAG_IMMUTABLE;\n    return SQ_OK;\n}\n\nSQRESULT sq_mark_pure_inplace(HSQUIRRELVM v, SQInteger idx)\n{\n    SQObjectPtr &o = stack_get(v, idx);\n    SQObjectType tp = sq_type(o);\n    if (tp == OT_CLOSURE)\n        _closure(o)->_function->_purefunction = true;\n    else if (tp == OT_NATIVECLOSURE)\n        _nativeclosure(o)->_purefunction = true;\n    else {\n        v->Raise_Error(\"Type '%s' cannot be marked as a pure function\", IdType2Name(tp));\n        return SQ_ERROR;\n    }\n\n    return SQ_OK;\n}\n\nbool sq_is_pure_function(HSQOBJECT *func)\n{\n    if (!func)\n        return false;\n\n    SQObjectType tp = sq_type(*func);\n\n    if (tp == OT_CLOSURE)\n        return _closure(*func)->_function->_purefunction;\n    else if (tp == OT_NATIVECLOSURE)\n        return _nativeclosure(*func)->_purefunction;\n    else\n        return false;\n}\n\nvoid sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc)\n{\n    _ss(v)->_printfunc = printfunc;\n    _ss(v)->_errorfunc = errfunc;\n}\n\nSQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)\n{\n    return _ss(v)->_printfunc;\n}\n\nSQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v)\n{\n    return _ss(v)->_errorfunc;\n}\n\nSQAllocContext sq_getallocctx(HSQUIRRELVM v)\n{\n    return _ss(v)->_alloc_ctx;\n}\n\nvoid *sq_malloc(SQAllocContext ctx, SQUnsignedInteger size)\n{\n    return SQ_MALLOC(ctx, size);\n}\n\nvoid *sq_realloc(SQAllocContext ctx, void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize)\n{\n    return SQ_REALLOC(ctx,p,oldsize,newsize);\n}\n\nvoid sq_free(SQAllocContext ctx, void *p,SQUnsignedInteger size)\n{\n    SQ_FREE(ctx,p,size);\n}\n\nSQRESULT sq_limitthreadaccess(HSQUIRRELVM vm, int64_t tid)\n{\n    vm->check_thread_access = tid;\n    return SQ_OK;\n}\n\nbool sq_canaccessfromthisthread(HSQUIRRELVM vm)\n{\n    return vm->CanAccessFromThisThread();\n}\n\nvoid sq_resetanalyzerconfig() {\n  SQCompilation::resetAnalyzerConfig();\n}\n\nbool sq_loadanalyzerconfig(const char *configFileName) {\n  return SQCompilation::loadAnalyzerConfigFile(configFileName);\n}\n\nbool sq_loadanalyzerconfigblk(const KeyValueFile &config) {\n  return SQCompilation::loadAnalyzerConfigFile(config);\n}\n\nbool sq_setdiagnosticstatebyname(const char *diagId, bool state) {\n  return SQCompilationContext::enableWarning(diagId, state);\n}\n\nbool sq_setdiagnosticstatebyid(int32_t id, bool state) {\n  return SQCompilationContext::enableWarning(id, state);\n}\n\nvoid sq_printwarningslist(FILE *ostream) {\n  SQCompilationContext::printAllWarnings(ostream);\n}\n\nvoid sq_enablesyntaxwarnings(bool on) {\n  SQCompilationContext::switchSyntaxWarningsState(on);\n}\n\nvoid sq_checkglobalnames(HSQUIRRELVM v) {\n  StaticAnalyzer::reportGlobalNamesWarnings(v);\n}\n\nvoid sq_mergeglobalnames(const HSQOBJECT *bindings) {\n  StaticAnalyzer::mergeKnownBindings(bindings);\n}\n"
  },
  {
    "path": "squirrel/sqarray.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQARRAY_H_\n#define _SQARRAY_H_\n\n#include \"vartrace.h\"\n\nstruct SQArray : public CHAINABLE_OBJ\n{\nprivate:\n    SQArray(SQSharedState *ss,SQInteger nsize) :\n      _values(ss->_alloc_ctx)\n      VT_DECL_CTR(ss->_alloc_ctx)\n    {\n        _values.resize(nsize); VT_RESIZE(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\n    }\n    ~SQArray()\n    {\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n    }\npublic:\n    static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){\n        SQArray *newarray=(SQArray*)SQ_MALLOC(ss->_alloc_ctx, sizeof(SQArray));\n        new (newarray) SQArray(ss,nInitialSize);\n        return newarray;\n    }\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    SQObjectType GetType() {return OT_ARRAY;}\n#endif\n    void Finalize(){\n        _values.resize(0);\n        VT_RESIZE(0);\n    }\n\n    VT_CODE(VarTrace * GetVarTracePtr(const SQInteger nidx) { return &varTrace[nidx]; })\n\n    bool Get(const SQInteger nidx,SQObjectPtr &val)\n    {\n        if((SQUnsignedInteger)nidx<(SQUnsignedInteger)_values.size()){\n            SQObjectPtr &o = _values[nidx];\n            val = _realval(o);\n            return true;\n        }\n        else return false;\n    }\n    bool Set(const SQInteger nidx,const SQObjectPtr &val)\n    {\n        if((SQUnsignedInteger)nidx<(SQUnsignedInteger)_values.size()){\n            _values[nidx]=val;\n            VT_TRACE(nidx, val, _ss(this)->_root_vm);\n            return true;\n        }\n        else return false;\n    }\n    SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval)\n    {\n        SQUnsignedInteger idx=TranslateIndex(refpos);\n        if (idx<_values.size()) {\n            //first found\n            outkey=(SQInteger)idx;\n            SQObjectPtr &o = _values[idx];\n            outval = _realval(o);\n            //return idx for the next iteration\n            return ++idx;\n        }\n        //nothing to iterate anymore\n        return -1;\n    }\n    SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),0); anew->_values.copy(_values); VT_CLONE_FROM_TO(this, anew); return anew; }\n    SQInteger Size() const {return _values.size();}\n    void Resize(SQInteger size, SQBool shrink = SQTrue)\n    {\n        SQObjectPtr _null;\n        Resize(size,_null, shrink);\n    }\n    void Resize(SQInteger size,SQObjectPtr &fill, SQBool shrink = SQTrue)\n    {\n      _values.resize(size,fill);\n      VT_RESIZE(size);\n      if (shrink)\n        ShrinkIfNeeded();\n    }\n    void Reserve(SQInteger size) { _values.reserve(size); VT_RESERVE(size); }\n    void Append(const SQObject &o){_values.push_back(SQObjectPtr(o)); VT_PUSHBACK(o, _ss(this)->_root_vm); }\n    void Extend(const SQArray *a);\n    SQObjectPtr &Top(){return _values.top();}\n    void Pop(){_values.pop_back(); VT_POPBACK(); ShrinkIfNeeded(); }\n    bool Insert(SQInteger idx,const SQObject &val){\n        if(idx < 0 || idx > (SQInteger)_values.size())\n            return false;\n        _values.insert(idx,SQObjectPtr(val));\n        VT_INSERT(idx, val, _ss(this)->_root_vm);\n        return true;\n    }\n    void ShrinkIfNeeded() {\n        if(_values.size() <= _values.capacity()>>2) //shrink the array\n            _values.shrinktofit();\n    }\n    bool Remove(SQInteger idx, bool shrink=true){\n        if(idx < 0 || idx >= (SQInteger)_values.size())\n            return false;\n        _values.remove(idx);\n        VT_REMOVE(idx);\n        if (shrink)\n            ShrinkIfNeeded();\n        return true;\n    }\n    void Release()\n    {\n        SQAllocContext ctx = _values._alloc_ctx;\n        sq_delete(ctx, this, SQArray);\n    }\n    bool IsBinaryEqual(const SQArray *o);\n\n    SQObjectPtrVec _values;\n    VT_DECL_VEC;\n};\n#endif //_SQARRAY_H_\n"
  },
  {
    "path": "squirrel/sqbaselib.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqclass.h\"\n#include <sqstringlib.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include \"compiler/sqtypeparser.h\"\n#include <sq_char_class.h>\n\n#ifndef SQ_BASELIB_INVOKE_CB_ERR_HANDLER\n#define SQ_BASELIB_INVOKE_CB_ERR_HANDLER SQTrue\n#endif\n\n\nstatic SQInteger delegable_getfuncinfos(HSQUIRRELVM v);\nstatic SQInteger class_getfuncinfos(HSQUIRRELVM v);\nSQInteger sq_deduplicate_object(HSQUIRRELVM vm, int index);\n\n\n#define SQ_CHECK_IMMUTABLE_SELF \\\n    if (sq_objflags(stack_get(v,1)) & SQOBJ_FLAG_IMMUTABLE) \\\n        return sq_throwerror(v, \"Cannot modify immutable object\");\n\n#define SQ_CHECK_IMMUTABLE_OBJ(o) \\\n    if (sq_objflags(o) & SQOBJ_FLAG_IMMUTABLE) \\\n        return sq_throwerror(v, \"Cannot modify immutable object\");\n\n\nstatic bool sq_parse_float(const char* str_begin, const char * str_end, SQObjectPtr& res, SQInteger base)\n{\n#if SQ_USE_STD_FROM_CHARS\n    SQFloat r;\n    auto ret = std::from_chars(str_begin, str_end, r);\n    for (const char* ptr = ret.ptr; ptr != str_end; ++ptr)\n        if (*ptr != '0')\n            return false;\n    if (ret.ec == std::errc::invalid_argument)\n        return false;\n    res = r;\n#else\n    char* end;\n    SQFloat r = SQFloat(strtod(str_begin, &end));\n    if (str_begin == end)\n        return false;\n    res = r;\n#endif\n    return true;\n}\n\nstatic bool sq_parse_int(const char* str_begin, const char* str_end, SQObjectPtr& res, SQInteger base)\n{\n    char* end;\n    const char* e = str_begin;\n    bool iseintbase = base > 13; //to fix error converting hexadecimals with e like 56f0791e\n    char c;\n    while ((c = *e) != '\\0')\n    {\n        if (c == '.' || (!iseintbase && (c == 'E' || c == 'e'))) //e and E is for scientific notation\n            return sq_parse_float(str_begin, str_end, res, base);\n        e++;\n    }\n\n    SQInteger r = SQInteger(scstrtol(str_begin, &end, (int)base));\n    if (str_begin == end)\n        return false;\n    res = r;\n    return true;\n}\n\n\nstatic SQInteger get_allowed_args_count(const SQObject &closure, SQInteger num_supported)\n{\n    if(sq_type(closure) == OT_CLOSURE) {\n        return _closure(closure)->_function->_nparameters;\n    }\n    else if (sq_type(closure) == OT_NATIVECLOSURE) {\n        SQInteger nParamsCheck = _nativeclosure(closure)->_nparamscheck;\n        if (nParamsCheck > 0)\n            return nParamsCheck;\n        else // push all params when there is no check or only minimal count set\n            return num_supported;\n    }\n    assert(false);\n    return -1;\n}\n\nstatic SQInteger base_getroottable(HSQUIRRELVM v)\n{\n    v->Push(v->_roottable);\n    return 1;\n}\n\nstatic SQInteger base_getconsttable(HSQUIRRELVM v)\n{\n    v->Push(_ss(v)->_consts);\n    return 1;\n}\n\nSQInteger __sq_getcallstackinfos(HSQUIRRELVM v,SQInteger level)\n{\n    SQStackInfos si;\n    SQInteger seq = 0;\n    const char *name = NULL;\n\n    if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si)))\n    {\n        const char *fn = \"unknown\";\n        const char *src = \"unknown\";\n        if(si.funcname)fn = si.funcname;\n        if(si.source)src = si.source;\n        sq_newtable(v);\n        sq_pushstring(v, \"func\", -1);\n        sq_pushstring(v, fn, -1);\n        sq_newslot(v, -3, SQFalse);\n        sq_pushstring(v, \"src\", -1);\n        sq_pushstring(v, src, -1);\n        sq_newslot(v, -3, SQFalse);\n        sq_pushstring(v, \"line\", -1);\n        sq_pushinteger(v, si.line);\n        sq_newslot(v, -3, SQFalse);\n        sq_pushstring(v, \"locals\", -1);\n        sq_newtable(v);\n        seq=0;\n        while ((name = sq_getlocal(v, level, seq))) {\n            sq_pushstring(v, name, -1);\n            sq_push(v, -2);\n            sq_newslot(v, -4, SQFalse);\n            sq_pop(v, 1);\n            seq++;\n        }\n        sq_newslot(v, -3, SQFalse);\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic SQInteger base_assert(HSQUIRRELVM v)\n{\n    if(SQVM::IsFalse(stack_get(v,2))){\n        if (sq_gettop(v) > 2) {\n            SQObjectPtr &arg = stack_get(v,3);\n            SQInteger msgIdx = 0;\n            if (sq_type(arg)==OT_CLOSURE || sq_type(arg)==OT_NATIVECLOSURE) {\n                sq_pushroottable(v);\n                if (SQ_SUCCEEDED(sq_call(v, 1, SQTrue, SQFalse)))\n                    msgIdx = -1;\n            }\n            else\n                msgIdx = 3;\n\n            if (msgIdx!=0 && SQ_SUCCEEDED(sq_tostring(v,msgIdx))) {\n                const char *str = 0;\n                if (SQ_SUCCEEDED(sq_getstring(v,-1,&str)))\n                    return sq_throwerror(v, str);\n            }\n        }\n\n        return sq_throwerror(v, \"assertion failed\");\n    }\n    return 0;\n}\n\nstatic SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o)\n{\n    SQInteger top = sq_gettop(v);\n    sidx=0;\n    eidx=0;\n    o=stack_get(v,1);\n    if(top>1){\n        SQObjectPtr &start=stack_get(v,2);\n        if(sq_type(start)!=OT_NULL && sq_isnumeric(start)){\n            sidx=tointeger(start);\n        }\n    }\n    if(top>2){\n        SQObjectPtr &end=stack_get(v,3);\n        if(sq_isnumeric(end)){\n            eidx=tointeger(end);\n        }\n    }\n    else {\n        eidx = sq_getsize(v,1);\n    }\n    return 1;\n}\n\nstatic SQInteger base_print(HSQUIRRELVM v, SQPRINTFUNCTION pf, bool newline)\n{\n    if (!pf) return 0;\n\n    const SQInteger top = sq_gettop(v);\n    SQObjectPtr s;\n\n    for (SQInteger i = 2; i <= top; ++i) {\n        if (i > 2)\n            pf(v, \" \");\n\n        if (v->ToString(stack_get(v, i), s))\n            pf(v, \"%s\", _stringval(s));\n        else\n            pf(v, \"< _tostring() call error >\");\n    }\n\n    if (newline)\n        pf(v, \"\\n\");\n\n    return 0;\n}\n\nstatic SQInteger base_print_newline(HSQUIRRELVM v)\n{\n    return base_print(v, _ss(v)->_printfunc, true);\n}\n\nstatic SQInteger base_print_(HSQUIRRELVM v)\n{\n    return base_print(v, _ss(v)->_printfunc, false);\n}\n\nstatic SQInteger base_error_newline(HSQUIRRELVM v)\n{\n    return base_print(v, _ss(v)->_errorfunc, true);\n}\n\nstatic SQInteger base_error_(HSQUIRRELVM v)\n{\n    return base_print(v, _ss(v)->_errorfunc, false);\n}\n\nstatic SQInteger base_compilestring(HSQUIRRELVM v)\n{\n    SQInteger nargs=sq_gettop(v);\n    const char *src=NULL,*name=\"unnamedbuffer\";\n    SQInteger size;\n    sq_getstringandsize(v,2,&src,&size);\n    if (nargs>2) {\n        sq_getstring(v,3,&name);\n    }\n\n    HSQOBJECT bindings;\n    bool ownBindings = false;\n    if (nargs>3) {\n        sq_getstackobj(v, 4, &bindings);\n    }\n    else {\n        ownBindings = true;\n        sq_newtable(v);\n        sq_getstackobj(v, -1, &bindings);\n        sq_addref(v, &bindings);\n        sq_poptop(v);\n    }\n\n    // overwrites existing keys in bindings with ones from base lib\n    sq_pushobject(v, bindings);\n    sq_registerbaselib(v);\n    sq_poptop(v);\n\n    bool ok = SQ_SUCCEEDED(sq_compile(v, src, size, name, SQFalse, &bindings));\n\n    if (ownBindings)\n        sq_release(v, &bindings);\n\n    return ok ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger base_newthread(HSQUIRRELVM v)\n{\n    SQObjectPtr &func = stack_get(v,2);\n    SQInteger stksize = (_closure(func)->_function->_stacksize << 1) + 2; // -V629\n    HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize);\n    sq_move(newv,v,-2);\n    return 1;\n}\n\nstatic SQInteger base_suspend(HSQUIRRELVM v)\n{\n    return sq_suspendvm(v);\n}\n\nstatic SQInteger builtin_array_ctor(HSQUIRRELVM v)\n{\n    SQInteger size = tointeger(stack_get(v,2));\n    if (size < 0)\n        return sq_throwerror(v, \"array size must be non-negative\");\n\n    SQArray *a;\n    if(sq_gettop(v) > 2) {\n        a = SQArray::Create(_ss(v),0);\n        a->Resize(size,stack_get(v,3));\n    }\n    else {\n        a = SQArray::Create(_ss(v),size);\n    }\n    v->Push(SQObjectPtr(a));\n    return 1;\n}\n\nstatic SQInteger base_type(HSQUIRRELVM v)\n{\n    SQObjectPtr &o = stack_get(v,2);\n    v->Push(SQObjectPtr(SQString::Create(_ss(v),GetTypeName(o),-1)));\n    return 1;\n}\n\nstatic SQInteger base_callee(HSQUIRRELVM v)\n{\n    if(v->_callsstacksize > 1)\n    {\n        v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);\n        return 1;\n    }\n    return sq_throwerror(v,\"no closure in the calls stack\");\n}\n\nstatic SQInteger base_freeze(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_freeze(v, 2)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger base_getobjflags(HSQUIRRELVM v)\n{\n    sq_pushinteger(v, sq_objflags(stack_get(v, 2)));\n    return 1;\n}\n\nstatic SQInteger base_deduplicate_object(HSQUIRRELVM v)\n{\n    return sq_deduplicate_object(v, 2);\n}\n\nstatic SQInteger base_classof(HSQUIRRELVM v)\n{\n    SQObjectPtr &obj = stack_get(v, 2);\n\n    if (sq_type(obj) == OT_INSTANCE) {\n        v->Push(SQObjectPtr(_instance(obj)->_class));\n        return 1;\n    }\n    else if (SQClass *cls = v->GetBuiltInClassForType(sq_type(obj))) {\n        v->Push(SQObjectPtr(cls));\n        return 1;\n    }\n\n    assert(0);\n    return 0;\n}\n\nstatic const SQRegFunctionFromStr base_funcs[] = {\n    { base_getroottable, \"getroottable(): table\" },\n    { base_getconsttable, \"getconsttable(): table\" },\n    { base_assert, \"assert(condition, [message: function|string])\" },\n    { base_print_, \"print(...)\" },\n    { base_print_newline, \"println(...)\" },\n    { base_error_, \"error(...)\" },\n    { base_error_newline, \"errorln(...)\" },\n    { base_compilestring, \"compilestring(source: string, [name: string, bindings: table|null]): function\" },\n    { base_newthread, \"newthread(func: function): thread\" },\n    { base_suspend, \"suspend(...): any\" },\n    { builtin_array_ctor, \"array(size: int, [default_value]): array\" },\n    { base_type, \"pure type(obj): string\" },\n    { base_callee, \"callee(): function\" },\n    { base_freeze, \"freeze(obj): any\" },\n    { base_deduplicate_object, \"deduplicate_object(obj: table|array|null): table|array|null\" },\n    { base_getobjflags, \"getobjflags(obj): int\" },\n    { NULL, NULL }\n};\n\n\nSQRESULT sq_registerbaselib(HSQUIRRELVM v)\n{\n    SQInteger i=0;\n    while(base_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, base_funcs[i].f, 0, base_funcs[i].declstring, base_funcs[i].docstring);\n        i++;\n    }\n\n    return SQ_OK;\n}\n\n\nstatic const SQRegFunctionFromStr types_funcs[] = {\n    { base_classof, \"pure classof(obj): class\" },\n    { NULL, NULL }\n};\n\nSQRESULT sq_registertypeslib(HSQUIRRELVM v)\n{\n    SQInteger i=0;\n    while(types_funcs[i].f) {\n        sq_new_closure_slot_from_decl_string(v, types_funcs[i].f, 0, types_funcs[i].declstring, types_funcs[i].docstring);\n        i++;\n    }\n\n    #define REG_CLS(name, cls) \\\n        sq_pushstring(v, #name, -1); \\\n        v->Push(cls); \\\n        sq_newslot(v, -3, SQFalse);\n\n    REG_CLS(Integer, _ss(v)->_integer_class)\n    REG_CLS(Float, _ss(v)->_float_class);\n    REG_CLS(Bool, _ss(v)->_bool_class);\n    REG_CLS(String, _ss(v)->_string_class);\n    REG_CLS(Array, _ss(v)->_array_class);\n    REG_CLS(Table, _ss(v)->_table_class);\n    REG_CLS(Function, _ss(v)->_function_class);\n    REG_CLS(Generator, _ss(v)->_generator_class);\n    REG_CLS(Thread, _ss(v)->_thread_class);\n    REG_CLS(Class, _ss(v)->_class_class);\n    REG_CLS(Instance, _ss(v)->_instance_class);\n    REG_CLS(WeakRef, _ss(v)->_weakref_class);\n    REG_CLS(UserData, _ss(v)->_userdata_class);\n    REG_CLS(Null, _ss(v)->_null_class);\n\n    #undef REG_CLS\n\n    return SQ_OK;\n}\n\n\nvoid sq_base_register(HSQUIRRELVM v)\n{\n    sq_pushroottable(v);\n    sq_registerbaselib(v);\n    sq_pop(v,1);\n\n    sq_pushconsttable(v);\n    sq_pushstring(v, \"SQOBJ_FLAG_IMMUTABLE\", -1);\n    sq_pushinteger(v, SQOBJ_FLAG_IMMUTABLE);\n    sq_newslot(v, -3, SQFalse);\n    sq_pop(v,1);\n}\n\nstatic SQInteger default_type_method_len(HSQUIRRELVM v)\n{\n    v->Push(SQObjectPtr(SQInteger(sq_getsize(v,1))));\n    return 1;\n}\n\nstatic SQInteger default_type_method_tofloat(HSQUIRRELVM v)\n{\n    SQObjectPtr &o=stack_get(v,1);\n    switch(sq_type(o)){\n    case OT_STRING:{\n        SQObjectPtr res;\n        if(sq_parse_float(_stringval(o), _stringval(o) + _string(o)->_len, res, 10)){\n            v->Push(SQObjectPtr(tofloat(res)));\n            break;\n        }}\n        return sq_throwerror(v, \"cannot convert the string to float\");\n    case OT_INTEGER:case OT_FLOAT:\n        v->Push(SQObjectPtr(tofloat(o)));\n        break;\n    case OT_BOOL:\n        v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0)));\n        break;\n    default:\n        v->PushNull();\n        break;\n    }\n    return 1;\n}\n\nstatic SQInteger default_type_method_tointeger(HSQUIRRELVM v)\n{\n    SQObjectPtr &o=stack_get(v,1);\n    SQInteger base = 10;\n    if(sq_gettop(v) > 1) {\n        sq_getinteger(v,2,&base);\n    }\n    switch(sq_type(o)){\n    case OT_STRING:{\n        SQObjectPtr res;\n        if(sq_parse_int(_stringval(o), _stringval(o) + _string(o)->_len, res, base)){\n            v->Push(SQObjectPtr(tointeger(res)));\n            break;\n        }}\n        return sq_throwerror(v, \"cannot convert the string to integer\");\n        break;\n    case OT_INTEGER:case OT_FLOAT:\n        v->Push(SQObjectPtr(tointeger(o)));\n        break;\n    case OT_BOOL:\n        v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0));\n        break;\n    default:\n        v->PushNull();\n        break;\n    }\n    return 1;\n}\n\nstatic SQInteger default_type_method_tostring(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_tostring(v,1)))\n        return SQ_ERROR;\n    return 1;\n}\n\nstatic SQInteger obj_type_method_weakref(HSQUIRRELVM v)\n{\n    sq_weakref(v,1);\n    return 1;\n}\n\nstatic SQInteger obj_clear(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n    return SQ_SUCCEEDED(sq_clear(v,-1)) ? 1 : SQ_ERROR;\n}\n\n\nstatic SQInteger number_type_method_tochar(HSQUIRRELVM v)\n{\n    SQObject &o=stack_get(v,1);\n    char c = (char)tointeger(o);\n    v->Push(SQObjectPtr(SQString::Create(_ss(v),(const char *)&c,1)));\n    return 1;\n}\n\n\nstatic SQInteger container_update(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    SQInteger top = sq_gettop(v);\n    for (int arg=2; arg<=top; ++arg) {\n        SQObjectType argType = sq_gettype(v, arg);\n        if (!(argType & (_RT_TABLE | _RT_CLASS | _RT_INSTANCE))) {\n            v->Raise_ParamTypeError(arg, _RT_TABLE | _RT_CLASS | _RT_INSTANCE, argType);\n            return SQ_ERROR;\n        }\n\n        sq_pushnull(v);\n        while (SQ_SUCCEEDED(sq_next(v, arg))) {\n            sq_newslot(v, 1, false);\n        }\n        sq_pop(v, 1); // pops the iterator\n    }\n    sq_push(v, 1);\n    return 1;\n}\n\n\nstatic SQInteger container_merge(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n\n    SQInteger top = sq_gettop(v);\n    switch (sq_type(o)) {\n        case OT_TABLE:\n            sq_newtableex(v, sq_getsize(v, 1));\n            break;\n        case OT_CLASS:\n            sq_newclass(v, SQFalse);\n            break;\n        default:\n            return sq_throwerror(v, \"merge() only works on tables and classes\");\n    }\n\n    for (int arg=1; arg<=top; ++arg) {\n        SQObjectType argType = sq_gettype(v, arg);\n        if (!(argType & (_RT_TABLE | _RT_CLASS | _RT_INSTANCE))) {\n            v->Raise_ParamTypeError(arg, _RT_TABLE | _RT_CLASS | _RT_INSTANCE, argType);\n            return SQ_ERROR;\n        }\n\n        sq_pushnull(v);\n        while (SQ_SUCCEEDED(sq_next(v, arg))) {\n            sq_newslot(v, top+1, false);\n        }\n        sq_pop(v, 1); // pops the iterator\n    }\n    return 1;\n}\n\n\nstatic SQInteger container_each(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    const SQObjectPtr &closure = stack_get(v, 2);\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n    SQObjectPtr tmp;\n\n    sq_pushnull(v);\n    while (SQ_SUCCEEDED(sq_next(v, 1))) {\n        SQInteger iterTop = sq_gettop(v);\n        v->PushNull();\n        v->Push(stack_get(v, iterTop));\n        if (nArgs >= 3)\n            v->Push(stack_get(v, iterTop-1));\n        if (nArgs >= 4)\n            v->Push(o);\n\n        bool callRes = v->Call(closure, nArgs, v->_top-nArgs, tmp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        v->Pop(2+nArgs);\n        if (!callRes)\n            return SQ_ERROR;\n    }\n    sq_pop(v, 1); // pops the iterator\n\n    return 0;\n}\n\n\nstatic SQInteger container_findindex(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    const SQObjectPtr &closure = stack_get(v, 2);\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n    SQObjectPtr tmp;\n\n    sq_pushnull(v);\n    while (SQ_SUCCEEDED(sq_next(v, 1))) {\n        SQInteger iterTop = sq_gettop(v);\n        v->PushNull();\n        v->Push(stack_get(v, iterTop));\n        if (nArgs >= 3)\n            v->Push(stack_get(v, iterTop-1));\n        if (nArgs >= 4)\n            v->Push(o);\n\n        bool callRes = v->Call(closure, nArgs, v->_top-nArgs, tmp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        if (!callRes)\n            return SQ_ERROR;\n\n        if (!v->IsFalse(tmp)) {\n            v->Push(stack_get(v, iterTop-1));\n            return 1;\n        }\n        v->Pop(2+nArgs);\n    }\n    sq_pop(v, 1); // pops the iterator\n\n    return 0;\n}\n\nstatic SQInteger container_findvalue(HSQUIRRELVM v)\n{\n    if (sq_gettop(v) > 3)\n        return sq_throwerror(v, \"Too many arguments for findvalue()\");\n\n    const SQObjectPtr &o = stack_get(v,1);\n    const SQObjectPtr &closure = stack_get(v, 2);\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n    SQObjectPtr tmp;\n\n    sq_pushnull(v);\n    while (SQ_SUCCEEDED(sq_next(v, 1))) {\n        SQInteger iterTop = sq_gettop(v);\n\n        v->PushNull();\n        v->Push(stack_get(v, iterTop));\n        if (nArgs >= 3)\n            v->Push(stack_get(v, iterTop-1));\n        if (nArgs >= 4)\n            v->Push(o);\n\n        bool callRes = v->Call(closure, nArgs, v->_top-nArgs, tmp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        if (!callRes)\n            return SQ_ERROR;\n\n        if (!v->IsFalse(tmp)) {\n            v->Push(stack_get(v, iterTop));\n            return 1;\n        }\n        v->Pop(2+nArgs);\n    }\n    sq_pop(v, 1); // pops the iterator\n\n    return sq_gettop(v) > 2 ? 1 : 0;\n}\n\nstatic SQInteger container_hasindex(HSQUIRRELVM v)\n{\n    const SQObjectPtr &self = stack_get(v, 1);\n    SQObjectType t = sq_type(self);\n    if (t != OT_TABLE && t != OT_CLASS && t != OT_INSTANCE)\n        return sq_throwerror(v, \"hasindex not supported for this type\");\n\n    const SQObjectPtr &key = stack_get(v, 2);\n    v->Push(self);\n    v->Push(key);\n    bool exists = SQ_SUCCEEDED(sq_rawget(v, -2));\n    sq_pushbool(v, exists);\n    return 1;\n}\n\nstatic SQInteger container_hasvalue(HSQUIRRELVM v)\n{\n    const SQObject &o = stack_get(v, 1);\n    SQObjectType t = sq_type(o);\n    if (t != OT_TABLE)\n        return sq_throwerror(v, \"hasvalue not supported for this type\");\n\n    const SQObjectPtr &value = stack_get(v, 2);\n    bool found = false;\n\n    SQTable *tbl = _table(o);\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    while ((nitr = tbl->Next(false, itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n        if (SQVM::IsEqual(val, value)) {\n            found = true;\n            break;\n         }\n    }\n    sq_pushbool(v, found);\n    return 1;\n}\n\n\nstatic SQInteger table_rawdelete(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue)))\n        return SQ_ERROR;\n    return 1;\n}\n\n\nstatic SQInteger container_rawexists(HSQUIRRELVM v)\n{\n    if(SQ_SUCCEEDED(sq_rawget(v,-2))) {\n        sq_pushbool(v,SQTrue);\n        return 1;\n    }\n    sq_pushbool(v,SQFalse);\n    return 1;\n}\n\nstatic SQInteger container_rawset(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    return SQ_SUCCEEDED(sq_rawset(v,-3)) ? 1 : SQ_ERROR;\n}\n\n\nstatic SQInteger container_rawget(HSQUIRRELVM v)\n{\n    // container type check is done by the typemask\n    if (SQ_FAILED(sq_rawget(v, 1)))\n        return sq_throwerror(v,\"the index doesn't exist\");\n    return 1;\n}\n\n\nstatic SQInteger table_filter(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    SQTable *tbl = _table(o);\n    const SQObjectPtr &closure = stack_get(v, 2);\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n\n    SQObjectPtr ret(SQTable::Create(_ss(v),0));\n    SQObjectPtr temp;\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    while((nitr = tbl->Next(false, itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n\n        v->PushNull();\n        v->Push(val);\n        if (nArgs >= 3)\n            v->Push(key);\n        if (nArgs >= 4)\n            v->Push(o);\n\n        bool callRes = v->Call(closure, nArgs, v->_top - nArgs, temp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        v->Pop(nArgs);\n        if (!callRes)\n            return SQ_ERROR;\n\n        if (!SQVM::IsFalse(temp)) {\n            _table(ret)->NewSlot(key, val);\n        }\n    }\n\n    v->Push(ret);\n    return 1;\n}\n\n#define TABLE_TO_ARRAY_FUNC(_funcname_,_valname_) static SQInteger _funcname_(HSQUIRRELVM v) \\\n{ \\\n    SQObject &o = stack_get(v, 1); \\\n    SQTable *t = _table(o); \\\n    SQObjectPtr itr, key, val; \\\n    SQInteger nitr, n = 0; \\\n    SQInteger nitems = t->CountUsed(); \\\n    SQArray *a = SQArray::Create(_ss(v), nitems); \\\n    if (nitems) { \\\n        while ((nitr = t->Next(false, itr, key, val)) != -1) { \\\n            itr = (SQInteger)nitr; \\\n            a->Set(n, _valname_); \\\n            n++; \\\n        } \\\n    } \\\n    v->Push(SQObjectPtr(a)); \\\n    return 1; \\\n}\n\nTABLE_TO_ARRAY_FUNC(table_keys, key)\nTABLE_TO_ARRAY_FUNC(table_values, val)\n\n\nstatic SQInteger table_to_pairs(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v, 1);\n    SQTable *t = _table(o);\n    SQObjectPtr itr, key, val;\n    SQInteger nitr, n = 0;\n    SQInteger nitems = t->CountUsed();\n    SQArray *result = SQArray::Create(_ss(v), nitems);\n    if (nitems) {\n        while ((nitr = t->Next(false, itr, key, val)) != -1) {\n            itr = (SQInteger)nitr;\n            SQArray *item = SQArray::Create(_ss(v), 2);\n            item->Set(0, key);\n            item->Set(1, val);\n            result->Set(n, SQObjectPtr(item));\n            n++;\n        }\n    }\n    v->Push(SQObjectPtr(result));\n    return 1;\n}\n\nstatic SQInteger swap(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n    SQObjectPtr &o = stack_get(v, 1);\n    SQObjectPtr &key1 = stack_get(v, 2);\n    SQObjectPtr &key2 = stack_get(v, 3);\n    switch(sq_type(o)) {\n        case OT_ARRAY: {\n            SQArray *arr = _array(o);\n            if (!sq_isnumeric(key1) || !sq_isnumeric(key2))\n                return sq_throwerror(v,\"invalid index type for an array\");\n\n            const int asize = arr->Size();\n            int k1 = tointeger(key1);\n            k1 = k1 >= 0 ? k1 : asize + k1;\n            int k2 = tointeger(key2);\n            k2 = k2 >= 0 ? k2 : asize + k2 ;\n            if( k1 >= asize || k2 >= asize || k1 < 0 || k2 < 0)\n                return sq_throwerror(v,\"index is out of range\");\n\n            _Swap(_array(o)->_values[k1], _array(o)->_values[k2]);\n            break;\n        }\n        case OT_TABLE: {\n            SQObjectPtr val1, val2;\n            if (!_table(o)->Get(key1, val1) || !_table(o)->Get(key2, val2))\n                sq_throwerror(v,\"the index doesn't exist\");\n\n            _table(o)->Set(key1, val2);\n            _table(o)->Set(key2, val1);\n            break;\n        }\n        case OT_INSTANCE: {\n            SQObjectPtr val1, val2;\n            if (!_instance(o)->Get(key1, val1) || !_instance(o)->Get(key2, val2))\n                return sq_throwerror(v,\"the index doesn't exist\");\n\n            _instance(o)->Set(key1, val2);\n            _instance(o)->Set(key2, val1);\n            break;\n        }\n        default:\n            return sq_throwerror(v,\"swap works only on array/table/instance\");\n    }\n    v->Push(o);\n    return 1;\n}\n\nstatic SQInteger array_to_table(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v, 1);\n    SQArray *arr = _array(o);\n    SQInteger count = arr->Size();\n    SQTable *result = SQTable::Create(_ss(v), count);\n\n    if (count == 0)\n    {\n        v->Push(SQObjectPtr(result));\n        return 1;\n    }\n\n    SQObjectPtr item;\n    bool expectArrays = arr->Get(0, item) && sq_isarray(item);\n\n    for (SQInteger i = 0; i < count; i++)\n    {\n        SQObjectPtr key;\n        SQObjectPtr val;\n\n        if (!arr->Get(i, item))\n            return sq_throwerror(v, \"totable() failed to get element from array\");\n\n        bool isSimpleType = sq_isstring(item) || sq_isnumeric(item) || sq_isbool(item) || sq_isnull(item);\n\n        if (expectArrays && sq_isarray(item) && _array(item)->Get(0, key) && _array(item)->Get(1, val) && _array(item)->Size() == 2)\n            result->NewSlot(key, val);\n        else if (!expectArrays && isSimpleType)\n            result->NewSlot(item, item);\n        else\n        {\n            if (expectArrays && sq_isarray(item) && _array(item)->Size() != 2)\n                return sq_throwerror(v, \"totable() expected array of pairs [[key, value], ...], size of the each pair array must be exactly 2 elements\");\n            else\n                return sq_throwerror(v, \"totable() expected array of pairs [[key, value], ...] or array of simple types [\\\"key1\\\", \\\"key2\\\", ...]\");\n        }\n    }\n\n    v->Push(SQObjectPtr(result));\n    return 1;\n}\n\n\nstatic SQInteger __map_table(SQTable *dest, SQTable *src, HSQUIRRELVM v) {\n    const SQObjectPtr &closure = stack_get(v, 2);\n\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    SQObjectPtr temp;\n    SQObjectPtr srcObj(src);\n    while ((nitr = src->Next(false, itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n\n        v->PushNull();\n        v->Push(val);\n        if (nArgs >= 3)\n            v->Push(key);\n        if (nArgs >= 4)\n            v->Push(srcObj);\n\n        bool callRes = v->Call(closure, nArgs, v->_top - nArgs, temp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        v->Pop(nArgs);\n        if (!callRes) {\n            if (sq_isnull(v->_lasterror))\n                continue;\n            else\n                return SQ_ERROR;\n        }\n\n        dest->NewSlot(key, temp);\n    }\n\n    return 0;\n}\n\nstatic SQInteger table_map(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v, 1);\n    SQObjectPtr ret(SQTable::Create(_ss(v), _table(o)->CountUsed()));\n    if(SQ_FAILED(__map_table(_table(ret), _table(o), v)))\n        return SQ_ERROR;\n    v->Push(ret);\n    return 1;\n}\n\n\nstatic SQInteger table_reduce(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    SQTable *tbl = _table(o);\n    const SQObjectPtr &closure = stack_get(v, 2);\n\n    bool gotAccum = false;\n    SQObjectPtr accum;\n\n    SQInteger nArgs = get_allowed_args_count(closure, 5);\n\n    if (sq_gettop(v) > 2) {\n        accum = stack_get(v, 3);\n        gotAccum = true;\n    }\n\n    SQObjectPtr itr, key, val;\n    SQInteger nitr;\n    while ((nitr = tbl->Next(false, itr, key, val)) != -1) {\n        itr = (SQInteger)nitr;\n\n        if (!gotAccum) {\n            accum = val;\n            gotAccum = true;\n        } else {\n            v->PushNull();\n            v->Push(accum);\n            v->Push(val);\n            if (nArgs >= 4)\n                v->Push(key);\n            if (nArgs >= 5)\n                v->Push(o);\n\n            bool callRes = v->Call(closure, nArgs, v->_top - nArgs, accum, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n            v->Pop(nArgs);\n            if (!callRes)\n                return SQ_ERROR;\n        }\n    }\n\n    if (!gotAccum)\n        return 0;\n\n    v->Push(accum);\n    return 1;\n}\n\nstatic SQInteger table_replace_with(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    SQTable *dst = _table(stack_get(v, 1));\n    dst->Clear(false);\n\n    // Alternatively, consider copying hash nodes directly instead of iterating slots\n    sq_pushnull(v);\n    while (SQ_SUCCEEDED(sq_next(v, 2)))\n        sq_newslot(v, 1, false);\n    sq_pop(v, 1); // pop iterator\n\n    v->Pop(1); // pop src, leave dst on stack as the return value\n    return 1;\n}\n\nstatic SQInteger obj_clone(HSQUIRRELVM vm) {\n    SQObjectPtr self = vm->PopGet();\n    SQObjectPtr target;\n\n    if (!vm->Clone(self, target)) {\n      return SQ_ERROR;\n    }\n\n    vm->Push(target);\n    return 1;\n}\n\nstatic SQInteger obj_is_frozen(HSQUIRRELVM vm) {\n  SQObjectPtr self = vm->PopGet();\n  SQObjectPtr target;\n\n  sq_pushbool(vm, (self._flags & SQOBJ_FLAG_IMMUTABLE) != 0);\n\n  return 1;\n}\n\nstatic SQInteger builtin_null_ctor(HSQUIRRELVM v);\nstatic SQInteger builtin_integer_ctor(HSQUIRRELVM v);\nstatic SQInteger builtin_float_ctor(HSQUIRRELVM v);\nstatic SQInteger builtin_bool_ctor(HSQUIRRELVM v);\nstatic SQInteger builtin_string_ctor(HSQUIRRELVM v);\nstatic SQInteger builtin_table_ctor(HSQUIRRELVM v);\nstatic SQInteger builtin_weakref_ctor(HSQUIRRELVM v);\n\nconst SQRegFunction SQSharedState::_table_default_type_methods_funcz[]={\n    {\"constructor\",builtin_table_ctor,1, NULL},\n    {\"len\",default_type_method_len,1, \"t\", NULL, true},\n    {\"rawget\",container_rawget,2, \"t\", NULL, true},\n    {\"rawset\",container_rawset,3, \"t\"},\n    {\"rawdelete\",table_rawdelete,2, \"t\"},\n    {\"rawin\",container_rawexists,2, \"t\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"clear\",obj_clear,1, \".\"},\n    {\"map\",table_map,2, \"tc\"},\n    {\"filter\",table_filter,2, \"tc\"},\n    {\"reduce\",table_reduce, -2, \"tc\"},\n    {\"getfuncinfos\",delegable_getfuncinfos,1, \"t\"},\n    {\"each\",container_each,2, \"tc\"},\n    {\"findindex\",container_findindex,2, \"tc\", NULL, true},\n    {\"findvalue\",container_findvalue,-2, \"tc.\", NULL, true},\n    {\"keys\",table_keys,1, \"t\", NULL, true},\n    {\"values\",table_values,1, \"t\", NULL, true},\n    {\"__update\",container_update, -2, \"t|yt|y|x\", NULL, false},\n    {\"__merge\",container_merge, -2, \"t|yt|y|x\", NULL, true},\n    {\"topairs\",table_to_pairs, 1, \"t\" },\n    {\"replace_with\",table_replace_with, 2, \"tt\" },\n    {\"hasindex\",container_hasindex,2, \"t.\", NULL, true},\n    {\"hasvalue\",container_hasvalue,2, \"t.\", NULL, true},\n    {\"clone\",obj_clone, 1, \".\" },\n    {\"is_frozen\",obj_is_frozen, 1, \".\" },\n    {\"swap\",swap, 3, \"t..\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// Array type methods\n\nstatic SQInteger array_append(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    SQArray *arr = _array(stack_get(v, 1));\n    SQInteger nitems = sq_gettop(v)-1;\n    SQInteger offs = arr->Size();\n    arr->Resize(offs + nitems);\n    for (SQInteger i=0; i<nitems; ++i)\n        arr->Set(offs+i, stack_get(v, 2+i));\n\n    v->Push(stack_get(v, 1));\n    return 1;\n}\n\nstatic SQInteger array_extend(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    SQArray *arr = _array(stack_get(v, 1));\n    SQInteger n = sq_gettop(v)-1;\n\n    for (SQInteger i=0; i<n; ++i) {\n        if (sq_type(stack_get(v,2+i)) != OT_ARRAY)\n            return sq_throwerror(v, \"only arrays can be used to extend array\");\n    }\n\n    for (SQInteger i=0; i<n; ++i) {\n        arr->Extend(_array(stack_get(v,2+i)));\n    }\n\n    sq_pop(v,n);\n    return 1;\n}\n\nstatic SQInteger array_reverse(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    return SQ_SUCCEEDED(sq_arrayreverse(v,-1)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger array_pop(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR;\n}\n\nstatic SQInteger array_top(HSQUIRRELVM v)\n{\n    const SQObject &o=stack_get(v,1);\n    if(_array(o)->Size()>0){\n        v->Push(_array(o)->Top());\n        return 1;\n    }\n    else return sq_throwerror(v,\"top() on a empty array\");\n}\n\nstatic SQInteger array_insert(HSQUIRRELVM v)\n{\n    const SQObject &o=stack_get(v,1);\n\n    SQ_CHECK_IMMUTABLE_OBJ(o);\n\n    SQObject &idx=stack_get(v,2);\n    SQObject &val=stack_get(v,3);\n    if(!_array(o)->Insert(tointeger(idx),val))\n        return sq_throwerror(v,\"index out of range\");\n    sq_pop(v,2);\n    return 1;\n}\n\nstatic SQInteger array_remove(HSQUIRRELVM v)\n{\n    const SQObject &o = stack_get(v, 1);\n    SQ_CHECK_IMMUTABLE_OBJ(o);\n\n    SQObject &idx = stack_get(v, 2);\n    if(!sq_isnumeric(idx)) return sq_throwerror(v, \"wrong type\");\n    SQObjectPtr val;\n    if(_array(o)->Get(tointeger(idx), val)) {\n        _array(o)->Remove(tointeger(idx));\n        v->Push(val);\n        return 1;\n    }\n    return sq_throwerror(v, \"idx out of range\");\n}\n\nstatic SQInteger array_resize(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v, 1);\n    SQ_CHECK_IMMUTABLE_OBJ(o);\n\n    SQObject &nsize = stack_get(v, 2);\n    SQObjectPtr fill;\n    if(sq_isnumeric(nsize)) {\n        SQInteger sz = tointeger(nsize);\n        if (sz<0)\n          return sq_throwerror(v, \"resizing to negative length\");\n\n        if(sq_gettop(v) > 2)\n            fill = stack_get(v, 3);\n        _array(o)->Resize(sz,fill);\n        sq_settop(v, 1);\n        return 1;\n    }\n    return sq_throwerror(v, \"size must be a number\");\n}\n\nstatic SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v, bool append) {\n    SQObjectPtr temp;\n    SQObjectPtr srcObj(src);\n    SQInteger size = src->Size();\n    const SQObjectPtr &closure = stack_get(v, 2);\n\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n    for(SQInteger n = 0; n < size; n++) {\n        src->Get(n,temp);\n        v->PushNull();\n        v->Push(temp);\n        if (nArgs >= 3)\n            v->Push(SQObjectPtr(n));\n        if (nArgs >= 4)\n            v->Push(srcObj);\n\n        bool callRes = v->Call(closure, nArgs, v->_top - nArgs, temp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        v->Pop(nArgs);\n        if (!callRes) {\n            if (append && sq_isnull(v->_lasterror)) {\n                continue;\n            }\n            return SQ_ERROR;\n        }\n\n        if (append)\n            dest->Append(temp);\n        else\n            dest->Set(n, temp);\n    }\n    return 0;\n}\n\nstatic SQInteger array_map(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    SQInteger size = _array(o)->Size();\n    SQArray *dest = SQArray::Create(_ss(v),0);\n    dest->Reserve(size);\n    SQObjectPtr ret(dest);\n    if(SQ_FAILED(__map_array(dest,_array(o),v,true)))\n        return SQ_ERROR;\n    dest->ShrinkIfNeeded();\n    v->Push(ret);\n    return 1;\n}\n\nstatic SQInteger array_apply(HSQUIRRELVM v)\n{\n    SQObject &o = stack_get(v,1);\n    SQ_CHECK_IMMUTABLE_OBJ(o);\n\n    if(SQ_FAILED(__map_array(_array(o),_array(o),v,false)))\n        return SQ_ERROR;\n    sq_pop(v,1);\n    return 1;\n}\n\nstatic SQInteger array_reduce(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    SQArray *a = _array(o);\n    SQInteger size = a->Size();\n    SQObjectPtr accum;\n    SQInteger iterStart;\n    if (sq_gettop(v)>2) {\n        accum = stack_get(v,3);\n        iterStart = 0;\n    } else if (size==0) {\n        return 0;\n    } else {\n        a->Get(0, accum);\n        iterStart = 1;\n    }\n\n    const SQObjectPtr &closure = stack_get(v, 2);\n    SQInteger nArgs = get_allowed_args_count(closure, 5);\n\n    if (size > iterStart) {\n        SQObjectPtr other;\n        for (SQInteger n = iterStart; n < size; n++) {\n            a->Get(n,other);\n            v->PushNull();\n            v->Push(accum);\n            v->Push(other);\n            if (nArgs >= 4)\n                v->Push(SQObjectPtr(n));\n            if (nArgs >= 5)\n                v->Push(o);\n\n            bool callRes = v->Call(closure, nArgs, v->_top - nArgs, accum, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n            v->Pop(nArgs);\n            if (!callRes)\n                return SQ_ERROR;\n        }\n    }\n    v->Push(accum);\n    return 1;\n}\n\nstatic SQInteger array_filter(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v,1);\n    SQArray *a = _array(o);\n    const SQObjectPtr &closure = stack_get(v, 2);\n    SQInteger nArgs = get_allowed_args_count(closure, 4);\n\n    SQObjectPtr ret(SQArray::Create(_ss(v),0));\n    SQInteger size = a->Size();\n    SQObjectPtr val, temp;\n\n    for(SQInteger n = 0; n < size; n++) {\n        a->Get(n,val);\n        v->PushNull();\n        v->Push(val);\n        if (nArgs >= 3)\n            v->Push(SQObjectPtr(n));\n        if (nArgs >= 4)\n            v->Push(o);\n\n        bool callRes = v->Call(closure, nArgs, v->_top - nArgs, temp, SQ_BASELIB_INVOKE_CB_ERR_HANDLER);\n        v->Pop(nArgs);\n        if (!callRes)\n            return SQ_ERROR;\n\n        if(!SQVM::IsFalse(temp)) {\n            _array(ret)->Append(val);\n        }\n    }\n    v->Push(ret);\n    return 1;\n}\n\n\nstatic SQInteger _push_scan_index(HSQUIRRELVM v, SQInteger index)\n{\n    if (index >= 0) {\n        sq_pushinteger(v, index);\n        return 1;\n    } else\n        return 0;\n}\n\n\nstatic SQInteger _push_scan_found_flag(HSQUIRRELVM v, SQInteger index)\n{\n    sq_pushbool(v, index>=0);\n    return 1;\n}\n\n\nstatic SQInteger _array_scan_for_value(HSQUIRRELVM v, SQInteger (*push_result)(HSQUIRRELVM v, SQInteger index))\n{\n    SQObject &o = stack_get(v,1);\n    SQObjectPtr &val = stack_get(v,2);\n    SQArray *a = _array(o);\n    SQInteger size = a->Size();\n    SQObjectPtr temp;\n    for(SQInteger n = 0; n < size; n++) {\n        a->Get(n,temp);\n        if(SQVM::IsEqual(temp,val))\n            return push_result(v, n);\n    }\n    return push_result(v, -1);\n}\n\n\nstatic SQInteger array_indexof(HSQUIRRELVM v)\n{\n    return _array_scan_for_value(v, _push_scan_index);\n}\n\n\nstatic SQInteger array_contains(HSQUIRRELVM v)\n{\n    return _array_scan_for_value(v, _push_scan_found_flag);\n}\n\n\nstatic bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a, SQObjectPtr &b,\n                          const SQObjectPtr &func, SQInteger &ret)\n{\n    if (sq_isnull(func)) {\n        if (!v->ObjCmp(a,b,ret))\n            return false;\n    }\n    else {\n        SQInteger top = sq_gettop(v);\n        v->PushNull();\n        v->Push(a);\n        v->Push(b);\n        SQObjectPtr *valptr = arr->_values._vals;\n        SQUnsignedInteger precallsize = arr->_values.size();\n        SQObjectPtr out;\n        bool callSucceeded = v->Call(func, 3, v->_top-3, out, false);\n        if (!callSucceeded) {\n            if (!sq_isstring( v->_lasterror))\n                v->Raise_Error(\"compare func failed\");\n            return false;\n        }\n        if (!sq_isnumeric(out)) {\n            v->Raise_Error(\"numeric value expected as return value of the compare function\");\n            return false;\n        }\n        if (precallsize != arr->_values.size() || valptr != arr->_values._vals) {\n            v->Raise_Error(\"array resized during sort operation\");\n            return false;\n        }\n        ret = tointeger(out);\n        sq_settop(v, top);\n        return true;\n    }\n    return true;\n}\n\nstatic bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, const SQObjectPtr &func)\n{\n    SQInteger maxChild;\n    SQInteger done = 0;\n    SQInteger ret;\n    SQInteger root2;\n    while (((root2 = root * 2) <= bottom) && (!done))\n    {\n        if (root2 == bottom) {\n            maxChild = root2;\n        }\n        else {\n            if(!_sort_compare(v,arr,arr->_values[root2],arr->_values[root2 + 1],func,ret))\n                return false;\n            if (ret > 0) {\n                maxChild = root2;\n            }\n            else {\n                maxChild = root2 + 1;\n            }\n        }\n\n        if(!_sort_compare(v,arr,arr->_values[root],arr->_values[maxChild],func,ret))\n            return false;\n        if (ret < 0) {\n            if (root == maxChild) {\n                v->Raise_Error(\"inconsistent compare function\");\n                return false; // We'd be swapping ourselve. The compare function is incorrect\n            }\n\n            _Swap(arr->_values[root],arr->_values[maxChild]);\n            root = maxChild;\n        }\n        else {\n            done = 1;\n        }\n    }\n    return true;\n}\n\nstatic bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger SQ_UNUSED_ARG(l), SQInteger SQ_UNUSED_ARG(r),const SQObjectPtr &func)\n{\n    SQArray *a = _array(arr);\n    SQInteger i;\n    SQInteger array_size = a->Size();\n    for (i = (array_size / 2); i >= 0; i--) {\n        if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false;\n    }\n\n    for (i = array_size-1; i >= 1; i--)\n    {\n        _Swap(a->_values[0],a->_values[i]);\n        if(!_hsort_sift_down(v,a, 0, i-1,func)) return false;\n    }\n    return true;\n}\n\nstatic SQInteger array_sort(HSQUIRRELVM v)\n{\n    SQObjectPtr func;\n    SQObjectPtr &o = stack_get(v,1);\n    SQ_CHECK_IMMUTABLE_OBJ(o);\n\n    if (_array(o)->Size() > 1) {\n        if(sq_gettop(v) == 2)\n            func = stack_get(v, 2);\n        if(!_hsort(v, o, 0, _array(o)->Size()-1, func))\n            return SQ_ERROR;\n\n    }\n    sq_settop(v,1);\n    return 1;\n}\n\n\nstatic SQInteger clamp_int(SQInteger v, SQInteger minv, SQInteger maxv)\n{\n  return (v < minv) ? minv : (v > maxv) ? maxv : v;\n}\n\nstatic SQInteger array_slice(HSQUIRRELVM v)\n{\n    SQInteger sidx,eidx;\n    SQObjectPtr o;\n    if(get_slice_params(v,sidx,eidx,o)==-1)return -1;\n    SQInteger alen = _array(o)->Size();\n\n    sidx = clamp_int((sidx < 0) ? (alen + sidx) : sidx, 0, alen);\n    eidx = clamp_int((eidx < 0) ? (alen + eidx) : eidx, 0, alen);\n\n    if (alen == 0 || eidx <= sidx)\n    {\n      SQArray *arr = SQArray::Create(_ss(v), 0);\n      v->Push(SQObjectPtr(arr));\n      return 1;\n    }\n\n    SQArray *arr=SQArray::Create(_ss(v),eidx-sidx);\n    SQObjectPtr t;\n    SQInteger count=0;\n    for(SQInteger i=sidx;i<eidx;i++){\n        _array(o)->Get(i,t);\n        arr->Set(count++,t);\n    }\n    v->Push(SQObjectPtr(arr));\n    return 1;\n\n}\n\nstatic SQInteger array_hasindex(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v, 1);\n    SQInteger idx = tointeger(stack_get(v, 2));\n    sq_pushbool(v, idx>=0 && idx < _array(o)->Size());\n    return 1;\n}\n\nstatic SQInteger array_replace_with(HSQUIRRELVM v)\n{\n    SQ_CHECK_IMMUTABLE_SELF;\n\n    SQArray *dst = _array(stack_get(v, 1));\n    SQArray *src = _array(stack_get(v, 2));\n    dst->_values.copy(src->_values);\n    dst->ShrinkIfNeeded();\n    VT_CLONE_FROM_TO(src, dst);\n    v->Pop(1);\n    return 1;\n}\n\nconst SQRegFunction SQSharedState::_array_default_type_methods_funcz[]={\n    {\"constructor\",builtin_array_ctor,-2, \".n.\"},\n    {\"len\",default_type_method_len,1, \"a\", NULL, true},\n    {\"append\",array_append,-2, \"a.\"},\n    {\"extend\",array_extend,-2, \"aa\"},\n    {\"pop\",array_pop,1, \"a\"},\n    {\"top\",array_top,1, \"a\"},\n    {\"insert\",array_insert,3, \"an.\"},\n    {\"remove\",array_remove,2, \"an\"},\n    {\"resize\",array_resize,-2, \"an\"},\n    {\"reverse\",array_reverse,1, \"a\"},\n    {\"sort\",array_sort,-1, \"ac\"},\n    {\"slice\",array_slice,-1, \"ann\"},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"clear\",obj_clear,1, \".\"},\n    {\"map\",array_map,2, \"ac\"},\n    {\"apply\",array_apply,2, \"ac\"},\n    {\"reduce\",array_reduce,-2, \"ac.\"},\n    {\"filter\",array_filter,2, \"ac\"},\n    {\"indexof\",array_indexof,2, \"a.\", NULL, true},\n    {\"contains\",array_contains,2, \"a.\"},\n    {\"each\",container_each,2, \"ac\"},\n    {\"findindex\",container_findindex,2, \"ac\", NULL, true},\n    {\"findvalue\",container_findvalue,-2, \"ac.\", NULL, true},\n    {\"totable\",array_to_table,1, \"a\", NULL, true},\n    {\"replace\",array_replace_with,2, \"aa\"}, // deprecated, use replace_with\n    {\"replace_with\",array_replace_with,2, \"aa\"},\n    {\"hasindex\",array_hasindex,2, \"an\", NULL, true},\n    {\"hasvalue\",array_contains,2, \"a.\", NULL, true},\n    {\"clone\",obj_clone, 1, \".\" },\n    {\"is_frozen\",obj_is_frozen, 1, \".\" },\n    {\"swap\",swap, 3, \"ann\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// String type methods\n\nstatic SQInteger string_hash(HSQUIRRELVM v)\n{\n    union { SQHash hash; SQInteger i; SQUnsignedInteger u; } convert;\n    memset(&convert, 0, sizeof(convert));\n    convert.hash = _string(stack_get(v, 1))->_hash;\n    if (convert.i < 0)\n        convert.u = ~convert.u;\n    sq_pushinteger(v, convert.i);\n    return 1;\n}\n\nstatic SQInteger string_slice(HSQUIRRELVM v)\n{\n    SQInteger sidx,eidx;\n    SQObjectPtr o;\n    if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1;\n    SQInteger slen = _string(o)->_len;\n\n    sidx = clamp_int((sidx < 0) ? (slen + sidx) : sidx, 0, slen);\n    eidx = clamp_int((eidx < 0) ? (slen + eidx) : eidx, 0, slen);\n\n    if (slen == 0 || eidx <= sidx)\n    {\n      v->Push(SQObjectPtr(SQString::Create(_ss(v), \"\", -1)));\n      return 1;\n    }\n\n    v->Push(SQObjectPtr(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)));\n    return 1;\n}\n\nstatic SQInteger string_hasindex(HSQUIRRELVM v)\n{\n    const SQObjectPtr &o = stack_get(v, 1);\n    SQInteger idx = tointeger(stack_get(v, 2));\n    sq_pushbool(v, idx >= 0 && idx < _string(o)->_len);\n    return 1;\n}\n\nstatic SQInteger _string_scan_for_substring(HSQUIRRELVM v, SQInteger (*push_result)(HSQUIRRELVM v, SQInteger index))\n{\n    SQInteger top,start_idx=0;\n    const char *str,*substr,*ret;\n    if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){\n        if (sq_getsize(v,2)<1)\n            return sq_throwerror(v, \"empty substring\");\n        if(top>2)sq_getinteger(v,3,&start_idx);\n        if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){\n            ret=strstr(&str[start_idx],substr);\n            if(ret)\n                return push_result(v, ret-str);\n        }\n        return push_result(v, -1);\n    }\n    return sq_throwerror(v,\"invalid param\");\n}\n\nstatic SQInteger string_indexof(HSQUIRRELVM v)\n{\n    return _string_scan_for_substring(v, _push_scan_index);\n}\n\nstatic SQInteger string_contains(HSQUIRRELVM v)\n{\n    return _string_scan_for_substring(v, _push_scan_found_flag);\n}\n\nstatic char* replace_all(SQAllocContext allocctx, char *s, SQInteger &buf_len, SQInteger &len,\n                          const char *from, SQInteger len_from, const char *to, SQInteger len_to)\n{\n    for (SQInteger pos=0; pos<=len-len_from; ) {\n        if (memcmp(s+pos, from, len_from*sizeof(char))==0) {\n            SQInteger d_size = len_to - len_from;\n            if (d_size > 0) {\n                s = (char*)sq_realloc(allocctx, s, buf_len*sizeof(char), (buf_len+d_size)*sizeof(char));\n                buf_len += d_size;\n            }\n            if (d_size!=0)\n                memmove(s+pos+len_to, s+pos+len_from, (len-pos-len_from)*sizeof(char));\n            memcpy(s+pos, to, len_to*sizeof(char));\n            len += d_size;\n            pos += len_to;\n        }\n        else\n            ++pos;\n    }\n    return s;\n}\n\nstatic char* replace_substring_internal(SQAllocContext allocctx, char *s, SQInteger &buf_len, SQInteger &len,\n    int pos, SQInteger len_from, const char *to, SQInteger len_to)\n{\n    SQInteger d_size = len_to - len_from;\n    if (d_size > 0) {\n        s = (char*)sq_realloc(allocctx, s, buf_len * sizeof(char), (buf_len + d_size) * sizeof(char));\n        buf_len += d_size;\n    }\n    if (d_size != 0)\n        memmove(s + pos + len_to, s + pos + len_from, (len - pos - len_from) * sizeof(char));\n    memcpy(s + pos, to, len_to * sizeof(char));\n    len += d_size;\n\n    return s;\n}\n\n\nstatic SQInteger string_substitute(HSQUIRRELVM v)\n{\n    SQAllocContext allocctx = _ss(v)->_alloc_ctx;\n    const char *fmt;\n    SQInteger len;\n    sq_getstringandsize(v, 1, &fmt, &len);\n    SQInteger buf_len = len;\n    char *s = (char *)sq_malloc(allocctx, len*sizeof(char));\n    memcpy(s, fmt, len * sizeof(char));\n\n    SQInteger top = sq_gettop(v);\n\n    for (int i = 0; i < int(len) - 2; i++)\n        if (s[i] == '{') {\n            int depth = 0;\n            for (int j = i + 1; j < len; j++) {\n                if (s[j] == '}') {\n                    depth--;\n                    if (depth < 0) {\n                        if (i + 1 == j)\n                          break;\n\n                        int index = 0;\n                        for (int k = i + 1; k < j; k++)\n                            if (s[k] >= '0' && s[k] <= '9')\n                                index = index * 10 + s[k] - '0';\n                            else {\n                                index = -1;\n                                break;\n                            }\n\n                        if (index >= 0) {\n                            index += 2;\n                            if (index <= top) {\n                                SQObjectPtr &val = stack_get(v, index);\n                                SQObjectPtr valStr;\n                                if (v->ToString(val, valStr)) {\n                                    int delta = (int)_string(valStr)->_len - (j + 1 - i);\n                                    s = replace_substring_internal(allocctx, s, buf_len, len, i, j + 1 - i,\n                                        _stringval(valStr), _string(valStr)->_len);\n                                    i = j + delta;\n                                    break;\n                                }\n                                else {\n                                    sq_free(allocctx, s, buf_len * sizeof(char));\n                                    return sq_throwerror(v, \"subst: Failed to convert value to string\");\n                                }\n                            }\n                        }\n\n                        for (int idx = 2; idx <= top; idx++) {\n                            SQObjectPtr &arg = stack_get(v, idx);\n                            if (sq_type(arg) == OT_TABLE) {\n                                SQTable *table = _table(arg);\n                                SQObjectPtr val;\n                                SQObjectPtr valStr;\n                                if (table->GetStr(s + i + 1, j - i - 1, val)) {\n                                    if (v->ToString(val, valStr)) {\n                                        int delta = (int)_string(valStr)->_len - (j + 1 - i);\n                                        s = replace_substring_internal(allocctx, s, buf_len, len, i, j + 1 - i,\n                                            _stringval(valStr), _string(valStr)->_len);\n                                        i = j + delta;\n                                        break;\n                                    }\n                                    else {\n                                        sq_free(allocctx, s, buf_len * sizeof(char));\n                                        return sq_throwerror(v, \"subst: Failed to convert value to string\");\n                                    }\n                                }\n                            }\n                        }\n\n                        break; // depth < 0\n                    }\n                }\n                else if (s[j] == '{')\n                  depth++;\n            }\n        }\n\n    sq_pushstring(v, s, len);\n    sq_free(allocctx, s, buf_len * sizeof(char));\n    return 1;\n}\n\n\nstatic SQInteger string_replace(HSQUIRRELVM v)\n{\n    const char *s, *from, *to;\n    SQInteger len_s, len_from, len_to;\n    sq_getstringandsize(v, 1, &s, &len_s);\n    sq_getstringandsize(v, 2, &from, &len_from);\n    sq_getstringandsize(v, 3, &to, &len_to);\n\n    if (len_from <= 0) {\n        sq_push(v, 1);\n        return 1;\n    }\n\n    // can be optimized by avoiding unnecessary copying\n    SQInteger buf_len = len_s;\n    char *dest = (char *)sq_malloc(_ss(v)->_alloc_ctx, buf_len*sizeof(char));\n    SQInteger len_dest = len_s;\n    memcpy(dest, s, len_s*sizeof(char));\n    dest = replace_all(_ss(v)->_alloc_ctx, dest, buf_len, len_dest, from, len_from, to, len_to);\n\n    sq_pushstring(v, dest, len_dest);\n    sq_free(_ss(v)->_alloc_ctx, dest, buf_len*sizeof(char));\n    return 1;\n}\n\nstatic SQInteger buf_concat(sqvector<char> &res, const SQObjectPtrVec &strings, const char *sep, SQInteger sep_len)\n{\n    SQInteger out_pos = 0;\n    for (SQInteger i=0, nitems=strings.size(); i<nitems; ++i) {\n        if (i) {\n            memcpy(res._vals+out_pos, sep, sep_len*sizeof(char));\n            out_pos += sep_len;\n        }\n\n        SQString *s = _string(strings[i]);\n        memcpy(res._vals+out_pos, s->_val, s->_len*sizeof(char));\n        out_pos += s->_len;\n    }\n    return out_pos;\n}\n\nstatic SQInteger string_join(HSQUIRRELVM v)\n{\n    const char *sep;\n    SQInteger sep_len;\n    sq_getstringandsize(v, 1, &sep, &sep_len);\n    SQArray *arr = _array(stack_get(v, 2));\n\n    SQObjectPtrVec strings(_ss(v)->_alloc_ctx);\n    strings.reserve(arr->Size());\n    SQObjectPtr tmp;\n    SQObjectPtr flt;\n\n    if (sq_gettop(v) > 3)\n        return sq_throwerror(v, \"Too many arguments\");\n\n    if (sq_gettop(v) == 3)\n        flt = stack_get(v, 3);\n\n    SQInteger res_len = 0;\n    for (SQInteger i=0; i<arr->Size(); ++i) {\n        SQObjectPtr &item = arr->_values[i];\n        if (sq_isbool(flt) && sq_objtobool(&flt)) {\n            if (sq_isnull(item) || (sq_isstring(item) && !_string(item)->_len))\n                continue;\n        } else if (sq_isclosure(flt) || sq_isnativeclosure(flt)) {\n            sq_push(v, 1);\n            sq_pushobject(v, item);\n\n            if (SQ_FAILED(sq_call(v,2,SQTrue,SQ_BASELIB_INVOKE_CB_ERR_HANDLER)))\n                return SQ_ERROR;\n            bool use = !SQVM::IsFalse(v->GetUp(-1));\n            v->Pop();\n            if (!use)\n                continue;\n        }\n\n        if (!v->ToString(item, tmp))\n            return sq_throwerror(v, \"Failed to convert array item to string\");\n\n        strings.push_back(tmp);\n        res_len += _string(tmp)->_len;\n    }\n\n    if (strings.empty()) {\n        sq_pushstring(v, \"\", 0);\n        return 1;\n    }\n\n    res_len += sep_len * (strings.size()-1);\n\n    sqvector<char> res(_ss(v)->_alloc_ctx);\n    res.resize(res_len);\n    SQInteger out_pos = buf_concat(res, strings, sep, sep_len);\n    (void)out_pos;\n    assert(out_pos == res_len);\n    sq_pushstring(v, res._vals, res_len);\n    return 1;\n}\n\n\nstatic SQInteger string_concat(HSQUIRRELVM v)\n{\n    const char *sep;\n    SQInteger sep_len;\n    sq_getstringandsize(v, 1, &sep, &sep_len);\n    SQInteger nitems = sq_gettop(v)-1;\n    if (nitems < 1) {\n        sq_pushstring(v, \"\", 0);\n        return 1;\n    }\n\n    SQObjectPtrVec strings(_ss(v)->_alloc_ctx);\n    strings.resize(nitems);\n\n    SQInteger res_len = sep_len * (nitems-1);\n    for (SQInteger i=0; i<nitems; ++i) {\n        if (!v->ToString(stack_get(v, i+2), strings[i]))\n            return sq_throwerror(v, \"Failed to convert array item to string\");\n        res_len += _string(strings[i])->_len;\n    }\n\n    sqvector<char> res(_ss(v)->_alloc_ctx);\n    res.resize(res_len);\n    SQInteger out_pos = buf_concat(res, strings, sep, sep_len);\n    (void)out_pos;\n    assert(out_pos == res_len);\n    sq_pushstring(v, res._vals, res_len);\n    return 1;\n}\n\n\nstatic SQInteger string_split(HSQUIRRELVM v)\n{\n    const char *str;\n    SQInteger len;\n    sq_getstringandsize(v, 1, &str, &len);\n\n    SQArray *res = SQArray::Create(_ss(v),0);\n\n    if (sq_gettop(v) == 1) {\n        SQInteger start = 0;\n        for (SQInteger pos=0; pos<=len; ++pos) {\n            if (pos==len || sq_isspace(str[pos])) {\n                if (pos > start)\n                    res->Append(SQObjectPtr(SQString::Create(_ss(v), str+start, pos-start)));\n                start = pos+1;\n            }\n        }\n    } else {\n        const char *sep;\n        SQInteger sep_len;\n        sq_getstringandsize(v, 2, &sep, &sep_len);\n        if (sep_len < 1)\n            return sq_throwerror(v, \"empty separator\");\n        SQInteger start = 0;\n        for (SQInteger pos=0; pos<=len;) {\n            if (pos>len-sep_len) {\n                res->Append(SQObjectPtr(SQString::Create(_ss(v), str+start, len-start)));\n                break;\n            }\n            else if (strncmp(str+pos, sep, sep_len)==0) {\n                res->Append(SQObjectPtr(SQString::Create(_ss(v), str+start, pos-start)));\n                pos += sep_len;\n                start = pos;\n            }\n            else\n                ++pos;\n        }\n    }\n    v->Push(SQObjectPtr(res));\n    return 1;\n}\n\n\n#define STRING_TOFUNCZ(func, call_func) static SQInteger string_##func(HSQUIRRELVM v) \\\n{\\\n    SQInteger sidx,eidx; \\\n    SQObjectPtr str; \\\n    if(SQ_FAILED(get_slice_params(v,sidx,eidx,str)))return -1; \\\n    SQInteger slen = _string(str)->_len; \\\n    if(sidx < 0)sidx = slen + sidx; \\\n    if(eidx < 0)eidx = slen + eidx; \\\n    if(eidx < sidx) return sq_throwerror(v,\"wrong indexes\"); \\\n    if(eidx > slen || sidx < 0) return sq_throwerror(v,\"slice out of range\"); \\\n    SQInteger len=_string(str)->_len; \\\n    const char *sthis=_stringval(str); \\\n    char *snew=(_ss(v)->GetScratchPad(len)); \\\n    memcpy(snew,sthis,len);\\\n    for(SQInteger i=sidx;i<eidx;i++) snew[i] = (char)call_func(sthis[i]); \\\n    v->Push(SQObjectPtr(SQString::Create(_ss(v),snew,len))); \\\n    return 1; \\\n}\n\n\nSTRING_TOFUNCZ(tolower, sq_tolower)\nSTRING_TOFUNCZ(toupper, sq_toupper)\n\n#define IMPL_STRING_FUNC(name) static SQInteger _baselib_string_##name(HSQUIRRELVM v) { return _sq_string_ ## name ## _impl(v, 1); }\n\nIMPL_STRING_FUNC(strip)\nIMPL_STRING_FUNC(lstrip)\nIMPL_STRING_FUNC(rstrip)\nIMPL_STRING_FUNC(split_by_chars)\nIMPL_STRING_FUNC(escape)\nIMPL_STRING_FUNC(startswith)\nIMPL_STRING_FUNC(endswith)\n\n#undef IMPL_STRING_FUNC\n#define _DECL_FUNC(name,nparams,pmask) {#name,_baselib_string_##name,nparams,pmask}\n\nconst SQRegFunction SQSharedState::_string_default_type_methods_funcz[]={\n    {\"constructor\",builtin_string_ctor,2, NULL},\n    {\"len\",default_type_method_len,1, \"s\", NULL, true},\n    {\"tointeger\",default_type_method_tointeger,-1, \"sn\", NULL, true},\n    {\"tofloat\",default_type_method_tofloat,1, \"s\", NULL, true},\n    {\"tostring\",default_type_method_tostring,1, \".\", NULL, true},\n    {\"hash\",string_hash, 1, \"s\", NULL, true},\n    {\"slice\",string_slice,-1, \"s n  n\", NULL, true},\n    {\"indexof\",string_indexof,-2, \"s s n\", NULL, true},\n    {\"contains\",string_contains,-2, \"s s n\", NULL, true},\n    {\"hasindex\",string_hasindex,-2, \"s n\", NULL, true},\n    {\"tolower\",string_tolower,-1, \"s n n\", NULL, true},\n    {\"toupper\",string_toupper,-1, \"s n n\", NULL, true},\n    {\"subst\",string_substitute,-2, \"s\", NULL, true},\n    {\"replace\",string_replace, 3, \"s s s\", NULL, true},\n    {\"join\",string_join, -2, \"s a b|c\", NULL, true},\n    {\"concat\",string_concat, -2, \"s.\", NULL, true},\n    {\"split\",string_split, -1, \"s s\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"clone\",obj_clone, 1, \".\" },\n    _DECL_FUNC(strip,1,\"s\"),\n    _DECL_FUNC(lstrip,1,\"s\"),\n    _DECL_FUNC(rstrip,1,\"s\"),\n    _DECL_FUNC(split_by_chars,-2,\"ssb\"),\n    _DECL_FUNC(escape,1,\"s\"),\n    _DECL_FUNC(startswith,2,\"ss\"),\n    _DECL_FUNC(endswith,2,\"ss\"),\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n#undef _DECL_FUNC\n\nstatic SQInteger builtin_integer_ctor(HSQUIRRELVM v)\n{\n    SQInteger nparams = sq_gettop(v);\n    if (nparams == 1) {\n        v->Push(SQObjectPtr((SQInteger)0));\n        return 1;\n    }\n\n    SQObjectPtr &o = stack_get(v, 2);\n    SQInteger base = 10;\n    if (nparams > 2) {\n        sq_getinteger(v, 3, &base);\n    }\n\n    switch (sq_type(o)) {\n        case OT_INTEGER:\n            v->Push(o);\n            return 1;\n        case OT_FLOAT:\n            v->Push(SQObjectPtr(tointeger(o)));\n            return 1;\n        case OT_STRING: {\n            SQObjectPtr res;\n            if (sq_parse_int(_stringval(o), _stringval(o) + _string(o)->_len, res, base)) {\n                v->Push(SQObjectPtr(tointeger(res)));\n                return 1;\n            }\n            return sq_throwerror(v, \"cannot convert string to Integer\");\n        }\n        case OT_BOOL:\n            v->Push(SQObjectPtr(_integer(o) ? (SQInteger)1 : (SQInteger)0));\n            return 1;\n        default:\n            return sq_throwerror(v, \"cannot convert to Integer\");\n    }\n}\n\nstatic SQInteger builtin_float_ctor(HSQUIRRELVM v)\n{\n    SQInteger nparams = sq_gettop(v);\n    if (nparams == 1) {\n        v->Push(SQObjectPtr((SQFloat)0.0));\n        return 1;\n    }\n\n    SQObjectPtr &o = stack_get(v, 2);\n    switch (sq_type(o)) {\n        case OT_FLOAT:\n            v->Push(o);\n            return 1;\n        case OT_INTEGER:\n            v->Push(SQObjectPtr(tofloat(o)));\n            return 1;\n        case OT_STRING: {\n            SQObjectPtr res;\n            if (sq_parse_float(_stringval(o), _stringval(o) + _string(o)->_len, res, 10)) {\n                v->Push(SQObjectPtr(tofloat(res)));\n                return 1;\n            }\n            return sq_throwerror(v, \"cannot convert string to Float\");\n        }\n        case OT_BOOL:\n            v->Push(SQObjectPtr((SQFloat)(_integer(o) ? 1.0 : 0.0)));\n            return 1;\n        default:\n            return sq_throwerror(v, \"cannot convert to Float\");\n    }\n}\n\nstatic SQInteger builtin_bool_ctor(HSQUIRRELVM v)\n{\n    SQInteger nparams = sq_gettop(v);\n    if (nparams == 1) {\n        v->Push(SQObjectPtr(false));\n        return 1;\n    }\n\n    v->Push(SQObjectPtr(!SQVM::IsFalse(stack_get(v, 2))));\n    return 1;\n}\n\nstatic SQInteger builtin_string_ctor(HSQUIRRELVM v)\n{\n    SQObjectPtr res;\n    if (v->ToString(stack_get(v, 2), res)) {\n        v->Push(res);\n        return 1;\n    }\n    return sq_throwerror(v, \"cannot convert to String\");\n}\n\nstatic SQInteger builtin_table_ctor(HSQUIRRELVM v)\n{\n    SQTable *tbl = SQTable::Create(_ss(v), 0);\n    v->Push(SQObjectPtr(tbl));\n    return 1;\n}\n\nstatic SQInteger builtin_null_ctor(HSQUIRRELVM v)\n{\n    return 0;\n}\n\nstatic SQInteger builtin_weakref_ctor(HSQUIRRELVM v)\n{\n    sq_weakref(v, 2);\n    return 1;\n}\n\n// Null type methods\nconst SQRegFunction SQSharedState::_null_default_type_methods_funcz[]={\n    {\"constructor\",builtin_null_ctor,-1, NULL},\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n\n// Integer type methods\nconst SQRegFunction SQSharedState::_integer_default_type_methods_funcz[]={\n    {\"constructor\",builtin_integer_ctor,-1, NULL},\n    {\"tointeger\",default_type_method_tointeger,1, \"n|b\", NULL, true},\n    {\"tofloat\",default_type_method_tofloat,1, \"n|b\", NULL, true},\n    {\"tostring\",default_type_method_tostring,1, \".\", NULL, true},\n    {\"tochar\",number_type_method_tochar,1, \"n|b\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// Float type methods\nconst SQRegFunction SQSharedState::_float_default_type_methods_funcz[]={\n    {\"constructor\",builtin_float_ctor,-1, NULL},\n    {\"tointeger\",default_type_method_tointeger,1, \"n|b\", NULL, true},\n    {\"tofloat\",default_type_method_tofloat,1, \"n|b\", NULL, true},\n    {\"tostring\",default_type_method_tostring,1, \".\", NULL, true},\n    {\"tochar\",number_type_method_tochar,1, \"n|b\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// Bool type methods\nconst SQRegFunction SQSharedState::_bool_default_type_methods_funcz[]={\n    {\"constructor\",builtin_bool_ctor,-1, NULL},\n    {\"tointeger\",default_type_method_tointeger,1, \"n|b\", NULL, true},\n    {\"tofloat\",default_type_method_tofloat,1, \"n|b\", NULL, true},\n    {\"tostring\",default_type_method_tostring,1, \".\", NULL, true},\n    {\"tochar\",number_type_method_tochar,1, \"n|b\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// Closure type methods\nstatic SQInteger closure_pcall(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;\n}\n\nstatic SQInteger closure_call(HSQUIRRELVM v)\n{\n    SQObjectPtr &c = stack_get(v, -1);\n    if (sq_type(c) == OT_CLOSURE && (_closure(c)->_function->_bgenerator == false))\n    {\n        return sq_tailcall(v, sq_gettop(v) - 1);\n    }\n    return SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR;\n}\n\nstatic SQInteger _closure_acall(HSQUIRRELVM v,SQBool invoke_err_handler)\n{\n    SQArray *aparams=_array(stack_get(v,2));\n    SQInteger nparams=aparams->Size();\n    v->Push(stack_get(v,1));\n    for(SQInteger i=0;i<nparams;i++)v->Push(aparams->_values[i]);\n    return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,invoke_err_handler))?1:SQ_ERROR;\n}\n\nstatic SQInteger closure_acall(HSQUIRRELVM v)\n{\n    return _closure_acall(v,SQTrue);\n}\n\nstatic SQInteger closure_pacall(HSQUIRRELVM v)\n{\n    return _closure_acall(v,SQFalse);\n}\n\nstatic SQInteger closure_bindenv(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_bindenv(v,1)))\n        return SQ_ERROR;\n    return 1;\n}\n\n\nstatic SQInteger closure_getfreevar(HSQUIRRELVM v)\n{\n    SQInteger varidx;\n    sq_getinteger(v, 2, &varidx);\n    const char *name = sq_getfreevariable(v, 1, SQUnsignedInteger(varidx));\n    if (!name)\n        return sq_throwerror(v, \"Invalid free variable index\");\n    SQObjectPtr val = v->PopGet();\n    SQTable *res = SQTable::Create(_ss(v),2);\n    res->NewSlot(SQObjectPtr(SQString::Create(_ss(v),\"name\",-1)), SQObjectPtr(SQString::Create(_ss(v),name,-1)));\n    res->NewSlot(SQObjectPtr(SQString::Create(_ss(v),\"value\",-1)), val);\n    v->Push(SQObjectPtr(res));\n    return 1;\n}\n\n\nstatic SQInteger closure_getfuncinfos_obj(HSQUIRRELVM v, SQObjectPtr & o) {\n    SQTable *res = SQTable::Create(_ss(v), 20);\n\n    #define SET_SLOT(name, value) \\\n        res->NewSlot(SQObjectPtr(SQString::Create(_ss(v), name, -1)), SQObjectPtr(value))\n\n    if(sq_type(o) == OT_CLOSURE) {\n        SQFunctionProto *f = _closure(o)->_function;\n        SQInteger nparams = f->_nparameters - (f->_varparams ? 1 : 0);\n        SQObjectPtr params(SQArray::Create(_ss(v),nparams));\n        SQObjectPtr typecheck(SQArray::Create(_ss(v),nparams));\n        SQObjectPtr defparams(SQArray::Create(_ss(v),f->_ndefaultparams));\n\n        for(SQInteger n = 0; n < nparams; n++) {\n            _array(params)->Set(n, f->_parameters[n]);\n            _array(typecheck)->Set(n, SQObjectPtr(int(f->_param_type_masks[n])));\n        }\n        for(SQInteger j = 0; j < f->_ndefaultparams; j++) {\n            _array(defparams)->Set((SQInteger)j,_closure(o)->_defaultparams[j]);\n        }\n        SET_SLOT(\"native\", false);\n        SET_SLOT(\"pure\", f->_purefunction);\n        SET_SLOT(\"nodiscard\", f->_nodiscard);\n        SET_SLOT(\"name\", f->_name);\n        SET_SLOT(\"freevars\", f->_noutervalues);\n        SET_SLOT(\"src\", f->_sourcename);\n        SET_SLOT(\"line\", SQInteger(f->_lineinfos->_first_line));\n        SET_SLOT(\"parameters\", params);\n        SET_SLOT(\"defparams\", defparams);\n        SET_SLOT(\"required_params\", nparams - f->_ndefaultparams);\n        SET_SLOT(\"varargs\", bool(f->_varparams));\n        SET_SLOT(\"typecheck\", typecheck);\n        SET_SLOT(\"return_type_mask\", SQObjectPtr(int(f->_result_type_mask)));\n        SET_SLOT(\"varargs_type_mask\", SQObjectPtr(int(f->_varparams ? f->_param_type_masks[f->_nparameters - 1] : 0)));\n\n        SQObjectPtr key;\n        SQObjectPtr docObject;\n        key._type = OT_USERPOINTER;\n        key._unVal.pUserPointer = (void *)_closure(o)->_function;\n        _table(_ss(v)->doc_objects)->Get(key, docObject);\n        SET_SLOT(\"doc\", docObject);\n    }\n    else { //OT_NATIVECLOSURE\n        SQNativeClosure *nc = _nativeclosure(o);\n\n        int requiredParams = nc->_nparamscheck == 0 ? 1 : abs(nc->_nparamscheck);\n        bool varargs = nc->_nparamscheck <= 0;\n        SQInteger varargsTypeMask = varargs ? -1 : 0;\n\n\n        SQObjectPtr parameters;\n        SQObjectPtr defparams;\n        SQObjectPtr typecheck;\n        SQObjectPtr key;\n        SQObjectPtr value;\n        key._type = OT_USERPOINTER;\n        key._unVal.pUserPointer = (void *)((size_t)(void *)nc->_function ^ ~size_t(0));\n        if (_table(_ss(v)->doc_objects)->Get(key, value)) {\n            SQFunctionType ft(_ss(v));\n            SQInteger errorPos = -1;\n            SQObjectPtr errorString;\n            if (sq_isstring(value)) {\n               if (sq_parse_function_type_string(v, _stringval(value), ft, errorPos, errorString)) {\n\n                   parameters = SQObjectPtr(SQArray::Create(_ss(v), ft.argNames.size() + 1));\n                   _array(parameters)->Set(SQInteger(0), SQObjectPtr(SQString::Create(_ss(v), \"this\", -1)));\n                   for (SQUnsignedInteger n = 0; n < ft.argNames.size(); n++) {\n                       _array(parameters)->Set((SQInteger)n + 1, SQObjectPtr(ft.argNames[n]));\n                   }\n\n                   int defParamsCount = ft.argNames.size() - ft.requiredArgs;\n                   defparams = SQObjectPtr(SQArray::Create(_ss(v), defParamsCount));\n                   for (SQUnsignedInteger n = 0; n < defParamsCount; n++) {\n                       _array(parameters)->Set((SQInteger)n, SQObjectPtr());\n                   }\n\n                   varargs = ft.ellipsisArgTypeMask != 0;\n                   varargsTypeMask = int(ft.ellipsisArgTypeMask);\n               }\n               else {\n                   // TODO: raise errorString\n               }\n            }\n        }\n        else {\n            parameters = SQObjectPtr(SQArray::Create(_ss(v), requiredParams));\n\n            _array(parameters)->Set(SQInteger(0), SQObjectPtr(SQString::Create(_ss(v), \"this\", -1)));\n            for (SQInteger n = 1; n < requiredParams; n++) {\n                char buf[16] = { 0 };\n                snprintf(buf, sizeof(buf), \"arg%d\", int(n));\n                _array(parameters)->Set((SQInteger)n, SQObjectPtr(SQString::Create(_ss(v), buf, -1)));\n            }\n\n            defparams = SQObjectPtr(SQArray::Create(_ss(v), 0));\n        }\n\n        typecheck = SQObjectPtr(SQArray::Create(_ss(v), nc->_typecheck.size()));\n        for (SQUnsignedInteger n = 0; n < nc->_typecheck.size(); n++) {\n            _array(typecheck)->Set((SQInteger)n, SQObjectPtr(int(nc->_typecheck[n])));\n        }\n\n        SET_SLOT(\"native\", true);\n        SET_SLOT(\"pure\", nc->_purefunction);\n        SET_SLOT(\"nodiscard\", nc->_nodiscard);\n        SET_SLOT(\"name\", nc->_name);\n        SET_SLOT(\"freevars\", SQInteger(nc->_noutervalues));\n        SET_SLOT(\"src\", SQObjectPtr());\n        SET_SLOT(\"line\", SQObjectPtr());\n        SET_SLOT(\"parameters\", parameters);\n        SET_SLOT(\"defparams\", defparams);\n        SET_SLOT(\"required_params\", requiredParams);\n        SET_SLOT(\"paramscheck\", nc->_nparamscheck);\n        SET_SLOT(\"varargs\", varargs);\n        SET_SLOT(\"typecheck\", typecheck);\n        SET_SLOT(\"return_type_mask\", SQObjectPtr(int(nc->_result_type_mask)));\n        SET_SLOT(\"varargs_type_mask\", varargsTypeMask);\n\n        SQObjectPtr docObject;\n        key._unVal.pUserPointer = (void *)nc->_function;\n        _table(_ss(v)->doc_objects)->Get(key, docObject);\n        SET_SLOT(\"doc\", docObject);\n    }\n\n    #undef SET_SLOT\n\n    v->Push(SQObjectPtr(res));\n    return 1;\n}\n\n\nstatic SQInteger closure_getfuncinfos(HSQUIRRELVM v)\n{\n  SQObjectPtr o = stack_get(v, 1);\n  return closure_getfuncinfos_obj(v, o);\n}\n\n\nstatic SQInteger delegable_getfuncinfos(HSQUIRRELVM v)\n{\n  SQObjectPtr o = stack_get(v, 1);\n\n  SQDelegable * delegable = _delegable(o);\n  SQObjectPtr call;\n  if (delegable->GetMetaMethod(v, MT_CALL, call))\n    closure_getfuncinfos_obj(v, call);\n  else\n    sq_pushnull(v);\n\n  return 1;\n}\n\nstatic SQInteger class_getfuncinfos(HSQUIRRELVM v)\n{\n  SQObjectPtr o = stack_get(v, 1);\n\n  if (!sq_isnull(_class(o)->_metamethods[MT_CALL]))\n    closure_getfuncinfos_obj(v, _class(o)->_metamethods[MT_CALL]);\n  else\n    sq_pushnull(v);\n\n  return 1;\n}\n\n\nconst SQRegFunction SQSharedState::_closure_default_type_methods_funcz[]={\n    {\"call\",closure_call,-1, \"c\"},\n    {\"pcall\",closure_pcall,-1, \"c\"},\n    {\"acall\",closure_acall,2, \"ca\"},\n    {\"pacall\",closure_pacall,2, \"ca\"},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"bindenv\",closure_bindenv,2, \"c x|y|t\"},\n    {\"getfuncinfos\",closure_getfuncinfos,1, \"c\"},\n    {\"getfreevar\",closure_getfreevar,2, \"ci\"},\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// Generator type methods\nstatic SQInteger generator_getstatus(HSQUIRRELVM v)\n{\n    SQObject &o=stack_get(v,1);\n    switch(_generator(o)->_state){\n        case SQGenerator::eSuspended:v->Push(SQObjectPtr(SQString::Create(_ss(v),\"suspended\")));break;\n        case SQGenerator::eRunning:v->Push(SQObjectPtr(SQString::Create(_ss(v),\"running\")));break;\n        case SQGenerator::eDead:v->Push(SQObjectPtr(SQString::Create(_ss(v),\"dead\")));break;\n    }\n    return 1;\n}\n\nconst SQRegFunction SQSharedState::_generator_default_type_methods_funcz[]={\n    {\"getstatus\",generator_getstatus,1, \"g\"},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n// Thead type methods\nstatic SQInteger thread_call(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQInteger nparams = sq_gettop(v);\n        sq_reservestack(_thread(o), nparams + 3);\n        _thread(o)->Push(_thread(o)->_roottable);\n        for(SQInteger i = 2; i<(nparams+1); i++)\n            sq_move(_thread(o),v,i);\n        if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQTrue))) {\n            sq_move(v,_thread(o),-1);\n            sq_pop(_thread(o),1);\n            return 1;\n        }\n        v->_lasterror = _thread(o)->_lasterror;\n        return SQ_ERROR;\n    }\n    return sq_throwerror(v,\"wrong parameter\");\n}\n\nstatic SQInteger thread_wakeup(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQVM *thread = _thread(o);\n        SQInteger state = sq_getvmstate(thread);\n        if(state != SQ_VMSTATE_SUSPENDED) {\n            switch(state) {\n                case SQ_VMSTATE_IDLE:\n                    return sq_throwerror(v,\"cannot wakeup a idle thread\");\n                break;\n                case SQ_VMSTATE_RUNNING:\n                    return sq_throwerror(v,\"cannot wakeup a running thread\");\n                break;\n            }\n        }\n\n        SQInteger wakeupret = sq_gettop(v)>1?SQTrue:SQFalse;\n        if(wakeupret) {\n            sq_move(thread,v,2);\n        }\n        if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) {\n            sq_move(v,thread,-1);\n            sq_pop(thread,1); //pop retval\n            if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {\n                sq_settop(thread,1); //pop roottable\n            }\n            return 1;\n        }\n        sq_settop(thread,1);\n        v->_lasterror = thread->_lasterror;\n        return SQ_ERROR;\n    }\n    return sq_throwerror(v,\"wrong parameter\");\n}\n\nstatic SQInteger thread_wakeupthrow(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQVM *thread = _thread(o);\n        SQInteger state = sq_getvmstate(thread);\n        if(state != SQ_VMSTATE_SUSPENDED) {\n            switch(state) {\n                case SQ_VMSTATE_IDLE:\n                    return sq_throwerror(v,\"cannot wakeup a idle thread\");\n                break;\n                case SQ_VMSTATE_RUNNING:\n                    return sq_throwerror(v,\"cannot wakeup a running thread\");\n                break;\n            }\n        }\n\n        sq_move(thread,v,2);\n        sq_throwobject(thread);\n        SQBool rethrow_error = SQTrue;\n        if(sq_gettop(v) > 2) {\n            sq_getbool(v,3,&rethrow_error);\n        }\n        if(SQ_SUCCEEDED(sq_wakeupvm(thread,SQFalse,SQTrue,SQTrue,SQTrue))) {\n            sq_move(v,thread,-1);\n            sq_pop(thread,1); //pop retval\n            if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {\n                sq_settop(thread,1); //pop roottable\n            }\n            return 1;\n        }\n        sq_settop(thread,1);\n        if(rethrow_error) {\n            v->_lasterror = thread->_lasterror;\n            return SQ_ERROR;\n        }\n        return SQ_OK;\n    }\n    return sq_throwerror(v,\"wrong parameter\");\n}\n\nstatic SQInteger thread_getstatus(HSQUIRRELVM v)\n{\n    SQObjectPtr &o = stack_get(v,1);\n    switch(sq_getvmstate(_thread(o))) {\n        case SQ_VMSTATE_IDLE:\n            sq_pushstring(v,\"idle\",-1);\n        break;\n        case SQ_VMSTATE_RUNNING:\n            sq_pushstring(v,\"running\",-1);\n        break;\n        case SQ_VMSTATE_SUSPENDED:\n            sq_pushstring(v,\"suspended\",-1);\n        break;\n        default:\n            return sq_throwerror(v,\"internal VM error\");\n    }\n    return 1;\n}\n\nstatic SQInteger thread_getstackinfos(HSQUIRRELVM v)\n{\n    SQObjectPtr o = stack_get(v,1);\n    if(sq_type(o) == OT_THREAD) {\n        SQVM *thread = _thread(o);\n        SQInteger threadtop = sq_gettop(thread);\n        SQInteger level;\n        sq_getinteger(v,-1,&level);\n        SQRESULT res = __sq_getcallstackinfos(thread,level);\n        if(SQ_FAILED(res))\n        {\n            sq_settop(thread,threadtop);\n            if(sq_type(thread->_lasterror) == OT_STRING) {\n                sq_throwerror(v,_stringval(thread->_lasterror));\n            }\n            else {\n                sq_throwerror(v,\"unknown error\");\n            }\n        }\n        if(res > 0) {\n            //some result\n            sq_move(v,thread,-1);\n            sq_settop(thread,threadtop);\n            return 1;\n        }\n        //no result\n        sq_settop(thread,threadtop);\n        return 0;\n\n    }\n    return sq_throwerror(v,\"wrong parameter\");\n}\n\nconst SQRegFunction SQSharedState::_thread_default_type_methods_funcz[] = {\n    {\"call\", thread_call, -1, \"v\"},\n    {\"wakeup\", thread_wakeup, -1, \"v\"},\n    {\"wakeupthrow\", thread_wakeupthrow, -2, \"v.b\"},\n    {\"getstatus\", thread_getstatus, 1, \"v\"},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"getstackinfos\",thread_getstackinfos,2, \"vn\"},\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n\nstatic SQInteger class_instance(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_getbase(HSQUIRRELVM v)\n{\n    return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR;\n}\n\nstatic SQInteger class_newmember(HSQUIRRELVM v)\n{\n    SQInteger top = sq_gettop(v);\n    SQBool bstatic = SQFalse;\n    if(top == 5)\n    {\n        sq_tobool(v,-1,&bstatic);\n        sq_pop(v,1);\n    }\n\n    if(top < 4) {\n        sq_pushnull(v);\n    }\n    return SQ_SUCCEEDED(sq_newmember(v,-4,bstatic))?1:SQ_ERROR;\n}\n\n\nstatic SQInteger get_class_metamethod(HSQUIRRELVM v)\n{\n    SQInteger mmidx = _ss(v)->GetMetaMethodIdxByName(stack_get(v, 2));\n    if (mmidx < 0)\n        return sq_throwerror(v, \"Unknown metamethod\");\n\n    SQClass *cls = nullptr;\n    if (sq_gettype(v, 1) == OT_CLASS)\n        cls = _class(stack_get(v, 1));\n    else // instance\n        cls = _instance(stack_get(v, 1))->_class;\n    v->Push(cls->_metamethods[mmidx]);\n    return 1;\n}\n\n\nstatic SQInteger class_lock(HSQUIRRELVM v)\n{\n    SQClass *cls = _class(stack_get(v, 1));\n    if (!cls->isLocked()) {\n        if (!cls->Lock(v))\n            return SQ_ERROR; // propagate raised error\n    }\n    return 1;\n}\n\n\nconst SQRegFunction SQSharedState::_class_default_type_methods_funcz[] = {\n    {\"rawget\",container_rawget,2, \"y\", NULL, true},\n    {\"rawset\",container_rawset,3, \"y\"},\n    {\"rawin\",container_rawexists,2, \"y\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"instance\",class_instance,1, \"y\"},\n    {\"getbase\",class_getbase,1, \"y\", NULL, true},\n    {\"newmember\",class_newmember,-3, \"y\"},\n    {\"getfuncinfos\",class_getfuncinfos,1, \"y\"},\n    {\"call\",closure_call,-1, \"y\"},\n    {\"pcall\",closure_pcall,-1, \"y\"},\n    {\"acall\",closure_acall,2, \"ya\"},\n    {\"pacall\",closure_pacall,2, \"ya\"},\n    {\"__update\",container_update, -2, \"t|yt|y|x\", NULL, false},\n    {\"__merge\",container_merge, -2, \"t|yt|y|x\", NULL, true},\n    {\"getmetamethod\",get_class_metamethod, 2, \"ys\"},\n    {\"hasindex\",container_hasindex,2, \"y.\", NULL, true},\n    {\"clone\",obj_clone, 1, \".\" },\n    {\"is_frozen\",obj_is_frozen, 1, \".\" },\n    {\"lock\",class_lock, 1, \"y\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\n\nstatic SQInteger instance_getclass(HSQUIRRELVM v)\n{\n    if(SQ_SUCCEEDED(sq_getclass(v,1)))\n        return 1;\n    return SQ_ERROR;\n}\n\nconst SQRegFunction SQSharedState::_instance_default_type_methods_funcz[] = {\n    {\"getclass\", instance_getclass, 1, \"x\", NULL, true},\n    {\"rawget\",container_rawget,2, \"x\", NULL, true},\n    {\"rawset\",container_rawset,3, \"x\"},\n    {\"rawin\",container_rawexists,2, \"x\", NULL, true},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"getfuncinfos\",delegable_getfuncinfos,1, \"x\"},\n    {\"getmetamethod\",get_class_metamethod, 2, \"xs\"},\n    {\"hasindex\",container_hasindex,2, \"x.\", NULL, true},\n    {\"clone\",obj_clone, 1, \".\" },\n    {\"is_frozen\",obj_is_frozen, 1, \".\" },\n    {\"swap\",swap, 3, \"x..\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nstatic SQInteger weakref_ref(HSQUIRRELVM v)\n{\n    if(SQ_FAILED(sq_getweakrefval(v,1)))\n        return SQ_ERROR;\n    return 1;\n}\n\nconst SQRegFunction SQSharedState::_weakref_default_type_methods_funcz[] = {\n    {\"constructor\",builtin_weakref_ctor, 2, NULL},\n    {\"ref\",weakref_ref,1, \"r\"},\n    {\"weakref\",obj_type_method_weakref,1, NULL },\n    {\"tostring\",default_type_method_tostring,1, \".\"},\n    {\"clone\",obj_clone, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n\nconst SQRegFunction SQSharedState::_userdata_default_type_methods_funcz[] = {\n    {\"getfuncinfos\",delegable_getfuncinfos,1, \"u\"},\n    {\"clone\",obj_clone, 1, \".\" },\n    {\"is_frozen\",obj_is_frozen, 1, \".\" },\n    {NULL,(SQFUNCTION)0,0,NULL}\n};\n"
  },
  {
    "path": "squirrel/sqclass.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"sqclass.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n\n\n\nSQClass::SQClass(SQSharedState *ss, SQClass *base) :\n    _defaultvalues(ss->_alloc_ctx),\n    _methods(ss->_alloc_ctx),\n    _nativefields(ss->_alloc_ctx)\n{\n    _base = base;\n    _typetag = 0;\n    _hook = NULL;\n    _udsize = 0;\n    _constructoridx = -1;\n    _lockedTypeId = 0;\n    _is_builtin_type = false;\n    _builtin_type_id = OT_NULL;\n    if(_base) {\n        _constructoridx = _base->_constructoridx;\n        _udsize = _base->_udsize;\n        _defaultvalues.copy(base->_defaultvalues);\n        _methods.copy(base->_methods);\n        _nativefields.copy(base->_nativefields);\n        _COPY_VECTOR(_metamethods,base->_metamethods,MT_NUM_METHODS);\n        __ObjAddRef(_base);\n    }\n    _members = base?base->_members->Clone() : SQTable::Create(ss,0);\n    __ObjAddRef(_members);\n\n    INIT_CHAIN();\n    ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);\n}\n\nvoid SQClass::Finalize() {\n    _NULL_SQOBJECT_VECTOR(_defaultvalues,_defaultvalues.size());\n    _methods.resize(0);\n    _nativefields.resize(0);\n    _NULL_SQOBJECT_VECTOR(_metamethods,MT_NUM_METHODS);\n    __ObjRelease(_members);\n    if(_base) {\n        __ObjRelease(_base);\n    }\n}\n\nSQClass::~SQClass()\n{\n    REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);\n    Finalize();\n}\n\n\nSQClass* SQClass::Create(SQVM *v,SQClass *base)\n{\n    if (base) {\n        if (base->_is_builtin_type) {\n            v->Raise_Error(\"Cannot inherit from built-in type '%s'\", IdType2Name(base->_builtin_type_id));\n            return nullptr;\n        }\n\n        if (!base->isLocked()) {\n            if (!base->Lock(v))\n                return nullptr;\n        }\n    }\n\n    SQClass *newclass = (SQClass *)SQ_MALLOC(_ss(v)->_alloc_ctx, sizeof(SQClass));\n    new (newclass) SQClass(_ss(v), base);\n    return newclass;\n}\n\n\nbool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\n{\n    SQObjectPtr temp;\n    bool belongs_to_static_table = sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE || bstatic;\n    if(isLocked() && !belongs_to_static_table)\n        return false; //the class already has an instance so cannot be modified\n    if(_members->Get(key,temp)) {\n        if (_isfield(temp)) { //overrides the default value\n            _defaultvalues[_member_idx(temp)].val = val;\n            return true;\n        }\n        if (_isnativefield(temp))\n            return false; // native fields cannot be overridden from script\n    }\n    if (_members->CountUsed() >= MEMBER_MAX_COUNT) {\n        return false;\n    }\n    if(belongs_to_static_table) {\n        SQInteger mmidx;\n        if((sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE) &&\n            (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) {\n            _metamethods[mmidx] = val;\n        }\n        else {\n            SQObjectPtr theval = val;\n            if(_base && sq_type(val) == OT_CLOSURE) {\n                theval = _closure(val)->Clone();\n                _closure(theval)->_base = _base;\n                __ObjAddRef(_base); //ref for the closure\n            }\n            if(sq_type(temp) == OT_NULL) {\n                bool isconstructor = SQVM::IsEqual(ss->_constructorstr, key);\n                if(isconstructor) {\n                    _constructoridx = (SQInteger)_methods.size();\n                }\n                SQClassMember m;\n                m.val = theval;\n                _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size())));\n                _methods.push_back(m);\n            }\n            else {\n                _methods[_member_idx(temp)].val = theval;\n            }\n        }\n        return true;\n    }\n    SQClassMember m;\n    m.val = val;\n    _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size())));\n    _defaultvalues.push_back(m);\n    return true;\n}\n\nSQInstance *SQClass::CreateInstance(SQVM *v)\n{\n    if (!isLocked()) {\n        if (!Lock(v))\n            return nullptr;\n    }\n    return SQInstance::Create(_opt_ss(this),this);\n}\n\nSQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\n{\n    SQObjectPtr oval;\n    SQInteger idx = _members->Next(false,refpos,outkey,oval);\n    if(idx != -1) {\n        if(_isfield(oval)) {\n            SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val;\n            outval = _realval(o);\n        }\n        else if(_isnativefield(oval)) {\n            outval.Null(); // no instance context\n        }\n        else {\n            outval = _methods[_member_idx(oval)].val;\n        }\n    }\n    return idx;\n}\n\n\nbool SQClass::Lock(SQVM *v)\n{\n    if (isLocked())\n        return true;\n\n    if (_base) {\n        if (!_base->Lock(v))\n            return false;\n    }\n\n    bool success = true;\n\n    if (sq_type(_metamethods[MT_LOCK]) != OT_NULL) {\n        SQInteger prevTop = v->_top;\n        SQObjectPtr res;\n        v->Push(SQObjectPtr(this));\n        success = v->Call(_metamethods[MT_LOCK], 1, v->_top-1, res, true);\n        v->_top = prevTop;\n    }\n\n    _lockedTypeId = currentHint();\n\n    return success;\n}\n\nbool SQClass::RegisterNativeField(SQSharedState *ss, const SQObjectPtr &key, uint16_t offset, uint8_t type)\n{\n    if (isLocked())\n        return false;\n    if (_udsize <= 0)\n        return false;\n    static const uint8_t type_sizes[] = {4, 8, 4, 8, 1}; // float32, float64, int32, int64, bool\n    if (type > SQNFT_BOOL || offset + type_sizes[type] > (uint32_t)_udsize)\n        return false;\n    if (_members->CountUsed() >= MEMBER_MAX_COUNT)\n        return false;\n    SQObjectPtr temp;\n    if (_members->Get(key, temp))\n        return false; // name already taken\n    SQNativeFieldDesc desc;\n    desc.offset = offset;\n    desc.type = type;\n    _members->NewSlot(key, SQObjectPtr(_make_native_field_idx(_nativefields.size())));\n    _nativefields.push_back(desc);\n    return true;\n}\n\n///////////////////////////////////////////////////////////////////////\nvoid SQInstance::Init(SQSharedState *ss)\n{\n    _alloc_ctx = ss->_alloc_ctx;\n    _userpointer = NULL;\n    _hook = NULL;\n    __ObjAddRef(_class);\n    _delegate = _class->_members;\n    INIT_CHAIN();\n    ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);\n}\n\nSQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize)\n{\n    _memsize = memsize;\n    _class = c;\n    SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n    for(SQUnsignedInteger n = 0; n < nvalues; n++) {\n        new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val);\n    }\n    Init(ss);\n}\n\nSQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize)\n{\n    _memsize = memsize;\n    _class = i->_class;\n    SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n    for(SQUnsignedInteger n = 0; n < nvalues; n++) {\n        new (&_values[n]) SQObjectPtr(i->_values[n]);\n    }\n    Init(ss);\n}\n\nvoid SQInstance::Finalize()\n{\n    SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n    __ObjRelease(_class);\n    _NULL_SQOBJECT_VECTOR(_values,nvalues);\n}\n\nSQInstance::~SQInstance()\n{\n    REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);\n    if(_class){ Finalize(); } //if _class is null it was already finalized by the GC\n}\n\nbool SQInstance::GetMetaMethod(SQVM* SQ_UNUSED_ARG(v),SQMetaMethod mm,SQObjectPtr &res)\n{\n    if(sq_type(_class->_metamethods[mm]) != OT_NULL) {\n        res = _class->_metamethods[mm];\n        return true;\n    }\n    return false;\n}\n\nbool SQInstance::InstanceOf(const SQClass *trg) const\n{\n    const SQClass *parent = _class;\n    while(parent != NULL) {\n        if(parent == trg)\n            return true;\n        parent = parent->_base;\n    }\n    return false;\n}\n"
  },
  {
    "path": "squirrel/sqclass.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQCLASS_H_\n#define _SQCLASS_H_\n\n#define SLOT_STATUS_OK         0\n#define SLOT_STATUS_NO_MATCH   1\n#define SLOT_STATUS_ERROR      2\n\nstruct SQInstance;\n\nstruct SQClassMember {\n    SQObjectPtr val;\n    void Null() {\n        val.Null();\n    }\n};\n\ntypedef sqvector<SQClassMember> SQClassMemberVec;\n\n#define MEMBER_MAX_COUNT_BIT_SHIFT 22\n#define MEMBER_TYPE_FIELD (0x01<<MEMBER_MAX_COUNT_BIT_SHIFT)\n#define MEMBER_TYPE_METHOD (0x02<<MEMBER_MAX_COUNT_BIT_SHIFT)\n#define MEMBER_TYPE_NATIVE_FIELD (0x03<<MEMBER_MAX_COUNT_BIT_SHIFT)\n#define MEMBER_KIND_MASK (0x03<<MEMBER_MAX_COUNT_BIT_SHIFT)\n#define MEMBER_MAX_COUNT ((1<<MEMBER_MAX_COUNT_BIT_SHIFT)-1)\n\n// NOTE: _isfieldi uses exact comparison, not bitwise AND.\n// (0x03 & 0x01) != 0, so bitwise AND would match NATIVE_FIELD as FIELD.\n#define _isfieldi(o) (((o)&MEMBER_KIND_MASK) == MEMBER_TYPE_FIELD)\n#define _isnativefieldi(o) (((o)&MEMBER_KIND_MASK) == MEMBER_TYPE_NATIVE_FIELD)\n#define _member_idxi(o) ((o)&MEMBER_MAX_COUNT)\n#define _isfield(o) (_isfieldi(_integer(o)))\n#define _isnativefield(o) (_isnativefieldi(_integer(o)))\n#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|(i)))\n#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|(i)))\n#define _make_native_field_idx(i) ((SQInteger)(MEMBER_TYPE_NATIVE_FIELD|(i)))\n#define _member_idx(o) (_member_idxi(_integer(o)))\n\n// Native field type constants are defined in squirrel.h as SQNFT_FLOAT32..SQNFT_BOOL\n\nstruct SQNativeFieldDesc {\n    uint16_t offset;    // byte offset within inline userdata\n    uint8_t type;       // SQNFT_* constant\n};\n\nstruct SQClass : public CHAINABLE_OBJ\n{\n    SQClass(SQSharedState *ss, SQClass *base);\npublic:\n    static SQClass* Create(SQVM *v,SQClass *base);\n    ~SQClass();\n    bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic);\n    bool RegisterNativeField(SQSharedState *ss, const SQObjectPtr &key, uint16_t offset, uint8_t type);\n    bool Get(const SQObjectPtr &key,SQObjectPtr &val) const {\n        if(_members->Get(key,val)) {\n            if(_isfield(val)) {\n                SQObjectPtr &o = _defaultvalues[_member_idx(val)].val;\n                val = _realval(o);\n            }\n            else if(_isnativefield(val)) {\n                val.Null(); // no instance context\n            }\n            else {\n                val = _methods[_member_idx(val)].val;\n            }\n            return true;\n        }\n        return false;\n    }\n    // for compiler use\n    bool GetStr(const char *key, int keylen, SQObjectPtr &val) const {\n        if(_members->GetStr(key, keylen, val)) {\n            if(_isfield(val)) {\n                SQObjectPtr &o = _defaultvalues[_member_idx(val)].val;\n                val = _realval(o);\n            }\n            else if(_isnativefield(val)) {\n                val.Null(); // no instance context\n            }\n            else {\n                val = _methods[_member_idx(val)].val;\n            }\n            return true;\n        }\n        return false;\n    }\n    bool GetConstructor(SQObjectPtr &ctor)\n    {\n        if(_constructoridx != -1) {\n            ctor = _methods[_constructoridx].val;\n            return true;\n        }\n        return false;\n    }\n    bool Lock(SQVM *v);\n    void Release() {\n        if (_hook) { _hook(_thread(_sharedstate->_root_vm),_typetag,0);}\n        SQAllocContext ctx = _methods._alloc_ctx;\n        sq_delete(ctx, this, SQClass);\n    }\n    uint64_t lockedTypeId() const {return _lockedTypeId;}\n\n    enum {CLASS_BITS = 40};\n    //all x64 bit platforms have only 48 meaningful bits in pointers. Yet, 3 lsb are always zero (or meaningless, as pointers are aligned)\n    //actually, even more bits are meaningless - as any class can't alias with other, there should be at least sizeof(SQClass) difference\n    //sizeof is at least 256 on all platforms, so there are no more than 40 meaningful bits (after first 8)\n    //still more than 32, unfortunately\n    bool isLocked() const {return _lockedTypeId != 0;}\n    static uint64_t classTypeFromHint(uint64_t hint)\n    {\n      static_assert(sizeof(SQClass)>=256);\n      return hint&((1ull<<uint64_t(CLASS_BITS)) - 1);\n    }\n    uint64_t currentHint() const {return classTypeFromHint(uintptr_t(this)>>uintptr_t(8));}\n    void Finalize();\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable ** );\n    SQObjectType GetType() {return OT_CLASS;}\n#endif\n    SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\n    SQInstance *CreateInstance(SQVM *v);\n    SQTable *_members;\n    SQClass *_base;\n    SQClassMemberVec _defaultvalues;\n    SQClassMemberVec _methods;\n    sqvector<SQNativeFieldDesc> _nativefields;\n    SQObjectPtr _metamethods[MT_NUM_METHODS];\n    SQUserPointer _typetag;\n    SQRELEASEHOOK _hook;\n    SQInteger _constructoridx;\n    SQInteger _udsize;\n    uint64_t _lockedTypeId;\n    bool _is_builtin_type;\n    SQObjectType _builtin_type_id;  // only valid if _is_builtin_type is true\n};\n\n#define calcinstancesize(_theclass_) \\\n    (_theclass_->_udsize + sq_aligning(sizeof(SQInstance) +  (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0))))\n\nstruct SQInstance : public SQDelegable\n{\n    void Init(SQSharedState *ss);\n    SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize);\n    SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize);\npublic:\n    static SQInstance* Create(SQSharedState *ss,SQClass *theclass) {\n\n        SQInteger size = calcinstancesize(theclass);\n        SQInstance *newinst = (SQInstance *)SQ_MALLOC(ss->_alloc_ctx, size);\n        new (newinst) SQInstance(ss, theclass,size);\n        if(theclass->_udsize) {\n            newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize);\n        }\n        return newinst;\n    }\n    SQInstance *Clone(SQSharedState *ss)\n    {\n        SQInteger size = calcinstancesize(_class);\n        SQInstance *newinst = (SQInstance *)SQ_MALLOC(ss->_alloc_ctx, size);\n        new (newinst) SQInstance(ss, this,size);\n        if(_class->_udsize) {\n            newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize);\n        }\n        return newinst;\n    }\n    ~SQInstance();\n\n    // Pointer to the inline userdata area at the tail of the SQInstance allocation.\n    // Computed from the allocation layout, immune to sq_setinstanceup() overrides.\n    inline void *_inlineud() const {\n        return ((unsigned char *)const_cast<SQInstance*>(this)) + (_memsize - _class->_udsize);\n    }\n\n    inline void GetNativeField(uint32_t fieldIdx, SQObjectPtr &val) const {\n        const SQNativeFieldDesc &desc = _class->_nativefields[fieldIdx];\n        const char *p = (const char *)_inlineud() + desc.offset;\n        switch (desc.type) {\n        case SQNFT_FLOAT32: val = SQObjectPtr((SQFloat)*(const float *)p); break;\n        case SQNFT_FLOAT64: val = SQObjectPtr((SQFloat)*(const double *)p); break;\n        case SQNFT_INT32:   val = SQObjectPtr((SQInteger)*(const int32_t *)p); break;\n        case SQNFT_INT64:   val = SQObjectPtr((SQInteger)*(const int64_t *)p); break;\n        case SQNFT_BOOL:    val._type = OT_BOOL; val._unVal.nInteger = *(const bool *)p ? 1 : 0; break;\n        }\n    }\n\n    inline bool SetNativeField(uint32_t fieldIdx, const SQObjectPtr &val) {\n        const SQNativeFieldDesc &desc = _class->_nativefields[fieldIdx];\n        char *p = (char *)_inlineud() + desc.offset;\n        SQObjectType vt = sq_type(val);\n        switch (desc.type) {\n        case SQNFT_FLOAT32:\n            if (vt == OT_FLOAT) *(float *)p = (float)_float(val);\n            else if (vt == OT_INTEGER) *(float *)p = (float)_integer(val);\n            else return false;\n            break;\n        case SQNFT_FLOAT64:\n            if (vt == OT_FLOAT) *(double *)p = (double)_float(val);\n            else if (vt == OT_INTEGER) *(double *)p = (double)_integer(val);\n            else return false;\n            break;\n        case SQNFT_INT32:\n            if (vt == OT_INTEGER) *(int32_t *)p = (int32_t)_integer(val);\n            else if (vt == OT_FLOAT) *(int32_t *)p = (int32_t)_float(val);\n            else return false;\n            break;\n        case SQNFT_INT64:\n            if (vt == OT_INTEGER) *(int64_t *)p = (int64_t)_integer(val);\n            else if (vt == OT_FLOAT) *(int64_t *)p = (int64_t)_float(val);\n            else return false;\n            break;\n        case SQNFT_BOOL:\n            if (vt == OT_BOOL || vt == OT_INTEGER) *(bool *)p = _integer(val) != 0;\n            else return false;\n            break;\n        }\n        return true;\n    }\n\n    inline void GetMember(uint32_t idx, SQObjectPtr &val) const {\n        uint32_t kind = idx & MEMBER_KIND_MASK;\n        if (kind == MEMBER_TYPE_FIELD)\n            val = _realval(_values[_member_idxi(idx)]);\n        else if (kind == MEMBER_TYPE_NATIVE_FIELD)\n            GetNativeField(_member_idxi(idx), val);\n        else\n            val = _class->_methods[_member_idxi(idx)].val;\n    }\n    bool Get(const SQObjectPtr &key,SQObjectPtr &val) const {\n        if(_class->_members->Get(key,val)) {\n            GetMember(_integer(val), val);\n            return true;\n        }\n        return false;\n    }\n    void SetMemberField(uint32_t idx, const SQObjectPtr &val) {\n        _values[_member_idxi(idx)] = val;\n    }\n    SQInteger Set(const SQObjectPtr &key,const SQObjectPtr &val) {\n        SQObjectPtr idx;\n        if(_class->_members->Get(key,idx)) {\n            if (_isfield(idx)) {\n                SetMemberField(_integer(idx), val);\n                return SLOT_STATUS_OK;\n            }\n            if (_isnativefield(idx)) {\n                return SetNativeField(_member_idx(idx), val)\n                    ?  SLOT_STATUS_OK : SLOT_STATUS_ERROR;\n            }\n        }\n        return SLOT_STATUS_NO_MATCH;\n    }\n    void Release() {\n        _uiRef++;\n        if (_hook) { _hook(_thread(_sharedstate->_root_vm),_userpointer,0);}\n        _uiRef--;\n        if(_uiRef > 0) return;\n        SQInteger size = _memsize;\n        SQAllocContext ctx = _alloc_ctx;\n        this->~SQInstance();\n        SQ_FREE(ctx, this, size);\n    }\n    void Finalize();\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable ** );\n    SQObjectType GetType() {return OT_INSTANCE;}\n#endif\n    bool InstanceOf(const SQClass *trg) const;\n    bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\n\n    SQClass *_class;\n    SQUserPointer _userpointer;\n    SQRELEASEHOOK _hook;\n    SQAllocContext _alloc_ctx;\n    SQInteger _memsize;\n    SQObjectPtr _values[1];\n};\n\n#endif //_SQCLASS_H_\n"
  },
  {
    "path": "squirrel/sqclosure.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQCLOSURE_H_\n#define _SQCLOSURE_H_\n\n\n#define _CALC_CLOSURE_SIZE(func) (sizeof(SQClosure) + (func->_noutervalues*sizeof(SQObjectPtr)) + (func->_ndefaultparams*sizeof(SQObjectPtr)))\n\nstruct SQFunctionProto;\nstruct SQClass;\nstruct SQClosure : public CHAINABLE_OBJ\n{\nprivate:\n    SQClosure(SQSharedState *ss,SQFunctionProto *func)\n    {\n      _function = func; __ObjAddRef(_function); _base = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;\n    }\n\npublic:\n    static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){\n        SQInteger size = _CALC_CLOSURE_SIZE(func);\n        SQClosure *nc=(SQClosure*)SQ_MALLOC(ss->_alloc_ctx, size);\n        new (nc) SQClosure(ss,func);\n        nc->_outervalues = (SQObjectPtr *)(nc + 1);\n        nc->_defaultparams = &nc->_outervalues[func->_noutervalues];\n        _CONSTRUCT_VECTOR(SQObjectPtr,func->_noutervalues,nc->_outervalues);\n        _CONSTRUCT_VECTOR(SQObjectPtr,func->_ndefaultparams,nc->_defaultparams);\n        return nc;\n    }\n    void Release(){\n        SQFunctionProto *f = _function;\n        SQInteger size = _CALC_CLOSURE_SIZE(f);\n        SQAllocContext ctx = f->_alloc_ctx;\n        _DESTRUCT_VECTOR(SQObjectPtr,f->_noutervalues,_outervalues);\n        _DESTRUCT_VECTOR(SQObjectPtr,f->_ndefaultparams,_defaultparams);\n        __ObjRelease(_function);\n        this->~SQClosure();\n        sq_vm_free(ctx, this, size);\n    }\n    SQClosure *Clone()\n    {\n        SQFunctionProto *f = _function;\n        SQClosure * ret = SQClosure::Create(_opt_ss(this),f);\n        ret->_env = _env;\n        if(ret->_env) __ObjAddRef(ret->_env);\n        _COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues);\n        _COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams);\n        return ret;\n    }\n    ~SQClosure();\n\n    bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);\n    static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){\n        SQFunctionProto *f = _function;\n        _NULL_SQOBJECT_VECTOR(_outervalues,f->_noutervalues);\n        _NULL_SQOBJECT_VECTOR(_defaultparams,f->_ndefaultparams);\n    }\n    SQObjectType GetType() {return OT_CLOSURE;}\n#endif\n    SQWeakRef *_env;\n    SQClass *_base;\n    SQFunctionProto *_function;\n    SQObjectPtr *_outervalues;\n    SQObjectPtr *_defaultparams;\n};\n\n//////////////////////////////////////////////\nstruct SQOuter : public CHAINABLE_OBJ\n{\n\nprivate:\n    SQOuter(SQSharedState *ss, SQObjectPtr *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); }\n\npublic:\n    static SQOuter *Create(SQSharedState *ss, SQObjectPtr *outer)\n    {\n        SQOuter *nc  = (SQOuter*)SQ_MALLOC(ss->_alloc_ctx, sizeof(SQOuter));\n        new (nc) SQOuter(ss, outer);\n        return nc;\n    }\n    ~SQOuter() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); }\n\n    void Release()\n    {\n        this->~SQOuter();\n        sq_vm_free(_sharedstate->_alloc_ctx, this, sizeof(SQOuter));\n    }\n\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize() { _value.Null(); }\n    SQObjectType GetType() {return OT_OUTER;}\n#endif\n\n    SQObjectPtr *_valptr;  /* pointer to value on stack, or _value below */\n    SQInteger    _idx;     /* idx in stack array, for relocation */\n    SQObjectPtr  _value;   /* value of outer after stack frame is closed */\n    SQOuter     *_next;    /* pointer to next outer when frame is open   */\n};\n\n//////////////////////////////////////////////\nstruct SQGenerator : public CHAINABLE_OBJ\n{\n    enum SQGeneratorState{eRunning,eSuspended,eDead};\nprivate:\n    SQGenerator(SQSharedState *ss,SQClosure *closure) :\n      _stack(ss->_alloc_ctx),\n      _etraps(ss->_alloc_ctx)\n    {\n      _closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\n    }\npublic:\n    static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){\n        SQGenerator *nc=(SQGenerator*)SQ_MALLOC(ss->_alloc_ctx, sizeof(SQGenerator));\n        new (nc) SQGenerator(ss,closure);\n        return nc;\n    }\n    ~SQGenerator()\n    {\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n    }\n    void Kill(){\n        _state=eDead;\n        _stack.resize(0);\n        _closure.Null();}\n    void Release(){\n        sq_delete(_sharedstate->_alloc_ctx, this,SQGenerator);\n    }\n\n    bool Yield(SQVM *v,SQInteger target);\n    bool Resume(SQVM *v,SQObjectPtr &dest);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){_stack.resize(0);_closure.Null();}\n    SQObjectType GetType() {return OT_GENERATOR;}\n#endif\n    SQObjectPtr _closure;\n    SQObjectPtrVec _stack;\n    SQVM::CallInfo _ci;\n    ExceptionsTraps _etraps;\n    SQGeneratorState _state;\n};\n\n#define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(SQNativeClosure) + ((noutervalues)*sizeof(SQObjectPtr)))\n\nstruct SQNativeClosure : public CHAINABLE_OBJ\n{\nprivate:\n    SQNativeClosure(SQSharedState *ss,SQFUNCTION func) :\n      _typecheck(ss->_alloc_ctx), _purefunction(false), _nodiscard(false)\n    {\n      _function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;\n    }\npublic:\n    static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func,SQInteger nouters)\n    {\n        SQInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters);\n        SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(ss->_alloc_ctx, size);\n        new (nc) SQNativeClosure(ss,func);\n        nc->_outervalues = (SQObjectPtr *)(nc + 1);\n        nc->_noutervalues = nouters;\n        nc->_result_type_mask = ~0u;\n        nc->_purefunction = false;\n        nc->_nodiscard = false;\n        _CONSTRUCT_VECTOR(SQObjectPtr,nc->_noutervalues,nc->_outervalues);\n        return nc;\n    }\n    SQNativeClosure *Clone()\n    {\n        SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function,_noutervalues);\n        ret->_env = _env;\n        if(ret->_env) __ObjAddRef(ret->_env);\n        ret->_name = _name;\n        _COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues);\n        ret->_result_type_mask = _result_type_mask;\n        ret->_typecheck.copy(_typecheck);\n        ret->_nparamscheck = _nparamscheck;\n        ret->_purefunction = _purefunction;\n        ret->_nodiscard = _nodiscard;\n        return ret;\n    }\n    ~SQNativeClosure()\n    {\n        __ObjRelease(_env);\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n    }\n    void Release(){\n        SQInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues);\n        _DESTRUCT_VECTOR(SQObjectPtr,_noutervalues,_outervalues);\n        SQAllocContext ctx = _typecheck._alloc_ctx;\n        this->~SQNativeClosure();\n        sq_free(ctx, this, size);\n    }\n\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize() { _NULL_SQOBJECT_VECTOR(_outervalues,_noutervalues); }\n    SQObjectType GetType() {return OT_NATIVECLOSURE;}\n#endif\n    SQInteger _nparamscheck;\n    SQUnsignedInteger32 _noutervalues;\n    SQUnsignedInteger32 _result_type_mask;\n    bool _purefunction;\n    bool _nodiscard;\n    SQIntVec _typecheck;\n    SQObjectPtr *_outervalues;\n    SQWeakRef *_env;\n    SQFUNCTION _function;\n    SQObjectPtr _name;\n};\n\n\n\n#endif //_SQCLOSURE_H_\n"
  },
  {
    "path": "squirrel/sqdebug.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include <stdarg.h>\n#include \"sqvm.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n\nSQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi)\n{\n    SQInteger cssize = v->_callsstacksize;\n    if (level >= 0 && cssize > level) {\n        SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];\n        if(sq_isclosure(ci._closure)) {\n            SQClosure *c = _closure(ci._closure);\n            SQFunctionProto *proto = c->_function;\n            fi->funcid = proto;\n            fi->name = sq_type(proto->_name) == OT_STRING?_stringval(proto->_name):\"unknown\";\n            fi->source = sq_type(proto->_sourcename) == OT_STRING?_stringval(proto->_sourcename):\"unknown\";\n            fi->line = proto->_lineinfos->_first_line;\n            return SQ_OK;\n        }\n    }\n    return sq_throwerror(v,\"the object is not a closure\");\n}\n\nSQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si)\n{\n    SQInteger cssize = v->_callsstacksize;\n    if (level >= 0 && cssize > level) {\n        memset(si, 0, sizeof(SQStackInfos));\n        SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];\n        switch (sq_type(ci._closure)) {\n        case OT_CLOSURE:{\n            SQFunctionProto *func = _closure(ci._closure)->_function;\n            if (sq_type(func->_name) == OT_STRING)\n                si->funcname = _stringval(func->_name);\n            if (sq_type(func->_sourcename) == OT_STRING)\n                si->source = _stringval(func->_sourcename);\n            si->line = func->GetLine(ci._ip);\n            break;\n        }\n        case OT_NATIVECLOSURE:\n            si->source = \"NATIVE\";\n            si->funcname = \"unknown\";\n            if(sq_type(_nativeclosure(ci._closure)->_name) == OT_STRING)\n                si->funcname = _stringval(_nativeclosure(ci._closure)->_name);\n            si->line = -1;\n            break;\n        default: break; //shutup compiler\n        }\n        return SQ_OK;\n    }\n    return SQ_ERROR;\n}\n\nvoid SQVM::Raise_Error(const char *s, ...)\n{\n    va_list vl;\n    va_start(vl, s);\n    SQInteger buffersize = (SQInteger)strlen(s) + 256;\n    vsnprintf(_sp(buffersize),buffersize, s, vl);\n    va_end(vl);\n    _lasterror = SQString::Create(_ss(this),_spval,-1);\n}\n\nvoid SQVM::Raise_Error(const SQObjectPtr &desc)\n{\n    _lasterror = desc;\n}\n\nSQString *SQVM::PrintObjVal(const SQObject &o)\n{\n    constexpr SQInteger MAX_STR_DISPLAY = 58;\n    // Printable overhead: ' (1) + ...' (4) + ' (type='string')' (16) = 21\n    constexpr SQInteger MAX_REPR_LEN = MAX_STR_DISPLAY + 21;\n    char buf[MAX_REPR_LEN + 1];\n\n    switch (sq_type(o)) {\n        case OT_STRING: {\n            SQInteger len = _string(o)->_len;\n            if (len > MAX_STR_DISPLAY) {\n                scsprintf(buf, sizeof(buf),\n                    \"'%.*s...' (type='%s')\", (int)MAX_STR_DISPLAY, _stringval(o), GetTypeName(o));\n            } else {\n                scsprintf(buf, sizeof(buf),\n                    \"'%s' (type='%s')\", _stringval(o), GetTypeName(o));\n            }\n            return SQString::Create(_ss(this), buf);\n        }\n        case OT_INTEGER:\n            scsprintf(buf, sizeof(buf),\n                    \"'\" _PRINT_INT_FMT \"' (type='%s')\", _integer(o), GetTypeName(o));\n            return SQString::Create(_ss(this), buf);\n        case OT_FLOAT:\n            scsprintf(buf, sizeof(buf),\n                    \"'%.14g' (type='%s')\", _float(o), GetTypeName(o));\n            return SQString::Create(_ss(this), buf);\n        default:\n            return SQString::Create(_ss(this), GetTypeName(o));\n    }\n}\n\nvoid SQVM::Raise_IdxError(const SQObjectPtr &o)\n{\n    SQObjectPtr oval(PrintObjVal(o));\n    Raise_Error(\"the index %s does not exist\", _stringval(oval));\n}\n\nvoid SQVM::Raise_MetamethodError(const char *mmname)\n{\n    if (sq_type(_lasterror) == OT_STRING) {\n        Raise_Error(\"Error in '%s' metamethod: %s\", mmname, _stringval(_lasterror));\n    } else {\n        SQObjectPtr oval(PrintObjVal(_lasterror));\n        Raise_Error(\"Error in '%s' metamethod: %s\", mmname, _stringval(oval));\n    }\n}\n\nvoid SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2)\n{\n    SQObjectPtr oval1(PrintObjVal(o1)), oval2(PrintObjVal(o2));\n    Raise_Error(\"comparison between %s and %s\", _stringval(oval1), _stringval(oval2));\n}\n\n\nvoid SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type,const char *funcname)\n{\n    SQObjectPtr exptypes(SQString::Create(_ss(this), \"\", -1));\n    SQInteger found = 0;\n    for(SQInteger i=0; i<16; i++)\n    {\n        SQInteger mask = ((SQInteger)1) << i;\n        if(typemask & (mask)) {\n            if(found>0) StringCat(exptypes, SQObjectPtr(SQString::Create(_ss(this), \"|\", -1)), exptypes);\n            found ++;\n            StringCat(exptypes, SQObjectPtr(SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1)), exptypes);\n        }\n    }\n    Raise_Error(\"parameter %d of '%s' has an invalid type '%s' ; expected: '%s'\", (int)nparam,\n                funcname && *funcname ? funcname : \"<unknown>\", IdType2Name((SQObjectType)type), _stringval(exptypes));\n}\n"
  },
  {
    "path": "squirrel/sqdedupshrinker.cpp",
    "content": "#include \"sqpcheader.h\"\n#include \"sqstate.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n\n#define SHRINK_HASH_INIT 0x811c9dc5\n#define SHRINK_HASH_MUL  0x01193193\n\nstatic inline uint32_t calc_shrinker_hash(uint32_t * data, int bytes)\n{\n  uint32_t hash = SHRINK_HASH_INIT;\n  for (int i = 0; i < bytes / 4; i++)\n    hash = (hash ^ data[i]) * SHRINK_HASH_MUL;\n  return (hash >> 19) ^ hash;\n}\n\nstruct SQDeduplicateShrinker\n{\nprivate:\n  static constexpr int CACHE_SIZE = 1 << 12; // must be power of 2\n  static constexpr int CACHE_ITEMS_LIMIT = 20;\n  SQObjectPtrVec arrayCache;\n  SQObjectPtrVec tableCache;\n  sqvector<void *> visitedTables;\n  sqvector<void *> visitedArrays;\n\npublic:\n\n  SQDeduplicateShrinker(HSQUIRRELVM vm) : arrayCache(vm->_sharedstate->_alloc_ctx), tableCache(vm->_sharedstate->_alloc_ctx),\n    visitedTables(vm->_sharedstate->_alloc_ctx), visitedArrays(vm->_sharedstate->_alloc_ctx)\n  {\n    arrayCache.resize(CACHE_SIZE);\n    tableCache.resize(CACHE_SIZE);\n  }\n\n  SQDeduplicateShrinker(const SQDeduplicateShrinker &) = delete;\n  SQDeduplicateShrinker(SQDeduplicateShrinker &&) = delete;\n  SQDeduplicateShrinker & operator=(const SQDeduplicateShrinker &) = delete;\n  SQDeduplicateShrinker & operator=(SQDeduplicateShrinker &&) = delete;\n\n\n  bool shrink(SQObjectPtr & obj)\n  {\n    switch (obj._type)\n    {\n      case OT_TABLE:\n      {\n        obj._flags |= SQOBJ_FLAG_IMMUTABLE;\n        bool simpleTypes = true;\n        SQTable *t = _table(obj);\n        int itemsCount = t->CountUsed();\n\n        SQTable::_HashNode *nodes = t->_nodes;\n        int allocatedNodes = t->AllocatedNodes();\n        int cacheIndex = 0;\n\n        if (itemsCount <= CACHE_ITEMS_LIMIT)\n        {\n          uint32_t hash = calc_shrinker_hash((uint32_t *)nodes, allocatedNodes * sizeof(SQTable::_HashNode));\n          cacheIndex = hash & (CACHE_SIZE - 1);\n          if (sq_istable(tableCache[cacheIndex]) && t->IsBinaryEqual(_table(tableCache[cacheIndex])))\n          {\n            obj = tableCache[cacheIndex];\n            return true;\n          }\n        }\n\n        for (void *p : visitedTables)\n          if (p == _table(obj))\n            return false;\n\n        visitedTables.push_back(_table(obj));\n\n        for (int i = 0; i < allocatedNodes; i++)\n        {\n          if (!(sq_type(nodes[i].key) & OT_FREE_TABLE_SLOT))\n          {\n            if (!sq_isstring(nodes[i].key) || (!sq_isnull(nodes[i].val) && !sq_isstring(nodes[i].val) && !sq_isinteger(nodes[i].val) && !sq_isfloat(nodes[i].val) && !sq_isbool(nodes[i].val)))\n              simpleTypes = false;\n\n            if (sq_isarray(nodes[i].val) || sq_istable(nodes[i].val))\n              shrink(nodes[i].val); // note: classType is not changed\n          }\n        }\n\n        visitedTables.pop_back();\n\n        if (simpleTypes && itemsCount <= CACHE_ITEMS_LIMIT)\n          tableCache[cacheIndex] = obj;\n      }\n      break;\n\n      case OT_ARRAY:\n      {\n        bool simpleTypes = true;\n        SQArray *array = _array(obj);\n        array->ShrinkIfNeeded();\n        obj._flags |= SQOBJ_FLAG_IMMUTABLE;\n        int cacheIndex = 0;\n\n        if (array->Size() <= CACHE_ITEMS_LIMIT)\n        {\n          uint32_t hash = calc_shrinker_hash((uint32_t *)&array->_values[0], array->Size() * sizeof(SQObjectPtr));\n          cacheIndex = hash & (CACHE_SIZE - 1);\n          if (sq_isarray(arrayCache[cacheIndex]) && array->IsBinaryEqual(_array(arrayCache[cacheIndex])))\n          {\n            obj = arrayCache[cacheIndex];\n            return true;\n          }\n        }\n\n        for (void *p : visitedArrays)\n          if (p == _array(obj))\n            return false;\n\n        visitedArrays.push_back(_array(obj));\n\n        for (int i = 0; i < int(array->Size()); i++)\n        {\n          if (!sq_isnull(array->_values[i]) && !sq_isstring(array->_values[i]) && !sq_isinteger(array->_values[i]) && !sq_isfloat(array->_values[i]) && !sq_isbool(array->_values[i]))\n            simpleTypes = false;\n\n          if (sq_isarray(array->_values[i]) || sq_istable(array->_values[i]))\n            shrink(array->_values[i]);\n        }\n\n        visitedArrays.pop_back();\n\n        if (simpleTypes && array->Size() <= CACHE_ITEMS_LIMIT)\n          arrayCache[cacheIndex] = obj;\n      }\n\n      default:\n        break;\n    }\n\n    return false;\n  }\n};\n\nSQRESULT sq_deduplicate_object(HSQUIRRELVM vm, int index)\n{\n  SQDeduplicateShrinker shrinker(vm);\n  shrinker.shrink(stack_get(vm, index));\n  return SQ_OK;\n}\n"
  },
  {
    "path": "squirrel/sqext.cpp",
    "content": "#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstate.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n#include \"sqarray.h\"\n\n\nSQRESULT sq_ext_getfuncinfo(HSQOBJECT obj, SQFunctionInfo *fi)\n{\n  if (!fi)\n    return SQ_ERROR;\n\n  if (!sq_isclosure(obj) && !sq_isnativeclosure(obj))\n    return SQ_ERROR;\n\n  if (sq_isclosure(obj))\n  {\n    SQFunctionProto *proto = _closure(obj)->_function;\n    if (!proto)\n      return SQ_ERROR;\n\n    fi->funcid = proto;\n    fi->name = sq_type(proto->_name) == OT_STRING?_stringval(proto->_name):\"unknown\";\n    fi->source = sq_type(proto->_sourcename) == OT_STRING?_stringval(proto->_sourcename):\"unknown\";\n    fi->line = proto->_lineinfos->_first_line;\n  }\n  else\n  {\n    SQNativeClosure *c = _nativeclosure(obj);\n\n    fi->funcid = (SQUserPointer)c->_function;\n    fi->name = sq_type(c->_name) == OT_STRING?_stringval(c->_name):\"unknown\";\n    fi->source = \"native\";\n    fi->line = -1;\n  }\n\n  return SQ_OK;\n}\n\n\nSQRESULT sq_ext_get_array_floats(HSQOBJECT obj, int start, int count, float * dest)\n{\n  if (sq_type(obj) != OT_ARRAY || !dest)\n    return SQ_ERROR;\n\n  SQArray * array = _array(obj);\n  SQObjectPtrVec & values = array->_values;\n  int arraySize = values.size();\n\n  if (count + start > arraySize)\n    return SQ_ERROR;\n\n  for (int i = 0; i < count; i++)\n  {\n    SQObjectPtr & v = values[i + start];\n    if (sq_type(v) == OT_FLOAT)\n      dest[i] = _float(v);\n    else if (sq_type(v) == OT_INTEGER || sq_type(v) == OT_BOOL)\n      dest[i] = _integer(v);\n    else\n      dest[i] = 0;\n  }\n\n  return SQ_OK;\n}\n\n\nint sq_ext_get_array_int(HSQOBJECT obj, int index, int def)\n{\n  if (sq_type(obj) != OT_ARRAY)\n    return def;\n\n  SQObjectPtrVec & values = _array(obj)->_values;\n  if (index < 0 || index >= values.size())\n    return def;\n\n  SQObjectPtr & v = values[index];\n  if (sq_type(v) == OT_INTEGER || sq_type(v) == OT_BOOL)\n    return _integer(v);\n  else if (sq_type(v) == OT_FLOAT)\n    return int(_float(v));\n  else\n    return def;\n}\n\n\nfloat sq_ext_get_array_float(HSQOBJECT obj, int index, float def)\n{\n  if (sq_type(obj) != OT_ARRAY)\n    return def;\n\n  SQObjectPtrVec & values = _array(obj)->_values;\n  if (index < 0 || index >= values.size())\n    return def;\n\n  SQObjectPtr & v = values[index];\n  if (sq_type(v) == OT_FLOAT)\n    return _float(v);\n  if (sq_type(v) == OT_INTEGER || sq_type(v) == OT_BOOL)\n    return _integer(v);\n  else\n    return def;\n}\n\n"
  },
  {
    "path": "squirrel/sqfuncproto.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQFUNCTION_H_\n#define _SQFUNCTION_H_\n\n#include \"opcodes.h\"\n\nenum SQOuterType {\n    otLOCAL = 0,\n    otOUTER = 1\n};\n\nenum SQLangFeature {\n    // parsing stage\n    LF_FORBID_ROOT_TABLE = 0x000001,\n    LF_FORBID_DELETE_OP = 0x000004,\n    LF_FORBID_CLONE_OP = 0x000008,\n    LF_FORBID_SWITCH_STMT = 0x000010,\n\n    // code generation stage\n    LF_DISABLE_OPTIMIZER = 0x000200,\n    LF_FORBID_GLOBAL_CONST_REWRITE = 0x000400,\n    LF_FORBID_IMPLICIT_TYPE_METHODS = 0x000800,\n    LF_ALLOW_AUTO_FREEZE = 0x001000,\n    LF_ALLOW_COMPILER_INTERNALS = 0x002000,\n\n    LF_STRICT = LF_FORBID_ROOT_TABLE |\n                LF_FORBID_DELETE_OP\n};\n\n\nenum SQVarFlags {\n    VF_ASSIGNABLE = 1 << 0,\n    VF_INIT_WITH_CONST = 1 << 1,\n    VF_PARAM = 1 << 2,\n    VF_DESTRUCTURED = 1 << 3,\n    VF_INIT_WITH_FREEZE = 1 << 4,\n    VF_INIT_WITH_PURE = 1 << 5,\n    VF_FIRST_LEVEL = 1 << 6,\n};\n\nstruct SQOuterVar\n{\n    SQOuterVar() : _varFlags(VF_ASSIGNABLE) {}\n    SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t,char varFlags)\n    {\n        _name = name;\n        _src=src;\n        _type=t;\n        _varFlags=varFlags;\n    }\n    SQOuterVar(const SQOuterVar &ov)\n    {\n        _type=ov._type;\n        _src=ov._src;\n        _name=ov._name;\n        _varFlags=ov._varFlags;\n    }\n    SQOuterType _type;\n    char _varFlags;\n    SQObjectPtr _name;\n    SQObjectPtr _src;\n};\n\nstruct SQLocalVarInfo\n{\n    SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0),_varFlags(VF_ASSIGNABLE){}\n    SQLocalVarInfo(const SQLocalVarInfo &lvi)\n    {\n        _name=lvi._name;\n        _start_op=lvi._start_op;\n        _end_op=lvi._end_op;\n        _pos=lvi._pos;\n        _varFlags=lvi._varFlags;\n    }\n    SQObjectPtr _name;\n    uint32_t _start_op;\n    uint32_t _end_op;\n    uint32_t _pos;\n    char _varFlags;\n};\n\nstruct SQLineInfosHeader\n{\n    unsigned _first_line: 31;\n    unsigned _is_compressed: 1;\n};\n\nstruct SQFullLineInfo\n{\n    uint32_t _op;\n    uint32_t _line_offset: 31;\n    uint32_t _is_dbg_step_point: 1;\n};\n\nstruct SQCompressedLineInfo\n{\n    uint8_t _op;\n    uint8_t _line_offset: 7;\n    uint8_t _is_dbg_step_point: 1;\n};\n\ntypedef sqvector<SQOuterVar> SQOuterVarVec;\ntypedef sqvector<SQLocalVarInfo> SQLocalVarInfoVec;\ntypedef sqvector<SQFullLineInfo> SQFullLineInfoVec;\n\n#define SQ_ALIGN_TO(n, t) (((n) + alignof(t) - 1) & ~(alignof(t) - 1))\n\n#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,compressed,localinf,defparams,nstaticmemos) (sizeof(SQFunctionProto) \\\n        +SQ_ALIGN_TO(((ni)-1)*sizeof(SQInstruction), SQObjectPtr)+((nl)*sizeof(SQObjectPtr)) \\\n        +((nparams)*sizeof(SQObjectPtr))+((nfuncs)*sizeof(SQObjectPtr)) \\\n        +((nouters)*sizeof(SQOuterVar)) \\\n        +SQ_ALIGN_TO(sizeof(SQLineInfosHeader)+(nlineinf)*(compressed ? sizeof(SQCompressedLineInfo) : sizeof(SQFullLineInfo)), SQLocalVarInfo) \\\n        +((localinf)*sizeof(SQLocalVarInfo))+((defparams)*sizeof(SQInt32))+((nparams)*sizeof(SQUnsignedInteger32)) \\\n        +((nstaticmemos)*sizeof(SQObjectPtr)))\n\n\nstruct SQFunctionProto : public CHAINABLE_OBJ\n{\nprivate:\n    SQFunctionProto(SQSharedState *ss);\n    ~SQFunctionProto();\n\npublic:\n    static SQFunctionProto *Create(SQSharedState *ss,\n        SQUnsignedInteger lang_features,\n        SQInteger ninstructions,\n        SQInteger nliterals,SQInteger nparameters,\n        SQInteger nfunctions,SQInteger noutervalues,\n        SQInteger nlineinfos, bool compressedLineInfos,\n        SQInteger nlocalvarinfos,\n        SQInteger ndefaultparams,SQInteger nstaticmemos\n        )\n    {\n        SQFunctionProto *f;\n        //I compact the whole class and members in a single memory allocation\n        size_t fnSize = _FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,compressedLineInfos,nlocalvarinfos,ndefaultparams,nstaticmemos);\n        f = (SQFunctionProto *)sq_vm_malloc(ss->_alloc_ctx, fnSize);\n\n        new (f) SQFunctionProto(ss);\n        char *ptr = (char *)f->_instructions;\n\n        f->_result_type_mask = ~0u;\n\n        f->_alloc_ctx = ss->_alloc_ctx;\n        f->lang_features = lang_features;\n        f->_ninstructions = ninstructions;\n        ptr += SQ_ALIGN_TO(ninstructions * sizeof(SQInstruction), SQLocalVarInfo);\n\n        assert(size_t(ptr) % alignof(SQObjectPtr) == 0);\n        f->_literals = (SQObjectPtr*)ptr;\n        f->_nliterals = nliterals;\n        ptr += nliterals * sizeof(SQObjectPtr);\n\n        f->_parameters = (SQObjectPtr*)ptr;\n        f->_nparameters = nparameters;\n        ptr += nparameters * sizeof(SQObjectPtr);\n\n        f->_functions = (SQObjectPtr*)ptr;\n        f->_nfunctions = nfunctions;\n        ptr += nfunctions * sizeof(SQObjectPtr);\n\n        f->_staticmemos = (SQObjectPtr*)ptr;\n        f->_nstaticmemos = nstaticmemos;\n        ptr += nstaticmemos * sizeof(SQObjectPtr);\n\n        assert(size_t(ptr) % alignof(SQOuterVar) == 0);\n        f->_outervalues = (SQOuterVar*)ptr;\n        f->_noutervalues = noutervalues;\n        ptr += noutervalues * sizeof(SQOuterVar);\n\n        assert(size_t(ptr) % alignof(SQLineInfosHeader) == 0);\n        f->_lineinfos = (SQLineInfosHeader *)ptr;\n        f->_nlineinfos = nlineinfos;\n        ptr += SQ_ALIGN_TO(sizeof(SQLineInfosHeader) + nlineinfos * (compressedLineInfos ? sizeof(SQCompressedLineInfo) : sizeof(SQFullLineInfo)), SQLocalVarInfo);\n\n        assert(size_t(ptr) % alignof(SQLocalVarInfo) == 0);\n        f->_localvarinfos = (SQLocalVarInfo *)ptr;\n        f->_nlocalvarinfos = nlocalvarinfos;\n        ptr += nlocalvarinfos * sizeof(SQLocalVarInfo);\n\n        assert(size_t(ptr) % alignof(SQInt32) == 0);\n        f->_defaultparams = (SQInt32 *)ptr;\n        f->_ndefaultparams = ndefaultparams;\n        ptr += ndefaultparams * sizeof(SQInt32);\n\n        f->_param_type_masks = (SQUnsignedInteger32 *)ptr;\n        ptr += nparameters * sizeof(SQUnsignedInteger32);\n\n        assert(ptr - (char *)f == fnSize);\n\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nliterals,f->_literals);\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nparameters,f->_parameters);\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nfunctions,f->_functions);\n        _CONSTRUCT_VECTOR(SQObjectPtr,f->_nstaticmemos,f->_staticmemos);\n        _CONSTRUCT_VECTOR(SQOuterVar,f->_noutervalues,f->_outervalues);\n        //_CONSTRUCT_VECTOR(SQLineInfo,f->_nlineinfos,f->_lineinfos); //not required are 2 integers\n        _CONSTRUCT_VECTOR(SQLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos);\n        return f;\n    }\n    void Release(){\n        _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals);\n        _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters);\n        _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions);\n        _DESTRUCT_VECTOR(SQObjectPtr,_nstaticmemos,_staticmemos);\n        _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues);\n        //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers\n        _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos);\n        SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_lineinfos->_is_compressed,_nlocalvarinfos,_ndefaultparams,_nstaticmemos);\n        SQAllocContext ctx = _alloc_ctx;\n        this->~SQFunctionProto();\n        sq_vm_free(ctx, this, size);\n    }\n\n    const char* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop);\n    static SQInteger GetLine(SQLineInfosHeader *lineinfos, int nlineinfos, int instruction_index, int *hint, bool *is_dbg_step_point = nullptr);\n    SQInteger GetLine(const SQInstruction *curr, int *hint = nullptr, bool *is_dbg_step_point = nullptr);\n    bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);\n    static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){\n        _NULL_SQOBJECT_VECTOR(_literals,_nliterals);\n        _NULL_SQOBJECT_VECTOR(_staticmemos,_nstaticmemos);\n    }\n    SQObjectType GetType() {return OT_FUNCPROTO;}\n#endif\n    SQAllocContext _alloc_ctx;\n    SQObjectPtr _sourcename;\n    SQObjectPtr _name;\n    SQUnsignedInteger32 lang_features;\n    SQUnsignedInteger32 _result_type_mask;\n    bool _inside_hoisted_scope;\n    bool _bgenerator;\n    bool _purefunction;\n    bool _nodiscard;\n    SQInt32 _stacksize;\n    SQInt32 _varparams;\n\n    // Struct field order optimized for 64-bit platform memory alignment\n    // General principle: Group pointers (8-byte) together, then two integers (4-byte),\n    // to minimize padding and cache misses\n\n    SQInt32 _nlineinfos;\n    SQLineInfosHeader *_lineinfos;\n\n    SQObjectPtr* _staticmemos;\n    SQInt32 _nstaticmemos;\n\n    SQInt32 _nlocalvarinfos;\n    SQLocalVarInfo *_localvarinfos;\n\n    SQObjectPtr *_literals;\n    SQInt32 _nliterals;\n\n    SQInt32 _nfunctions;\n    SQObjectPtr *_functions;\n\n    SQObjectPtr* _parameters;\n    SQInt32 _nparameters;\n\n    SQInt32 _noutervalues;\n    SQOuterVar *_outervalues;\n\n    SQUnsignedInteger32* _param_type_masks;\n\n    SQInt32* _defaultparams;\n    SQInt32 _ndefaultparams;\n\n    SQInt32 _ninstructions;\n    alignas(8) SQInstruction _instructions[1];\n};\n\nvoid Dump(SQFunctionProto *func, int instruction_index = -1);\nvoid Dump(OutputStream *stream, SQFunctionProto *func, bool deep = false, int instruction_index = -1);\n\nvoid ResetStaticMemos(SQFunctionProto *func, SQSharedState *ss);\n\n#endif //_SQFUNCTION_H_\n"
  },
  {
    "path": "squirrel/sqmem.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#ifndef SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS\n\nvoid sq_vm_init_alloc_context(SQAllocContext *) {}\nvoid sq_vm_destroy_alloc_context(SQAllocContext *) {}\nvoid sq_vm_assign_to_alloc_context(SQAllocContext, HSQUIRRELVM) {}\n\nvoid *sq_vm_malloc(SQAllocContext SQ_UNUSED_ARG(ctx), SQUnsignedInteger size) {\n    return malloc(size);\n}\n\nvoid *sq_vm_realloc(SQAllocContext SQ_UNUSED_ARG(ctx), void *p, SQUnsignedInteger SQ_UNUSED_ARG(oldsize), SQUnsignedInteger size) {\n    return realloc(p, size);\n}\n\nvoid sq_vm_free(SQAllocContext SQ_UNUSED_ARG(ctx), void *p, SQUnsignedInteger SQ_UNUSED_ARG(size)) {\n    free(p);\n}\n#endif\n"
  },
  {
    "path": "squirrel/sqobject.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqstring.h\"\n#include \"sqarray.h\"\n#include \"sqtable.h\"\n#include \"squserdata.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclass.h\"\n#include \"sqclosure.h\"\n\n\nconst char *IdType2Name(SQObjectType type)\n{\n    switch(_RAW_TYPE(type))\n    {\n    case OT_NULL: // fallthrough\n    case _RT_NULL:return \"null\";\n    case _RT_INTEGER:return \"integer\";\n    case _RT_FLOAT:return \"float\";\n    case _RT_BOOL:return \"bool\";\n    case _RT_STRING:return \"string\";\n    case _RT_TABLE:return \"table\";\n    case _RT_ARRAY:return \"array\";\n    case _RT_GENERATOR:return \"generator\";\n    case _RT_CLOSURE:\n    case _RT_NATIVECLOSURE:\n        return \"function\";\n    case _RT_USERDATA:\n    case _RT_USERPOINTER:\n        return \"userdata\";\n    case _RT_THREAD: return \"thread\";\n    case _RT_FUNCPROTO: return \"function\";\n    case _RT_CLASS: return \"class\";\n    case _RT_INSTANCE: return \"instance\";\n    case _RT_WEAKREF: return \"weakref\";\n    case _RT_OUTER: return \"outer\";\n    default:\n        return NULL;\n    }\n}\n\nconst char *GetTypeName(const SQObject &obj1)\n{\n    return IdType2Name(sq_type(obj1));\n}\n\nSQObjectPtr::SQObjectPtr(SQVM *vm, const char *str, SQInteger len)\n    : SQObjectPtr(SQString::Create(vm->_sharedstate, str, len))\n{\n}\n\nSQString *SQString::Create(SQSharedState *ss,const char *s,SQInteger len)\n{\n    SQString *str=ADD_STRING(ss,s,len);\n    return str;\n}\n\nvoid SQString::Release()\n{\n    REMOVE_STRING(_sharedstate,this);\n}\n\nSQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)\n{\n    SQInteger idx = (SQInteger)TranslateIndex(refpos);\n    if (idx < _len) {\n        outkey = (SQInteger)idx;\n        outval = (SQInteger)((SQUnsignedInteger)_val[idx]);\n        //return idx for the next iteration\n        return ++idx;\n    }\n    //nothing to iterate anymore\n    return -1;\n}\n\nSQWeakRef *SQRefCounted::GetWeakRef(SQAllocContext alloc_ctx, SQObjectType type, SQObjectFlags flags)\n{\n    if(!_weakref) {\n        sq_new(alloc_ctx, _weakref, SQWeakRef);\n        _weakref->_alloc_ctx = alloc_ctx;\n        _weakref->_obj._unVal.raw = 0;\n        _weakref->_obj._type = type;\n        _weakref->_obj._flags = flags;\n        _weakref->_obj._unVal.pRefCounted = this;\n    }\n    return _weakref;\n}\n\nSQRefCounted::~SQRefCounted()\n{\n    if(_weakref) {\n        _weakref->_obj._type = OT_NULL;\n        _weakref->_obj._unVal.raw = 0;\n    }\n}\n\nvoid SQWeakRef::Release() {\n    if(ISREFCOUNTED(_obj._type)) {\n        _obj._unVal.pRefCounted->_weakref = NULL;\n    }\n    sq_delete(_alloc_ctx, this, SQWeakRef);\n}\n\nbool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {\n    if(_delegate) {\n        return _delegate->Get((*_ss(v)->_metamethodnames)[mm],res);\n    }\n    return false;\n}\n\nbool SQDelegable::SetDelegate(SQTable *mt)\n{\n    SQTable *temp = mt;\n    if(temp == this) return false;\n    while (temp) {\n        if (temp->_delegate == this) return false; //cycle detected\n        temp = temp->_delegate;\n    }\n    if (mt) __ObjAddRef(mt);\n    __ObjRelease(_delegate);\n    _delegate = mt;\n    return true;\n}\n\nbool SQGenerator::Yield(SQVM *v,SQInteger target)\n{\n    if(_state==eSuspended) { v->Raise_Error(\"internal vm error, yielding dead generator\");  return false;}\n    if(_state==eDead) { v->Raise_Error(\"internal vm error, yielding a dead generator\"); return false; }\n    SQInteger size = v->_top-v->_stackbase;\n\n    _stack.resize(size);\n    SQObject _this = v->_stack[v->_stackbase];\n    _stack._vals[0] = ISREFCOUNTED(sq_type(_this))\n        ? SQObjectPtr(_refcounted(_this)->GetWeakRef(_ss(v)->_alloc_ctx, sq_type(_this), _this._flags))\n        : _this;\n\n    for(SQInteger n =1; n<target; n++) {\n        _stack._vals[n] = v->_stack[v->_stackbase+n];\n    }\n    for(SQInteger j =0; j < size; j++)\n    {\n        v->_stack[v->_stackbase+j].Null();\n    }\n\n    _ci = *v->ci;\n    _ci._generator=NULL;\n    for(SQInteger i=0;i<_ci._etraps;i++) {\n        _etraps.push_back(v->_etraps.top());\n        v->_etraps.pop_back();\n        // store relative stack base and size in case of resume to other _top\n        SQExceptionTrap &et = _etraps.back();\n        et._stackbase -= v->_stackbase;\n        et._stacksize -= v->_stackbase;\n    }\n    _state=eSuspended;\n    return true;\n}\n\nbool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)\n{\n    if(_state==eDead){ v->Raise_Error(\"resuming dead generator\"); return false; }\n    if(_state==eRunning){ v->Raise_Error(\"resuming active generator\"); return false; }\n    SQInteger size = _stack.size();\n    SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]);\n    assert(target>=0 && target<=255);\n    SQInteger newbase = v->_top;\n    if(!v->EnterFrame(v->_top, v->_top + size, false))\n        return false;\n    v->ci->_generator   = this;\n    v->ci->_target      = (SQInt32)target;\n    v->ci->_closure     = _ci._closure;\n    v->ci->_ip          = _ci._ip;\n    v->ci->_literals    = _ci._literals;\n    v->ci->_ncalls      = _ci._ncalls;\n    v->ci->_etraps      = _ci._etraps;\n    v->ci->_root        = _ci._root;\n\n\n    for(SQInteger i=0;i<_ci._etraps;i++) {\n        v->_etraps.push_back(_etraps.top());\n        _etraps.pop_back();\n        SQExceptionTrap &et = v->_etraps.back();\n        // restore absolute stack base and size\n        et._stackbase += newbase;\n        et._stacksize += newbase;\n    }\n    SQObject _this = _stack._vals[0];\n    v->_stack[v->_stackbase] = sq_type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this;\n\n    for(SQInteger n = 1; n<size; n++) {\n        v->_stack[v->_stackbase+n] = _stack._vals[n];\n        _stack._vals[n].Null();\n    }\n\n    _state=eRunning;\n    if (v->_debughook)\n        v->CallDebugHook('c');\n\n    return true;\n}\n\nvoid SQArray::Extend(const SQArray *a){\n    SQInteger xlen;\n    if((xlen=a->Size()))\n        for(SQInteger i=0;i<xlen;i++)\n            Append(a->_values[i]);\n}\n\nbool SQArray::IsBinaryEqual(const SQArray *o)\n{\n    if (this == o)\n        return true;\n    if (_values.size() != o->_values.size())\n        return false;\n    if (_values.size() == 0)\n        return true;\n\n    return memcmp(_values._vals, o->_values._vals, _values.size() * sizeof(SQObjectPtr)) == 0;\n}\n\nconst char* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop)\n{\n    SQUnsignedInteger nvars=_nlocalvarinfos;\n    const char *res=NULL;\n    if(nvars>=nseq){\n        for(SQUnsignedInteger i=0;i<nvars;i++){\n            if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop)\n            {\n                if(nseq==0){\n                    vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]);\n                    res=_stringval(_localvarinfos[i]._name);\n                    break;\n                }\n                nseq--;\n            }\n        }\n    }\n    return res;\n}\n\n\ntemplate <typename T>\ninline SQInteger get_line_offset_impl(T* lineinfos, int nlineinfos, int instruction_index, int* hint, bool* is_dbg_step_point)\n{\n    int pos = nlineinfos - 1;\n    int low = 0;\n    int high = nlineinfos - 1;\n    int tryCount = 20;\n\n    if (hint && unsigned(*hint) < unsigned(high)) {\n        int h = *hint;\n        if (instruction_index >= (int)lineinfos[h]._op && instruction_index < (int)lineinfos[h + 1]._op) {\n            if (is_dbg_step_point)\n                *is_dbg_step_point = lineinfos[h]._is_dbg_step_point;\n            return lineinfos[h]._line_offset;\n        }\n        else if (instruction_index >= (int)lineinfos[h + 1]._op && instruction_index < (int)lineinfos[h + 2]._op) {\n            h++;\n            *hint = h;\n            if (is_dbg_step_point)\n                *is_dbg_step_point = lineinfos[h]._is_dbg_step_point;\n            return lineinfos[h]._line_offset;\n        }\n        else if (instruction_index == 0) {\n            for (int i = 0; i < nlineinfos - 1; i++)\n                if (instruction_index >= (int)lineinfos[i]._op && instruction_index < (int)lineinfos[i + 1]._op) {\n                    *hint = i;\n                    if (is_dbg_step_point)\n                        *is_dbg_step_point = lineinfos[i]._is_dbg_step_point;\n                    return lineinfos[i]._line_offset;\n                }\n        }\n    }\n\n    while (high >= low && --tryCount) {\n        int mid = (high + low) / 2;\n\n        if (instruction_index < (int)lineinfos[mid]._op)\n            high = mid - 1;\n        else if (instruction_index >= (int)lineinfos[mid + 1]._op)\n            low = mid + 1;\n        else {\n            pos = mid;\n            break;\n        }\n    }\n\n    if (tryCount == 0) {\n        // TODO: failsafe pass, to be reomved later\n        assert(0);\n        for (int i = 0; i < nlineinfos - 1; i++)\n            if (instruction_index >= (int)lineinfos[i]._op && instruction_index < (int)lineinfos[i + 1]._op) {\n                pos = i;\n                break;\n            }\n    }\n\n    if (is_dbg_step_point)\n        *is_dbg_step_point = lineinfos[pos]._is_dbg_step_point;\n\n    if (hint)\n        *hint = pos;\n\n    return lineinfos[pos]._line_offset;\n}\n\n\nSQInteger SQFunctionProto::GetLine(SQLineInfosHeader* lineinfos, int nlineinfos, int instruction_index, int* hint, bool* is_dbg_step_point)\n{\n    if (lineinfos->_is_compressed)\n        return get_line_offset_impl((SQCompressedLineInfo *)(void *)(lineinfos + 1), nlineinfos, instruction_index, hint, is_dbg_step_point) + lineinfos->_first_line;\n    else\n        return get_line_offset_impl((SQFullLineInfo *)(void *)(lineinfos + 1), nlineinfos, instruction_index, hint, is_dbg_step_point) + lineinfos->_first_line;\n}\n\n\nSQInteger SQFunctionProto::GetLine(const SQInstruction *curr, int *hint, bool *is_dbg_step_point)\n{\n    return GetLine(_lineinfos, _nlineinfos, int(curr - _instructions), hint, is_dbg_step_point);\n}\n\n\nSQClosure::~SQClosure()\n{\n    __ObjRelease(_env);\n    __ObjRelease(_base);\n    REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\n#define _CHECK_IO(exp)  { if(!exp)return false; }\nstatic bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size)\n{\n    if(write(up,dest,size) != size) {\n        v->Raise_Error(\"io error (write function failure)\");\n        return false;\n    }\n    return true;\n}\n\nstatic bool SafeRead(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size)\n{\n    if(size && read(up,dest,size) != size) {\n        v->Raise_Error(\"io error, read function failure, the origin stream could be corrupted/trucated\");\n        return false;\n    }\n    return true;\n}\n\nstatic bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger32 tag)\n{\n    return SafeWrite(v,write,up,&tag,sizeof(tag));\n}\n\nstatic bool CheckTag(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUnsignedInteger32 tag)\n{\n    SQUnsignedInteger32 t;\n    _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t)));\n    if(t != tag){\n        v->Raise_Error(\"invalid or corrupted closure stream\");\n        return false;\n    }\n    return true;\n}\n\nstatic bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o)\n{\n    SQUnsignedInteger32 _type = (SQUnsignedInteger32)sq_type(o);\n    _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type)));\n    switch(sq_type(o)){\n    case OT_STRING:\n        _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));\n        _CHECK_IO(SafeWrite(v,write,up,_stringval(o),_string(o)->_len));\n        break;\n    case OT_BOOL:\n    case OT_INTEGER:\n        _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break;\n    case OT_FLOAT:\n        _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break;\n    case OT_NULL:\n        break;\n    default:\n        v->Raise_Error(\"cannot serialize a %s\",GetTypeName(o));\n        return false;\n    }\n    return true;\n}\n\nstatic bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)\n{\n    SQUnsignedInteger32 _type;\n    _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type)));\n    SQObjectType t = (SQObjectType)_type;\n    switch(t){\n    case OT_STRING:{\n        SQInteger len;\n        _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));\n        _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(len),len));\n        o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);\n                   }\n        break;\n    case OT_INTEGER:{\n        SQInteger i;\n        _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break;\n                    }\n    case OT_BOOL:{\n        SQInteger i;\n        _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o._type = OT_BOOL; o._unVal.nInteger = i; break;\n                    }\n    case OT_FLOAT:{\n        SQFloat f;\n        _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break;\n                  }\n    case OT_NULL:\n        o.Null();\n        break;\n    default:\n        v->Raise_Error(\"cannot serialize a %s\",IdType2Name(t));\n        return false;\n    }\n    return true;\n}\n\nbool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)\n{\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD));\n    _CHECK_IO(WriteTag(v,write,up,sizeof(char)));\n    _CHECK_IO(WriteTag(v,write,up,sizeof(SQInteger)));\n    _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat)));\n    _CHECK_IO(_function->Save(v,up,write));\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL));\n    return true;\n}\n\nbool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)\n{\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD));\n    _CHECK_IO(CheckTag(v,read,up,sizeof(char)));\n    _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger)));\n    _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat)));\n    SQObjectPtr func;\n    _CHECK_IO(SQFunctionProto::Load(v,up,read,func));\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL));\n    ret = SQClosure::Create(_ss(v),_funcproto(func));\n    return true;\n}\n\nSQFunctionProto::SQFunctionProto(SQSharedState *ss)\n{\n    _stacksize=0;\n    _bgenerator=false;\n    _purefunction=false;\n    _nodiscard=false;\n    _inside_hoisted_scope=false;\n    INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nSQFunctionProto::~SQFunctionProto()\n{\n    REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nbool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)\n{\n    SQInteger i,nliterals = _nliterals,nparameters = _nparameters;\n    SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos;\n    SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions;\n    SQInteger ndefaultparams = _ndefaultparams;\n    SQInteger nstaticmemos = _nstaticmemos;\n    bool compressedLineInfos = _lineinfos->_is_compressed;\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(WriteObject(v,up,write,_sourcename));\n    _CHECK_IO(WriteObject(v,up,write,_name));\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up, &lang_features, sizeof(lang_features)));\n    _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals)));\n    _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters)));\n    _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues)));\n    _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos)));\n    _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos)));\n    _CHECK_IO(SafeWrite(v,write,up,&compressedLineInfos,sizeof(compressedLineInfos)));\n    _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams)));\n    _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions)));\n    _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions)));\n    _CHECK_IO(SafeWrite(v,write,up,&nstaticmemos,sizeof(nstaticmemos)));\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nliterals;i++){\n        _CHECK_IO(WriteObject(v,up,write,_literals[i]));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nparameters;i++){\n        _CHECK_IO(WriteObject(v,up,write,_parameters[i]));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<noutervalues;i++){\n        _CHECK_IO(SafeWrite(v,write,up,&_outervalues[i]._type,sizeof(SQUnsignedInteger)));\n        _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._src));\n        _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._name));\n        SQInteger varFlags = _outervalues[i]._varFlags;\n        _CHECK_IO(SafeWrite(v,write,up,&varFlags,sizeof(SQInteger)));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nlocalvarinfos;i++){\n        SQLocalVarInfo &lvi=_localvarinfos[i];\n        _CHECK_IO(WriteObject(v,up,write,lvi._name));\n        _CHECK_IO(SafeWrite(v,write,up,&lvi._pos,sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeWrite(v,write,up,&lvi._start_op,sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeWrite(v,write,up,&lvi._end_op,sizeof(SQUnsignedInteger)));\n    }\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    size_t lineinfosSize = (char *)_defaultparams - (char *)_lineinfos;\n    _CHECK_IO(SafeWrite(v,write,up,_lineinfos,lineinfosSize));\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up,_defaultparams,sizeof(SQInteger)*ndefaultparams));\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeWrite(v,write,up,_instructions,sizeof(SQInstruction)*ninstructions));\n\n    _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));\n    for(i=0;i<nfunctions;i++){\n        _CHECK_IO(_funcproto(_functions[i])->Save(v,up,write));\n    }\n    _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize)));\n    _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator)));\n    _CHECK_IO(SafeWrite(v,write,up,&_purefunction,sizeof(_purefunction)));\n    _CHECK_IO(SafeWrite(v,write,up,&_nodiscard,sizeof(_nodiscard)));\n    _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams)));\n    return true;\n}\n\nbool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)\n{\n    SQInteger i, nliterals,nparameters;\n    SQUnsignedInteger langFeatures;\n    SQInteger noutervalues ,nlocalvarinfos ;\n    SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ;\n    SQInteger nstaticmemos;\n    SQObjectPtr sourcename, name;\n    SQObjectPtr o;\n    bool compressedLineInfos = false;\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(ReadObject(v, up, read, sourcename));\n    _CHECK_IO(ReadObject(v, up, read, name));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, &langFeatures, sizeof(langFeatures)));\n    _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals)));\n    _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters)));\n    _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues)));\n    _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos)));\n    _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos)));\n    _CHECK_IO(SafeRead(v,read,up, &compressedLineInfos, sizeof(compressedLineInfos)));\n    _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams)));\n    _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions)));\n    _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions)));\n    _CHECK_IO(SafeRead(v,read,up, &nstaticmemos, sizeof(nfunctions)));\n\n    SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v), langFeatures,\n            ninstructions,nliterals,nparameters,\n            nfunctions,noutervalues,nlineinfos,compressedLineInfos,\n            nlocalvarinfos,ndefaultparams,nstaticmemos);\n    SQObjectPtr proto(f); //gets a ref in case of failure\n    f->_sourcename = sourcename;\n    f->_name = name;\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0;i < nliterals; i++){\n        _CHECK_IO(ReadObject(v, up, read, o));\n        f->_literals[i] = o;\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0; i < nparameters; i++){\n        _CHECK_IO(ReadObject(v, up, read, o));\n        f->_parameters[i] = o;\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0; i < noutervalues; i++){\n        SQUnsignedInteger type;\n        SQObjectPtr name;\n        SQInteger varFlags;\n        _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger)));\n        _CHECK_IO(ReadObject(v, up, read, o));\n        _CHECK_IO(ReadObject(v, up, read, name));\n        _CHECK_IO(SafeRead(v, read, up, &varFlags, sizeof(SQInteger)));\n        f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type, varFlags);\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n\n    for(i = 0; i < nlocalvarinfos; i++){\n        SQLocalVarInfo lvi;\n        _CHECK_IO(ReadObject(v, up, read, lvi._name));\n        _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger)));\n        _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger)));\n        f->_localvarinfos[i] = lvi;\n    }\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    size_t lineinfosSize = (char *)f->_defaultparams - (char *)f->_lineinfos;\n    _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, lineinfosSize));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions));\n\n    _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));\n    for(i = 0; i < nfunctions; i++){\n        _CHECK_IO(_funcproto(o)->Load(v, up, read, o));\n        f->_functions[i] = o;\n    }\n    _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize)));\n    _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator)));\n    _CHECK_IO(SafeRead(v,read,up, &f->_purefunction, sizeof(f->_purefunction)));\n    _CHECK_IO(SafeRead(v,read,up, &f->_nodiscard, sizeof(f->_nodiscard)));\n    _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams)));\n\n    ret = f;\n    return true;\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\n\n#define START_MARK()    if(!(_uiRef&MARK_FLAG)){ \\\n        _uiRef|=MARK_FLAG;\n\n#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \\\n        AddToChain(chain, this); }\n\nvoid SQVM::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        SQSharedState::MarkObject(_lasterror,chain);\n        SQSharedState::MarkObject(_errorhandler,chain);\n        SQSharedState::MarkObject(_debughook_closure,chain);\n        SQSharedState::MarkObject(_roottable, chain);\n        SQSharedState::MarkObject(temp_reg, chain);\n        for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);\n        for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain);\n    END_MARK()\n}\n\nvoid SQArray::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        SQInteger len = _values.size();\n        for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain);\n    END_MARK()\n}\nvoid SQTable::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        if(_delegate) _delegate->Mark(chain);\n        SQInteger len = _numofnodes_minus_one;\n        for(SQInteger i = 0; i <= len; i++){\n            SQSharedState::MarkObject(_nodes[i].key, chain);\n            SQSharedState::MarkObject(_nodes[i].val, chain);\n        }\n    END_MARK()\n}\n\nvoid SQClass::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        _members->Mark(chain);\n        if(_base) _base->Mark(chain);\n        for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) {\n            SQSharedState::MarkObject(_defaultvalues[i].val, chain);\n        }\n        for(SQUnsignedInteger j =0; j< _methods.size(); j++) {\n            SQSharedState::MarkObject(_methods[j].val, chain);\n        }\n        for(SQUnsignedInteger k =0; k< MT_NUM_METHODS; k++) {\n            SQSharedState::MarkObject(_metamethods[k], chain);\n        }\n    END_MARK()\n}\n\nvoid SQInstance::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        _class->Mark(chain);\n        SQUnsignedInteger nvalues = _class->_defaultvalues.size();\n        for(SQUnsignedInteger i =0; i< nvalues; i++) {\n            SQSharedState::MarkObject(_values[i], chain);\n        }\n    END_MARK()\n}\n\nvoid SQGenerator::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);\n        SQSharedState::MarkObject(_closure, chain);\n    END_MARK()\n}\n\nvoid SQFunctionProto::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain);\n        for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain);\n    END_MARK()\n}\n\nvoid SQClosure::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        if(_base) _base->Mark(chain);\n        SQFunctionProto *fp = _function;\n        fp->Mark(chain);\n        for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);\n        for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain);\n        for(SQInteger j = 0; j < fp->_nstaticmemos; j++) SQSharedState::MarkObject(fp->_staticmemos[j], chain);\n    END_MARK()\n}\n\nvoid SQNativeClosure::Mark(SQCollectable **chain)\n{\n    START_MARK()\n        for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);\n    END_MARK()\n}\n\nvoid SQOuter::Mark(SQCollectable **chain)\n{\n    START_MARK()\n    /* If the valptr points to a closed value, that value is alive */\n    if(_valptr == &_value) {\n      SQSharedState::MarkObject(_value, chain);\n    }\n    END_MARK()\n}\n\nvoid SQUserData::Mark(SQCollectable **chain){\n    START_MARK()\n        if(_delegate) _delegate->Mark(chain);\n    END_MARK()\n}\n\nvoid SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; }\n\n#endif\n\n"
  },
  {
    "path": "squirrel/sqobject.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQOBJECT_H_\n#define _SQOBJECT_H_\n\n#include \"squtils.h\"\n\n#define UINT32_MINUS_ONE (0xFFFFFFFF)\n\n#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R'))\n#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T'))\n#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L'))\n\nstruct SQSharedState;\n\n#define METAMETHODS_LIST \\\n    MM_IMPL(MT_ADD      ,\"_add\")\\\n    MM_IMPL(MT_SUB      ,\"_sub\")\\\n    MM_IMPL(MT_MUL      ,\"_mul\")\\\n    MM_IMPL(MT_DIV      ,\"_div\")\\\n    MM_IMPL(MT_UNM      ,\"_unm\")\\\n    MM_IMPL(MT_MODULO   ,\"_modulo\")\\\n    MM_IMPL(MT_SET      ,\"_set\")\\\n    MM_IMPL(MT_GET      ,\"_get\")\\\n    MM_IMPL(MT_TYPEOF   ,\"_typeof\")\\\n    MM_IMPL(MT_NEXTI    ,\"_nexti\")\\\n    MM_IMPL(MT_CMP      ,\"_cmp\")\\\n    MM_IMPL(MT_CALL     ,\"_call\")\\\n    MM_IMPL(MT_CLONED   ,\"_cloned\")\\\n    MM_IMPL(MT_NEWSLOT  ,\"_newslot\")\\\n    MM_IMPL(MT_DELSLOT  ,\"_delslot\")\\\n    MM_IMPL(MT_TOSTRING ,\"_tostring\")\\\n    MM_IMPL(MT_LOCK     ,\"_lock\")\\\n\n\n#define MM_IMPL(mm, name) mm,\n\nenum SQMetaMethod{\n    METAMETHODS_LIST\n    MT_NUM_METHODS\n};\n\n#undef MM_IMPL\n\n\n#define _CONSTRUCT_VECTOR(type,size,ptr) { \\\n    for(SQInteger n = 0; n < ((SQInteger)size); n++) { \\\n            new (&ptr[n]) type(); \\\n        } \\\n}\n\n#define _DESTRUCT_VECTOR(type,size,ptr) { \\\n    for(SQInteger nl = 0; nl < ((SQInteger)size); nl++) { \\\n            ptr[nl].~type(); \\\n    } \\\n}\n\n#define _COPY_VECTOR(dest,src,size) { \\\n    for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \\\n        dest[_n_] = src[_n_]; \\\n    } \\\n}\n\n#define _NULL_SQOBJECT_VECTOR(vec,size) { \\\n    for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \\\n        vec[_n_].Null(); \\\n    } \\\n}\n\n\nstruct SQRefCounted\n{\n    SQUnsignedInteger _uiRef;\n    struct SQWeakRef *_weakref;\n    SQRefCounted() { _uiRef = 0; _weakref = NULL; }\n    virtual ~SQRefCounted();\n    SQWeakRef *GetWeakRef(SQAllocContext alloc_ctx, SQObjectType type, SQObjectFlags flags);\n    virtual void Release()=0;\n\n};\n\nstruct SQWeakRef : SQRefCounted\n{\n    void Release();\n    SQObject _obj;\n    SQAllocContext _alloc_ctx;\n};\n\n#define _realval(o) (sq_type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj)\n\nstruct SQObjectPtr;\n\n#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \\\n        { \\\n            unval.pRefCounted->_uiRef++; \\\n        }\n\n#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)==0))  \\\n        {   \\\n            unval.pRefCounted->Release();   \\\n        }\n\n#define __ObjRelease(obj) { \\\n    if((obj)) { \\\n        (obj)->_uiRef--; \\\n        if((obj)->_uiRef == 0) \\\n            (obj)->Release(); \\\n        (obj) = NULL;   \\\n    } \\\n}\n\n#define __ObjAddRef(obj) { \\\n    (obj)->_uiRef++; \\\n}\n\n#define is_delegable(t) (sq_type(t)&SQOBJECT_DELEGABLE)\n#define raw_type(obj) _RAW_TYPE((obj)._type)\n\n#define _integer(obj) ((obj)._unVal.nInteger)\n#define _float(obj) ((obj)._unVal.fFloat)\n#define _string(obj) ((obj)._unVal.pString)\n#define _table(obj) ((obj)._unVal.pTable)\n#define _array(obj) ((obj)._unVal.pArray)\n#define _closure(obj) ((obj)._unVal.pClosure)\n#define _generator(obj) ((obj)._unVal.pGenerator)\n#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure)\n#define _userdata(obj) ((obj)._unVal.pUserData)\n#define _userpointer(obj) ((obj)._unVal.pUserPointer)\n#define _thread(obj) ((obj)._unVal.pThread)\n#define _funcproto(obj) ((obj)._unVal.pFunctionProto)\n#define _class(obj) ((obj)._unVal.pClass)\n#define _instance(obj) ((obj)._unVal.pInstance)\n#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable)\n#define _weakref(obj) ((obj)._unVal.pWeakRef)\n#define _outer(obj) ((obj)._unVal.pOuter)\n#define _refcounted(obj) ((obj)._unVal.pRefCounted)\n#define _rawval(obj) ((obj)._unVal.raw)\n\n#define _stringval(obj) (obj)._unVal.pString->_val\n#define _userdataval(obj) ((SQUserPointer)sq_aligning((obj)._unVal.pUserData + 1))\n\n#define tofloat(num) ((sq_type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num))\n#define tointeger(num) ((sq_type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num))\n/////////////////////////////////////////////////////////////////////////////////////\n/////////////////////////////////////////////////////////////////////////////////////\n#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64)\n#define SQ_REFOBJECT_INIT() SQ_OBJECT_RAWINIT()\n#else\n#define SQ_REFOBJECT_INIT()\n#endif\n\n#define _REF_TYPE_DECL(type,_class,sym) \\\n    explicit SQObjectPtr(_class * __restrict x) \\\n    { \\\n        SQ_OBJECT_RAWINIT() \\\n        _type=type; \\\n        _flags=0; \\\n        _unVal.sym = x; \\\n        assert(_unVal.pTable); \\\n        _unVal.pRefCounted->_uiRef++; \\\n    } \\\n    inline SQObjectPtr& operator=(_class *__restrict x) \\\n    {  \\\n        SQObjectType  tOldType = _type; \\\n        SQObjectValue unOldVal = _unVal; \\\n        _type = type; \\\n        _flags = 0; \\\n        SQ_REFOBJECT_INIT() \\\n        _unVal.sym = x; \\\n        _unVal.pRefCounted->_uiRef++; \\\n        __Release(tOldType,unOldVal); \\\n        return *this; \\\n    }\n\n#define _SCALAR_TYPE_DECL(type,_class,sym) \\\n    explicit SQObjectPtr(_class x) \\\n    { \\\n        SQ_OBJECT_RAWINIT() \\\n        _type=type; \\\n        _flags = 0; \\\n        _unVal.sym = x; \\\n    } \\\n    inline SQObjectPtr& operator=(_class x) \\\n    {  \\\n        __Release(_type,_unVal); \\\n        _type = type; \\\n        _flags = 0; \\\n        SQ_OBJECT_RAWINIT() \\\n        _unVal.sym = x; \\\n        return *this; \\\n    }\nstruct SQObjectPtr : public SQObject\n{\n    SQObjectPtr() noexcept\n    {\n        memset(this, 0, sizeof(SQObjectPtr)); // OT_NULL == 0\n    }\n    SQObjectPtr(const SQObjectPtr &__restrict o)\n    {\n        memcpy(this, &o, sizeof(o));\n        __AddRef(_type,_unVal);\n    }\n    SQObjectPtr(SQObjectPtr &&__restrict o) noexcept\n    {\n        memcpy(this, &o, sizeof(o));\n        memset(&o, 0, sizeof(SQObjectPtr)); // OT_NULL == 0\n    }\n    explicit SQObjectPtr(const SQObject &__restrict o)\n    {\n        memcpy(this, &o, sizeof(o));\n        __AddRef(_type,_unVal);\n    }\n    _REF_TYPE_DECL(OT_TABLE,SQTable,pTable)\n    _REF_TYPE_DECL(OT_CLASS,SQClass,pClass)\n    _REF_TYPE_DECL(OT_INSTANCE,SQInstance,pInstance)\n    _REF_TYPE_DECL(OT_ARRAY,SQArray,pArray)\n    _REF_TYPE_DECL(OT_CLOSURE,SQClosure,pClosure)\n    _REF_TYPE_DECL(OT_NATIVECLOSURE,SQNativeClosure,pNativeClosure)\n    _REF_TYPE_DECL(OT_OUTER,SQOuter,pOuter)\n    _REF_TYPE_DECL(OT_GENERATOR,SQGenerator,pGenerator)\n    _REF_TYPE_DECL(OT_STRING,SQString,pString)\n    _REF_TYPE_DECL(OT_USERDATA,SQUserData,pUserData)\n    _REF_TYPE_DECL(OT_WEAKREF,SQWeakRef,pWeakRef)\n    _REF_TYPE_DECL(OT_THREAD,SQVM,pThread)\n    _REF_TYPE_DECL(OT_FUNCPROTO,SQFunctionProto,pFunctionProto)\n\n    _SCALAR_TYPE_DECL(OT_INTEGER,SQInteger,nInteger)\n#ifdef _SQ64\n    _SCALAR_TYPE_DECL(OT_INTEGER,SQInt32,nInteger)\n#endif\n    _SCALAR_TYPE_DECL(OT_FLOAT,SQFloat,fFloat)\n    _SCALAR_TYPE_DECL(OT_USERPOINTER,SQUserPointer,pUserPointer)\n\n    SQObjectPtr(SQVM *vm, const char *str, SQInteger len = -1);\n\n    explicit SQObjectPtr(bool bBool)\n    {\n        memset(this, 0, sizeof(SQObjectPtr));\n        _type = OT_BOOL;\n        if (bBool)\n            _unVal.nInteger = 1;\n    }\n    inline SQObjectPtr& operator=(bool b)\n    {\n        __Release(_type,_unVal);\n        SQ_OBJECT_RAWINIT()\n        _type = OT_BOOL;\n        _flags = 0;\n        _unVal.nInteger = b?1:0;\n        return *this;\n    }\n\n    ~SQObjectPtr()\n    {\n        __Release(_type,_unVal);\n    }\n\n    inline SQObjectPtr& operator=(const SQObjectPtr& __restrict obj)\n    {\n        SQObjectType  tOldType = _type;\n        SQObjectValue unOldVal =_unVal;\n        memcpy(this, &obj, sizeof(SQObjectPtr));\n        __AddRef(_type,_unVal);\n        __Release(tOldType,unOldVal);\n        return *this;\n    }\n    inline SQObjectPtr& operator=(const SQObject& __restrict obj)\n    {\n        SQObjectType  tOldType = _type;\n        SQObjectValue unOldVal =_unVal;\n        memcpy(this, &obj, sizeof(SQObject));\n        __AddRef(_type,_unVal);\n        __Release(tOldType,unOldVal);\n        return *this;\n    }\n    inline SQObjectPtr& operator=(SQObjectPtr&& __restrict obj) noexcept\n    {\n        if (this != &obj) {\n            __Release(_type, _unVal);\n            memcpy(this, &obj, sizeof(SQObjectPtr));\n            memset(&obj, 0, sizeof(SQObjectPtr));  // OT_NULL == 0\n        }\n        return *this;\n    }\n    inline void Null()\n    {\n        SQObjectType  tOldType = _type;\n        SQObjectValue unOldVal = _unVal;\n        memset(this,0, sizeof(SQObjectPtr));\n        _type = OT_NULL;\n        __Release(tOldType ,unOldVal);\n    }\n    private:\n        SQObjectPtr(const char *){} //safety\n};\n\n\ninline void _Swap(SQObject &a,SQObject &b)\n{\n    SQObject t = a;\n    a = b;\n    b = t;\n}\n\n/////////////////////////////////////////////////////////////////////////////////////\n#ifndef NO_GARBAGE_COLLECTOR\n#define MARK_FLAG 0x80000000\nstruct SQCollectable : public SQRefCounted {\n    SQCollectable *_gc_next;\n    SQCollectable *_gc_prev;\n    SQSharedState *_sharedstate;\n    virtual SQObjectType GetType()=0;\n    virtual void Release()=0;\n    virtual void Mark(SQCollectable **chain)=0;\n    void UnMark();\n    virtual void Finalize()=0;\n    static void AddToChain(SQCollectable **chain,SQCollectable *c);\n    static void RemoveFromChain(SQCollectable **chain,SQCollectable *c);\n};\n\n\n#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj)\n#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);}\n#define CHAINABLE_OBJ SQCollectable\n#define INIT_CHAIN() {_gc_next=NULL;_gc_prev=NULL;_sharedstate=ss;}\n#else\n\n// Need this to keep SQSharedState pointer to access alloc_ctx\n// Otherwise, just use SQRefCounted as CHAINABLE_OBJ in the way it was initially\nstruct SQRefCountedWithSharedState : public SQRefCounted\n{\n    SQSharedState *_sharedstate;\n};\n#define ADD_TO_CHAIN(chain,obj) ((void)0)\n#define REMOVE_FROM_CHAIN(chain,obj) ((void)0)\n#define CHAINABLE_OBJ SQRefCountedWithSharedState\n#define INIT_CHAIN() {_sharedstate=ss;}\n\n#endif\n\nstruct SQDelegable : public CHAINABLE_OBJ {\n    bool SetDelegate(SQTable *m);\n    virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);\n    SQTable *_delegate;\n};\n\ninline SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)\n{\n    switch(sq_type(idx)){\n        case OT_NULL:\n            return 0;\n        case OT_INTEGER:\n            return (SQUnsignedInteger)_integer(idx);\n        default: assert(0); break;\n    }\n    return 0;\n}\n\ntypedef sqvector<SQObjectPtr> SQObjectPtrVec;\ntypedef sqvector<SQInteger> SQIntVec;\nconst char *GetTypeName(const SQObject &obj1);\nconst char *IdType2Name(SQObjectType type);\n\n\n\n#endif //_SQOBJECT_H_\n"
  },
  {
    "path": "squirrel/sqpcheader.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQPCHEADER_H_\n#define _SQPCHEADER_H_\n\n#if defined(_MSC_VER) && defined(_DEBUG)\n#include <crtdbg.h>\n#endif\n\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n#ifdef QUIRREL_HOST_HEADER\n#define _SQ_QHH_STR(x) #x\n#define _SQ_QHH_STR2(x) _SQ_QHH_STR(x)\n#include _SQ_QHH_STR2(QUIRREL_HOST_HEADER)\n#undef _SQ_QHH_STR\n#undef _SQ_QHH_STR2\n#endif\n\n#include <new>\n//squirrel stuff\n#include <squirrel.h>\n#include \"sqobject.h\"\n#include \"sqstate.h\"\n\n#if defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L\n#include <charconv>\n#define SQ_USE_STD_FROM_CHARS 1\n#endif\n\n#ifndef SQ_RUNTIME_TYPE_CHECK\n#define SQ_RUNTIME_TYPE_CHECK 1\n#endif\n\n#ifndef SQ_WATCHDOG_ENABLED\n#define SQ_WATCHDOG_ENABLED 0\n#endif\n\n#endif //_SQPCHEADER_H_\n"
  },
  {
    "path": "squirrel/sqstate.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"opcodes.h\"\n#include \"sqvm.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"sqarray.h\"\n#include \"squserdata.h\"\n#include \"sqclass.h\"\n\nSQSharedState::SQSharedState(SQAllocContext allocctx) :\n    _alloc_ctx(allocctx),\n    _refs_table(allocctx),\n    defaultLangFeatures(LF_FORBID_DELETE_OP | LF_FORBID_SWITCH_STMT)\n{\n    _compilererrorhandler = NULL;\n    _compilerdiaghandler = NULL;\n    _printfunc = NULL;\n    _errorfunc = NULL;\n    _lineInfoInExpressions = false;\n    _varTraceEnabled = false;\n    _notifyallexceptions = false;\n    _foreignptr = NULL;\n    _releasehook = NULL;\n    compilationOptions = 0;\n    doc_object_index = 1;\n    rand_seed = 0;\n    watchdog_last_alive_time_msec = 0;\n    watchdog_threshold_msec = 0;\n}\n\n\nbool CompileTypemask(SQIntVec &res,const char *typemask)\n{\n    SQInteger i = 0;\n    SQInteger mask = 0;\n    while(typemask[i] != 0) {\n        switch(typemask[i]) {\n                case 'o': mask |= _RT_NULL; break;\n                case 'i': mask |= _RT_INTEGER; break;\n                case 'f': mask |= _RT_FLOAT; break;\n                case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;\n                case 's': mask |= _RT_STRING; break;\n                case 't': mask |= _RT_TABLE; break;\n                case 'a': mask |= _RT_ARRAY; break;\n                case 'u': mask |= _RT_USERDATA; break;\n                case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;\n                case 'b': mask |= _RT_BOOL; break;\n                case 'g': mask |= _RT_GENERATOR; break;\n                case 'p': mask |= _RT_USERPOINTER; break;\n                case 'v': mask |= _RT_THREAD; break;\n                case 'x': mask |= _RT_INSTANCE; break;\n                case 'y': mask |= _RT_CLASS; break;\n                case 'r': mask |= _RT_WEAKREF; break;\n                case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;\n                case ' ': i++; continue; //ignores spaces\n                default:\n                    return false;\n        }\n        i++;\n        if(typemask[i] == '|') {\n            i++;\n            if(typemask[i] == 0)\n                return false;\n            continue;\n        }\n        res.push_back(mask);\n        mask = 0;\n\n    }\n    return true;\n}\n\nstatic SQClass *CreateBuiltInTypeClass(SQSharedState *ss, const char *name, const SQRegFunction *funcz, SQObjectType type_id)\n{\n    SQClass *cls = (SQClass *)SQ_MALLOC(ss->_alloc_ctx, sizeof(SQClass));\n    new (cls) SQClass(ss, NULL);\n\n    cls->_is_builtin_type = true;\n    cls->_builtin_type_id = type_id;\n\n    if (funcz) {\n        SQInteger i = 0;\n        while (funcz[i].name != 0) {\n            SQNativeClosure *nc = SQNativeClosure::Create(ss, funcz[i].f, 0);\n            nc->_nparamscheck = funcz[i].nparamscheck;\n            nc->_name = SQString::Create(ss, funcz[i].name);\n            if (funcz[i].typemask && !CompileTypemask(nc->_typecheck, funcz[i].typemask))\n                return NULL;\n            if (funcz[i].pure)\n                nc->_purefunction = true;\n            if (funcz[i].nodiscard)\n                nc->_nodiscard = true;\n            if (funcz[i].docstring) {\n                SQObjectPtr docValue(SQString::Create(ss, funcz[i].docstring));\n                SQObjectPtr docKey;\n                docKey._type = OT_USERPOINTER;\n                docKey._unVal.pUserPointer = (void *)nc->_function;\n                _table(ss->doc_objects)->NewSlot(docKey, docValue);\n            }\n\n            cls->NewSlot(ss, SQObjectPtr(nc->_name), SQObjectPtr(nc), /*static*/ true);\n            i++;\n        }\n    }\n\n    // Lock manually\n    assert(cls->_lockedTypeId == 0);\n    cls->_lockedTypeId = cls->currentHint();\n\n    return cls;\n}\n\nvoid SQSharedState::Init()\n{\n    _scratchpad=NULL;\n    _scratchpadsize=0;\n#ifndef NO_GARBAGE_COLLECTOR\n    _gc_chain=NULL;\n#endif\n\n    _stringtable = (SQStringTable*)SQ_MALLOC(_alloc_ctx, sizeof(SQStringTable));\n    new (_stringtable) SQStringTable(this);\n    sq_new(_alloc_ctx, _metamethodnames, SQObjectPtrVec, _alloc_ctx);\n    sq_new(_alloc_ctx, _systemstrings, SQObjectPtrVec, _alloc_ctx);\n    sq_new(_alloc_ctx, _types, SQObjectPtrVec, _alloc_ctx);\n    _metamethodsmap = SQTable::Create(this,MT_NUM_METHODS);\n\n#define newsysstring(s) {   \\\n    _systemstrings->push_back(SQObjectPtr(SQString::Create(this,s)));    \\\n    }\n\n    //adding type strings to avoid memory trashing\n    //types names\n    newsysstring(\"null\");\n    newsysstring(\"table\");\n    newsysstring(\"array\");\n    newsysstring(\"closure\");\n    newsysstring(\"string\");\n    newsysstring(\"userdata\");\n    newsysstring(\"integer\");\n    newsysstring(\"float\");\n    newsysstring(\"userpointer\");\n    newsysstring(\"function\");\n    newsysstring(\"generator\");\n    newsysstring(\"thread\");\n    newsysstring(\"class\");\n    newsysstring(\"instance\");\n    newsysstring(\"bool\");\n#undef newsysstring\n\n    //meta methods\n#define MM_IMPL(mm, name) {  \\\n        _metamethodnames->push_back(SQObjectPtr(SQString::Create(this,name)));  \\\n        _table(_metamethodsmap)->NewSlot(_metamethodnames->back(), SQObjectPtr((SQInteger)(mm))); \\\n    }\n\n    METAMETHODS_LIST\n\n#undef MM_IMPL\n\n    _constructorstr = SQString::Create(this,\"constructor\");\n    _registry = SQTable::Create(this,0);\n    _consts = SQTable::Create(this,0);\n    doc_objects = SQTable::Create(this,0);\n\n    _null_class     = CreateBuiltInTypeClass(this, \"Null\", _null_default_type_methods_funcz, OT_NULL);\n    _integer_class  = CreateBuiltInTypeClass(this, \"Integer\", _integer_default_type_methods_funcz, OT_INTEGER);\n    _float_class    = CreateBuiltInTypeClass(this, \"Float\", _float_default_type_methods_funcz, OT_FLOAT);\n    _bool_class     = CreateBuiltInTypeClass(this, \"Bool\", _bool_default_type_methods_funcz, OT_BOOL);\n    _string_class   = CreateBuiltInTypeClass(this, \"String\", _string_default_type_methods_funcz, OT_STRING);\n    _array_class    = CreateBuiltInTypeClass(this, \"Array\", _array_default_type_methods_funcz, OT_ARRAY);\n    _table_class    = CreateBuiltInTypeClass(this, \"Table\", _table_default_type_methods_funcz, OT_TABLE);\n    _function_class = CreateBuiltInTypeClass(this, \"Function\", _closure_default_type_methods_funcz, OT_CLOSURE);\n    _generator_class= CreateBuiltInTypeClass(this, \"Generator\", _generator_default_type_methods_funcz, OT_GENERATOR);\n    _thread_class   = CreateBuiltInTypeClass(this, \"Thread\", _thread_default_type_methods_funcz, OT_THREAD);\n    _class_class    = CreateBuiltInTypeClass(this, \"Class\", _class_default_type_methods_funcz, OT_CLASS);\n    _instance_class = CreateBuiltInTypeClass(this, \"Instance\", _instance_default_type_methods_funcz, OT_INSTANCE);\n    _weakref_class  = CreateBuiltInTypeClass(this, \"WeakRef\", _weakref_default_type_methods_funcz, OT_WEAKREF);\n    _userdata_class = CreateBuiltInTypeClass(this, \"UserData\", _userdata_default_type_methods_funcz, OT_USERDATA);\n}\n\nSQSharedState::~SQSharedState()\n{\n    if(_releasehook) { _releasehook(_thread(_root_vm),_foreignptr,0); _releasehook = NULL; }\n    _constructorstr.Null();\n    _table(_registry)->Finalize();\n    _table(_consts)->Finalize();\n    _table(_metamethodsmap)->Finalize();\n    _table(doc_objects)->Finalize();\n    _registry.Null();\n    _consts.Null();\n    _metamethodsmap.Null();\n    doc_objects.Null();\n    while(!_systemstrings->empty()) {\n        _systemstrings->back().Null();\n        _systemstrings->pop_back();\n    }\n    _thread(_root_vm)->Finalize();\n    _root_vm.Null();\n\n    _null_class.Null();\n    _integer_class.Null();\n    _float_class.Null();\n    _bool_class.Null();\n    _string_class.Null();\n    _array_class.Null();\n    _table_class.Null();\n    _function_class.Null();\n    _generator_class.Null();\n    _thread_class.Null();\n    _class_class.Null();\n    _instance_class.Null();\n    _weakref_class.Null();\n    _userdata_class.Null();\n\n    _refs_table.Finalize();\n#ifndef NO_GARBAGE_COLLECTOR\n    SQCollectable *t = _gc_chain;\n    SQCollectable *nx = NULL;\n    if(t) {\n        t->_uiRef++;\n        while(t) {\n            t->Finalize();\n            nx = t->_gc_next;\n            if(nx) nx->_uiRef++;\n            if(--t->_uiRef == 0)\n                t->Release();\n            t = nx;\n        }\n    }\n    assert(_gc_chain==NULL); //just to proove a theory\n    while(_gc_chain){\n        _gc_chain->_uiRef++;\n        _gc_chain->Release();\n    }\n#endif\n\n    sq_delete(_alloc_ctx, _types, SQObjectPtrVec);\n    sq_delete(_alloc_ctx, _systemstrings, SQObjectPtrVec);\n    sq_delete(_alloc_ctx, _metamethodnames, SQObjectPtrVec);\n    sq_delete(_alloc_ctx, _stringtable,SQStringTable);\n    if(_scratchpad)SQ_FREE(_alloc_ctx,_scratchpad,_scratchpadsize);\n}\n\n\nSQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)\n{\n    if(sq_type(name) != OT_STRING)\n        return -1;\n    SQObjectPtr ret;\n    if(_table(_metamethodsmap)->Get(name,ret)) {\n        return _integer(ret);\n    }\n    return -1;\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\n\nvoid SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)\n{\n    switch(sq_type(o)){\n    case OT_TABLE:_table(o)->Mark(chain);break;\n    case OT_ARRAY:_array(o)->Mark(chain);break;\n    case OT_USERDATA:_userdata(o)->Mark(chain);break;\n    case OT_CLOSURE:_closure(o)->Mark(chain);break;\n    case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;\n    case OT_GENERATOR:_generator(o)->Mark(chain);break;\n    case OT_THREAD:_thread(o)->Mark(chain);break;\n    case OT_CLASS:_class(o)->Mark(chain);break;\n    case OT_INSTANCE:_instance(o)->Mark(chain);break;\n    case OT_OUTER:_outer(o)->Mark(chain);break;\n    case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;\n    default: break; //shutup compiler\n    }\n}\n\nvoid SQSharedState::RunMark(SQVM* SQ_UNUSED_ARG(vm),SQCollectable **tchain)\n{\n    SQVM *vms = _thread(_root_vm);\n\n    vms->Mark(tchain);\n\n    _refs_table.Mark(tchain);\n    MarkObject(_registry,tchain);\n    MarkObject(_consts,tchain);\n    MarkObject(_metamethodsmap,tchain);\n\n    MarkObject(_null_class,tchain);\n    MarkObject(_integer_class,tchain);\n    MarkObject(_float_class,tchain);\n    MarkObject(_bool_class,tchain);\n    MarkObject(_string_class,tchain);\n    MarkObject(_array_class,tchain);\n    MarkObject(_table_class,tchain);\n    MarkObject(_function_class,tchain);\n    MarkObject(_generator_class,tchain);\n    MarkObject(_thread_class,tchain);\n    MarkObject(_class_class,tchain);\n    MarkObject(_instance_class,tchain);\n    MarkObject(_weakref_class,tchain);\n    MarkObject(_userdata_class,tchain);\n\n    MarkObject(doc_objects,tchain);\n}\n\nSQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)\n{\n    SQInteger n=0;\n    SQCollectable *tchain=NULL;\n\n    RunMark(vm,&tchain);\n\n    SQCollectable *resurrected = _gc_chain;\n    SQCollectable *t = resurrected;\n\n    _gc_chain = tchain;\n\n    SQArray *ret = NULL;\n    if(resurrected) {\n        ret = SQArray::Create(this,0);\n        SQCollectable *rlast = NULL;\n        while(t) {\n            rlast = t;\n            SQObjectType type = t->GetType();\n            if(type != OT_FUNCPROTO && type != OT_OUTER) {\n                SQObject sqo;\n                sqo._type = type;\n                sqo._unVal.pRefCounted = t;\n                sqo._flags = 0; //< FIXME: we lose information on mutability, so it turns everyhing into mutable\n                ret->Append(sqo);\n            }\n            t = t->_gc_next;\n            n++;\n        }\n\n        assert(rlast->_gc_next == NULL);\n        rlast->_gc_next = _gc_chain;\n        if(_gc_chain)\n        {\n            _gc_chain->_gc_prev = rlast;\n        }\n        _gc_chain = resurrected;\n    }\n\n    t = _gc_chain;\n    while(t) {\n        t->UnMark();\n        t = t->_gc_next;\n    }\n\n    if(ret) {\n        SQObjectPtr temp(ret);\n        vm->Push(temp);\n    }\n    else {\n        vm->PushNull();\n    }\n    return n;\n}\n\nSQInteger SQSharedState::CollectGarbage(SQVM *vm)\n{\n    SQInteger n = 0;\n    SQCollectable *tchain = NULL;\n\n    RunMark(vm,&tchain);\n\n    SQCollectable *t = _gc_chain;\n    SQCollectable *nx = NULL;\n    if(t) {\n        t->_uiRef++;\n        while(t) {\n            t->Finalize();\n            nx = t->_gc_next;\n            if(nx) nx->_uiRef++;\n            if(--t->_uiRef == 0)\n                t->Release();\n            t = nx;\n            n++;\n        }\n    }\n\n    t = tchain;\n    while(t) {\n        t->UnMark();\n        t = t->_gc_next;\n    }\n    _gc_chain = tchain;\n\n    return n;\n}\n#endif\n\n#ifndef NO_GARBAGE_COLLECTOR\nvoid SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)\n{\n    c->_gc_prev = NULL;\n    c->_gc_next = *chain;\n    if(*chain) (*chain)->_gc_prev = c;\n    *chain = c;\n}\n\nvoid SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)\n{\n    if(c->_gc_prev) c->_gc_prev->_gc_next = c->_gc_next;\n    else *chain = c->_gc_next;\n    if(c->_gc_next)\n        c->_gc_next->_gc_prev = c->_gc_prev;\n    c->_gc_next = NULL;\n    c->_gc_prev = NULL;\n}\n#endif\n\nchar* SQSharedState::GetScratchPad(SQInteger size)\n{\n    SQInteger newsize;\n    if(size>0) {\n        if(_scratchpadsize < size) {\n            newsize = size + (size>>1);\n            _scratchpad = (char *)SQ_REALLOC(_alloc_ctx, _scratchpad, _scratchpadsize, newsize);\n            _scratchpadsize = newsize;\n\n        }else if(_scratchpadsize >= (size<<5)) {\n            newsize = _scratchpadsize >> 1;\n            _scratchpad = (char *)SQ_REALLOC(_alloc_ctx, _scratchpad, _scratchpadsize, newsize);\n            _scratchpadsize = newsize;\n        }\n    }\n    return _scratchpad;\n}\n\nRefTable::RefTable(SQAllocContext ctx) :\n    _alloc_ctx(ctx)\n{\n    AllocNodes(4);\n}\n\nvoid RefTable::Finalize()\n{\n    RefNode *nodes = _nodes;\n    for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\n        nodes->obj.Null();\n        nodes++;\n    }\n}\n\nRefTable::~RefTable()\n{\n    SQ_FREE(_alloc_ctx, _buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));\n}\n\n#ifndef NO_GARBAGE_COLLECTOR\nvoid RefTable::Mark(SQCollectable **chain)\n{\n    RefNode *nodes = (RefNode *)_nodes;\n    for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\n        if(sq_type(nodes->obj) != OT_NULL) {\n            SQSharedState::MarkObject(nodes->obj,chain);\n        }\n        nodes++;\n    }\n}\n#endif\n\nvoid RefTable::AddRef(SQObject &obj)\n{\n    SQHash mainpos;\n    RefNode *prev;\n    RefNode *ref = Get(obj,mainpos,&prev,true);\n    ref->refs++;\n}\n\nSQUnsignedInteger RefTable::GetRefCount(SQObject &obj)\n{\n     SQHash mainpos;\n     RefNode *prev;\n     RefNode *ref = Get(obj,mainpos,&prev,false);\n     return ref ? ref->refs : 0;\n}\n\n\nSQBool RefTable::Release(SQObject &obj)\n{\n    SQHash mainpos;\n    RefNode *prev;\n    RefNode *ref = Get(obj,mainpos,&prev,false);\n    if(ref) {\n        if(--ref->refs == 0) {\n            SQObjectPtr o = ref->obj;\n            if(prev) {\n                prev->next = ref->next;\n            }\n            else {\n                _buckets[mainpos] = ref->next;\n            }\n            ref->next = _freelist;\n            _freelist = ref;\n            _slotused--;\n            ref->obj.Null();\n            //<<FIXME>>test for shrink?\n            return SQTrue;\n        }\n    }\n    else {\n        assert(0);\n    }\n    return SQFalse;\n}\n\nvoid RefTable::Resize(SQUnsignedInteger size)\n{\n    RefNode **oldbucks = _buckets;\n    RefNode *t = _nodes;\n    SQUnsignedInteger oldnumofslots = _numofslots;\n    AllocNodes(size);\n    //rehash\n    SQUnsignedInteger nfound = 0;\n    for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {\n        if(sq_type(t->obj) != OT_NULL) {\n            //add back;\n            assert(t->refs != 0);\n            RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);\n            nn->refs = t->refs;\n            t->obj.Null();\n            nfound++;\n        }\n        t++;\n    }\n    (void)nfound;\n    assert(nfound == oldnumofslots);\n    SQ_FREE(_alloc_ctx, oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));\n}\n\nRefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)\n{\n    RefNode *t = _buckets[mainpos];\n    RefNode *newnode = _freelist;\n    newnode->obj = obj;\n    _buckets[mainpos] = newnode;\n    _freelist = _freelist->next;\n    newnode->next = t;\n    assert(newnode->refs == 0);\n    _slotused++;\n    return newnode;\n}\n\nRefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)\n{\n    RefNode *ref;\n    mainpos = ::HashObj(obj)&(_numofslots-1);\n    *prev = NULL;\n    for (ref = _buckets[mainpos]; ref; ) {\n        if(_rawval(ref->obj) == _rawval(obj) && sq_type(ref->obj) == sq_type(obj))\n            break;\n        *prev = ref;\n        ref = ref->next;\n    }\n    if(ref == NULL && add) {\n        if(_numofslots == _slotused) {\n            assert(_freelist == 0);\n            Resize(_numofslots*2);\n            mainpos = ::HashObj(obj)&(_numofslots-1);\n        }\n        ref = Add(mainpos,obj);\n    }\n    return ref;\n}\n\nvoid RefTable::AllocNodes(SQUnsignedInteger size)\n{\n    RefNode **bucks;\n    RefNode *nodes;\n    bucks = (RefNode **)SQ_MALLOC(_alloc_ctx, (size * sizeof(RefNode *)) + (size * sizeof(RefNode)));\n    nodes = (RefNode *)&bucks[size];\n    RefNode *temp = nodes;\n    SQUnsignedInteger n;\n    for(n = 0; n < size - 1; n++) {\n        bucks[n] = NULL;\n        temp->refs = 0;\n        new (&temp->obj) SQObjectPtr;\n        temp->next = temp+1;\n        temp++;\n    }\n    bucks[n] = NULL;\n    temp->refs = 0;\n    new (&temp->obj) SQObjectPtr;\n    temp->next = NULL;\n    _freelist = nodes;\n    _nodes = nodes;\n    _buckets = bucks;\n    _slotused = 0;\n    _numofslots = size;\n}\n//////////////////////////////////////////////////////////////////////////\n//SQStringTable\n/*\n* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)\n* http://www.lua.org/copyright.html#4\n* http://www.lua.org/source/4.0.1/src_lstring.c.html\n*/\n\nSQStringTable::SQStringTable(SQSharedState *ss)\n{\n    _sharedstate = ss;\n    AllocNodes(4);\n    _slotused = 0;\n}\n\nSQStringTable::~SQStringTable()\n{\n    SQ_FREE(_sharedstate->_alloc_ctx, _strings,sizeof(SQString*)*_numofslots);\n    _strings = NULL;\n}\n\nvoid SQStringTable::AllocNodes(SQInteger size)\n{\n    _numofslots = size;\n    _strings = (SQString**)SQ_MALLOC(_sharedstate->_alloc_ctx, sizeof(SQString*)*_numofslots);\n    memset(_strings,0,sizeof(SQString*)*_numofslots);\n}\n\nSQString *SQStringTable::Add(const char *news,SQInteger len)\n{\n    if(len<0)\n        len = (SQInteger)strlen(news);\n    SQHash newhash = ::_hashstr(news,len);\n    SQHash h = newhash&(_numofslots-1);\n    SQString *s;\n    for (s = _strings[h]; s; s = s->_next){\n        if(s->_len == len && (!memcmp(news,s->_val,len)))\n            return s; //found\n    }\n\n    SQString *t = (SQString *)SQ_MALLOC(_sharedstate->_alloc_ctx, len+sizeof(SQString));\n    new (t) SQString;\n    t->_sharedstate = _sharedstate;\n    memcpy(t->_val,news,len);\n    t->_val[len] = '\\0';\n    t->_len = len;\n    t->_hash = newhash;\n    t->_next = _strings[h];\n    _strings[h] = t;\n    _slotused++;\n    if (_slotused > _numofslots)  /* too crowded? */\n        Resize(_numofslots*2);\n    return t;\n}\n\nvoid SQStringTable::Resize(SQInteger size)\n{\n    SQInteger oldsize=_numofslots;\n    SQString **oldtable=_strings;\n    AllocNodes(size);\n    for (SQInteger i=0; i<oldsize; i++){\n        SQString *p = oldtable[i];\n        while(p){\n            SQString *next = p->_next;\n            SQHash h = p->_hash&(_numofslots-1);\n            p->_next = _strings[h];\n            _strings[h] = p;\n            p = next;\n        }\n    }\n    SQ_FREE(_sharedstate->_alloc_ctx, oldtable, oldsize*sizeof(SQString*));\n}\n\nvoid SQStringTable::Remove(SQString *bs)\n{\n    SQString *s;\n    SQString *prev=NULL;\n    SQHash h = bs->_hash&(_numofslots - 1);\n\n    for (s = _strings[h]; s; ){\n        if(s == bs){\n            if(prev)\n                prev->_next = s->_next;\n            else\n                _strings[h] = s->_next;\n            _slotused--;\n            SQInteger slen = s->_len;\n            s->~SQString();\n            SQ_FREE(_sharedstate->_alloc_ctx, s, sizeof(SQString) + slen);\n            return;\n        }\n        prev = s;\n        s = s->_next;\n    }\n    assert(0);//if this fail something is wrong\n}\n"
  },
  {
    "path": "squirrel/sqstate.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTATE_H_\n#define _SQSTATE_H_\n\n#include \"squtils.h\"\n#include \"sqobject.h\"\nstruct SQString;\nstruct SQTable;\n\nstruct SQStringTable\n{\n    SQStringTable(SQSharedState*ss);\n    ~SQStringTable();\n    SQString *Add(const char *,SQInteger len);\n    void Remove(SQString *);\nprivate:\n    void Resize(SQInteger size);\n    void AllocNodes(SQInteger size);\n    SQString **_strings;\n    SQUnsignedInteger _numofslots;\n    SQUnsignedInteger _slotused;\n    SQSharedState *_sharedstate;\n};\n\nstruct RefTable {\n    struct RefNode {\n        SQObjectPtr obj;\n        SQUnsignedInteger refs;\n        struct RefNode *next;\n    };\n    RefTable(SQAllocContext ctx);\n    ~RefTable();\n    void AddRef(SQObject &obj);\n    SQBool Release(SQObject &obj);\n    SQUnsignedInteger GetRefCount(SQObject &obj);\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n#endif\n    void Finalize();\nprivate:\n    RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add);\n    RefNode *Add(SQHash mainpos,SQObject &obj);\n    void Resize(SQUnsignedInteger size);\n    void AllocNodes(SQUnsignedInteger size);\n    SQUnsignedInteger _numofslots;\n    SQUnsignedInteger _slotused;\n    RefNode *_nodes;\n    RefNode *_freelist;\n    RefNode **_buckets;\n    SQAllocContext _alloc_ctx;\n};\n\n#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len)\n#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr)\n\nstruct SQObjectPtr;\n\nstruct SQSharedState\n{\n    SQSharedState(SQAllocContext allocctx);\n    ~SQSharedState();\n    void Init();\npublic:\n    bool checkCompilationOption(SQUnsignedInteger co) const {\n      return (compilationOptions & co) != 0;\n    }\n\n    void enableCompilationOption(SQUnsignedInteger co) {\n      compilationOptions |= co;\n    }\n\n    void disableCompilationOption(SQUnsignedInteger co) {\n      compilationOptions &= ~co;\n    }\n    char* GetScratchPad(SQInteger size);\n    SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name);\n#ifndef NO_GARBAGE_COLLECTOR\n    SQInteger CollectGarbage(SQVM *vm);\n    void RunMark(SQVM *vm,SQCollectable **tchain);\n    SQInteger ResurrectUnreachable(SQVM *vm);\n    static void MarkObject(SQObjectPtr &o,SQCollectable **chain);\n#endif\n    SQAllocContext _alloc_ctx;\n    SQObjectPtrVec *_metamethodnames;\n    SQObjectPtr _metamethodsmap;\n    SQObjectPtrVec *_systemstrings;\n    SQObjectPtrVec *_types;\n    SQStringTable *_stringtable;\n    RefTable _refs_table;\n    SQObjectPtr _registry;\n    SQObjectPtr _consts;\n    SQObjectPtr _constructorstr;\n#ifndef NO_GARBAGE_COLLECTOR\n    SQCollectable *_gc_chain;\n#endif\n    SQObjectPtr _root_vm;\n\n    // Built-in type classes\n    SQObjectPtr _null_class;\n    SQObjectPtr _integer_class;\n    SQObjectPtr _float_class;\n    SQObjectPtr _bool_class;\n    SQObjectPtr _string_class;\n    SQObjectPtr _array_class;\n    SQObjectPtr _table_class;\n    SQObjectPtr _function_class;\n    SQObjectPtr _generator_class;\n    SQObjectPtr _thread_class;\n    SQObjectPtr _class_class;\n    SQObjectPtr _instance_class;\n    SQObjectPtr _weakref_class;\n    SQObjectPtr _userdata_class;\n\n    static const SQRegFunction _table_default_type_methods_funcz[];\n    static const SQRegFunction _array_default_type_methods_funcz[];\n    static const SQRegFunction _string_default_type_methods_funcz[];\n    static const SQRegFunction _integer_default_type_methods_funcz[];\n    static const SQRegFunction _float_default_type_methods_funcz[];\n    static const SQRegFunction _bool_default_type_methods_funcz[];\n    static const SQRegFunction _null_default_type_methods_funcz[];\n    static const SQRegFunction _generator_default_type_methods_funcz[];\n    static const SQRegFunction _closure_default_type_methods_funcz[];\n    static const SQRegFunction _thread_default_type_methods_funcz[];\n    static const SQRegFunction _class_default_type_methods_funcz[];\n    static const SQRegFunction _instance_default_type_methods_funcz[];\n    static const SQRegFunction _weakref_default_type_methods_funcz[];\n    static const SQRegFunction _userdata_default_type_methods_funcz[];\n\n    SQCOMPILERERROR _compilererrorhandler;\n    SQPRINTFUNCTION _printfunc;\n    SQPRINTFUNCTION _errorfunc;\n    SQ_COMPILER_DIAG_CB _compilerdiaghandler;\n\n    bool _notifyallexceptions;\n    bool _lineInfoInExpressions;\n    bool _varTraceEnabled;\n    SQUnsignedInteger compilationOptions;\n    SQUnsignedInteger defaultLangFeatures;\n    SQUserPointer _foreignptr;\n    SQRELEASEHOOK _releasehook;\n\n    SQObjectPtr doc_objects;\n    int doc_object_index;\n    SQUnsignedInteger32 rand_seed;\n    SQUnsignedInteger32 watchdog_last_alive_time_msec;\n    SQUnsignedInteger32 watchdog_threshold_msec;\nprivate:\n    char *_scratchpad;\n    SQInteger _scratchpadsize;\n};\n\n#define _sp(s) (_sharedstate->GetScratchPad(s))\n#define _spval (_sharedstate->GetScratchPad(-1))\n\nbool CompileTypemask(SQIntVec &res,const char *typemask);\n\n\n#endif //_SQSTATE_H_\n"
  },
  {
    "path": "squirrel/sqstring.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQSTRING_H_\n#define _SQSTRING_H_\n\ninline SQHash _hashstr_lua5(const char *s, size_t l)\n{\n        SQHash h = (SQHash)l;  /* seed */\n        size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */\n        for (; l>=step; l-=step)\n            h ^= ((h<<5)+(h>>2)+(char)(s[l-1]));\n        return h;\n}\n//djb2\ninline SQHash _hashstr_djb2(const char *s, size_t l)\n{\n  SQHash hash = SQHash(5381+l);\n  size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */\n\n  for (; l>=step; l-=step)\n    hash = hash * 33 + s[l-1];\n\n  return hash;\n}\n\n//fnv1\ninline uint32_t _hashstr_fnv1a(const char *s, size_t l)\n{\n  uint32_t result = 2166136261U;\n  size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */\n\n  for (; l>=step; l-=step)\n    result = (result ^ s[l-1])* 16777619;\n  return result;\n}\n\ninline uint64_t _hashstr_fnv1a_64(const char *s, size_t l)\n{\n  uint64_t result = 14695981039346656037LU;\n  size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */\n\n  for (; l>=step; l-=step)\n    result = (result ^ s[l-1]) * 1099511628211LU;\n  return result;\n}\n//inline SQHash _hashstr (const char *s, size_t l){return _hashstr_lua5(s, l);}//worst\n//inline SQHash _hashstr (const char *s, size_t l){return _hashstr_djb2(s, l);}//good\n#ifdef _SQ64//assume we run on 64 bit platform\ninline SQHash _hashstr (const char *s, size_t l){return _hashstr_fnv1a_64(s, l);}\n#else\ninline SQHash _hashstr (const char *s, size_t l){return _hashstr_fnv1a(s, l);}\n#endif\n\nstruct SQString : public SQRefCounted\n{\n    SQString(){}\n    ~SQString(){}\npublic:\n    static SQString *Create(SQSharedState *ss, const char *, SQInteger len = -1 );\n    SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\n    void Release();\n    SQSharedState *_sharedstate;\n    SQString *_next; //chain for the string table\n    SQInteger _len;\n    SQHash _hash;\n    char _val[1];\n};\n\n\n\n#endif //_SQSTRING_H_\n"
  },
  {
    "path": "squirrel/sqstringlib.cpp",
    "content": "#include <sqstringlib.h>\n#include <squirrel.h>\n#include <string.h>\n#include <stdio.h>\n#include <sq_char_class.h>\n\nstatic void __strip_l(const char *str,const char **start)\n{\n    const char *t = str;\n    while(((*t) != '\\0') && sq_isspace(*t)){ t++; }\n    *start = t;\n}\n\nstatic void __strip_r(const char *str,SQInteger len,const char **end)\n{\n    if(len == 0) {\n        *end = str;\n        return;\n    }\n    const char *t = &str[len-1];\n    while(t >= str && sq_isspace(*t)) { t--; }\n    *end = t + 1;\n}\n\nSQInteger _sq_string_strip_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str,*start,*end;\n    sq_getstring(v,arg_stack_start,&str);\n    SQInteger len = sq_getsize(v,arg_stack_start);\n    __strip_l(str,&start);\n    __strip_r(str,len,&end);\n    sq_pushstring(v,start,end - start);\n    return 1;\n}\n\nSQInteger _sq_string_lstrip_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str,*start;\n    sq_getstring(v,arg_stack_start,&str);\n    __strip_l(str,&start);\n    sq_pushstring(v,start,-1);\n    return 1;\n}\n\nSQInteger _sq_string_rstrip_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str,*end;\n    sq_getstring(v,arg_stack_start,&str);\n    SQInteger len = sq_getsize(v,arg_stack_start);\n    __strip_r(str,len,&end);\n    sq_pushstring(v,str,end - str);\n    return 1;\n}\n\nSQInteger _sq_string_split_by_chars_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str,*seps;\n    SQInteger sepsize;\n    SQBool skipempty = SQFalse;\n    sq_getstring(v,arg_stack_start,&str);\n    sq_getstringandsize(v,arg_stack_start+1,&seps,&sepsize);\n    if(sepsize == 0) return sq_throwerror(v,\"empty separators string\");\n    if(sq_gettop(v)>arg_stack_start+1) {\n        sq_getbool(v,arg_stack_start+2,&skipempty);\n    }\n    const char *start = str;\n    const char *end = str;\n    sq_newarray(v,0);\n    while(*end != '\\0')\n    {\n        char cur = *end;\n        for(SQInteger i = 0; i < sepsize; i++)\n        {\n            if(cur == seps[i])\n            {\n                if(!skipempty || (end != start)) {\n                    sq_pushstring(v,start,end-start);\n                    sq_arrayappend(v,-2);\n                }\n                start = end + 1;\n                break;\n            }\n        }\n        end++;\n    }\n    if(end != start)\n    {\n        sq_pushstring(v,start,end-start);\n        sq_arrayappend(v,-2);\n    }\n    return 1;\n}\n\nSQInteger _sq_string_escape_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str;\n    char *dest,*resstr;\n    SQInteger size;\n    sq_getstringandsize(v,arg_stack_start,&str,&size);\n    if(size == 0) {\n        sq_push(v,arg_stack_start);\n        return 1;\n    }\n\n    const char *escpat = \"\\\\x%02x\";\n    const SQInteger maxescsize = 4;\n\n    SQInteger destcharsize = (size * maxescsize) + 1; // +1 for null terminator of last escape\n    resstr = dest = (char *)sq_getscratchpad(v,destcharsize * sizeof(char));\n    char c;\n    char escch;\n    SQInteger escaped = 0;\n    for(int n = 0; n < size; n++){\n        c = *str++;\n        escch = 0;\n        if(sq_isprint(c) || c == 0) {\n            switch(c) {\n            case '\\a': escch = 'a'; break;\n            case '\\b': escch = 'b'; break;\n            case '\\t': escch = 't'; break;\n            case '\\n': escch = 'n'; break;\n            case '\\v': escch = 'v'; break;\n            case '\\f': escch = 'f'; break;\n            case '\\r': escch = 'r'; break;\n            case '\\\\': escch = '\\\\'; break;\n            case '\\\"': escch = '\\\"'; break;\n            case '\\'': escch = '\\''; break;\n            case 0: escch = '0'; break;\n            }\n            if(escch) {\n                *dest++ = '\\\\';\n                *dest++ = escch;\n                escaped++;\n            }\n            else {\n                *dest++ = c;\n            }\n        }\n        else {\n\n            dest += scsprintf(dest, maxescsize + 1, escpat, (unsigned char)c);\n            escaped++;\n        }\n    }\n\n    if(escaped) {\n        sq_pushstring(v,resstr,dest - resstr);\n    }\n    else {\n        sq_push(v,arg_stack_start); //nothing escaped\n    }\n    return 1;\n}\n\nSQInteger _sq_string_startswith_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str,*cmp;\n    SQInteger len, cmplen;\n    sq_getstringandsize(v,arg_stack_start,&str,&len);\n    sq_getstringandsize(v,arg_stack_start+1,&cmp,&cmplen);\n    SQBool ret = SQFalse;\n    if(cmplen <= len) {\n        ret = memcmp(str,cmp,cmplen) == 0 ? SQTrue : SQFalse;\n    }\n    sq_pushbool(v,ret);\n    return 1;\n}\n\nSQInteger _sq_string_endswith_impl(HSQUIRRELVM v, SQInteger arg_stack_start)\n{\n    const char *str,*cmp;\n    SQInteger len, cmplen;\n    sq_getstringandsize(v,arg_stack_start,&str,&len);\n    sq_getstringandsize(v,arg_stack_start+1,&cmp,&cmplen);\n    SQBool ret = SQFalse;\n    if(cmplen <= len) {\n        ret = memcmp(&str[len - cmplen],cmp,cmplen) == 0 ? SQTrue : SQFalse;\n    }\n    sq_pushbool(v,ret);\n    return 1;\n}\n"
  },
  {
    "path": "squirrel/sqtable.cpp",
    "content": "/*\nsee copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include \"sqvm.h\"\n#include \"sqtable.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include <assert.h>\n\n#if defined(_MSC_VER) && !defined(__clang__)\n#pragma intrinsic(_BitScanReverse)\n#endif\n\n#define _FAST_CLONE\n\n#define MINPOWER2 1\n\n#define CLASS_TYPE_HASH_INIT    14695981039346656037ul\n#define CLASS_TYPE_HASH_PRIME   1099511628211ul\n\n\nstatic inline uint64_t class_type_hash_update_1(uint64_t hashval, uint8_t x) {\n    return (hashval ^ x) * CLASS_TYPE_HASH_PRIME;\n}\n\nstatic inline uint64_t class_type_hash_update_4(uint64_t hashval, uint32_t x) {\n    // Unrolled FNV1\n    const uint8_t *bytes = (const uint8_t *)&x;\n    hashval = (hashval ^ bytes[0]) * CLASS_TYPE_HASH_PRIME;\n    hashval = (hashval ^ bytes[1]) * CLASS_TYPE_HASH_PRIME;\n    hashval = (hashval ^ bytes[2]) * CLASS_TYPE_HASH_PRIME;\n    hashval = (hashval ^ bytes[3]) * CLASS_TYPE_HASH_PRIME;\n    return hashval;\n}\n\n\nSQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize)\n    : _alloc_ctx(ss->_alloc_ctx)\n    , _classTypeId(0)\n{\n    SQInteger pow2size=MINPOWER2;\n    while(nInitialSize>pow2size)pow2size=pow2size<<1;\n    AllocNodes(pow2size);\n    _usednodes = 0;\n    _delegate = NULL;\n    INIT_CHAIN();\n    ADD_TO_CHAIN(&_sharedstate->_gc_chain,this);\n}\n\nvoid SQTable::Remove(const SQObjectPtr &key)\n{\n    _HashNode *n = _Get(key, HashObj(key) & _numofnodes_minus_one);\n    if (n) {\n        n->val.Null();\n        n->key.Null();\n        n->key._type = OT_FREE_TABLE_SLOT;\n        VT_CLEAR_SINGLE(n);\n        _usednodes--;\n        Rehash(false);\n        _classTypeId = 0;\n    }\n}\n\nvoid SQTable::AllocNodes(SQInteger nSize)\n{\n    assert((nSize & (nSize-1)) == 0); // pow2\n    _HashNode *nodes=(_HashNode *)SQ_MALLOC(_alloc_ctx, sizeof(_HashNode)*nSize);\n    _numofnodes_minus_one=(uint32_t)(nSize-1);\n    _nodes=nodes;\n    _firstfree=&_nodes[_numofnodes_minus_one];\n    for (_HashNode *i = nodes, *e = i + nSize; i != e; i++)\n        new (i) _HashNode;\n}\n\nvoid SQTable::Rehash(bool force)\n{\n    SQInteger oldsize=_numofnodes_minus_one+1;\n    //prevent problems with the integer division\n    if (oldsize < MINPOWER2) oldsize = MINPOWER2;\n    _HashNode *nold=_nodes;\n    SQInteger nelems=CountUsed();\n    if (nelems >= oldsize - oldsize/4)  /* using more than 3/4? */\n        AllocNodes(oldsize*2);\n    else if (nelems < oldsize/4 &&  /* less than 1/4? */\n        oldsize > MINPOWER2)\n        AllocNodes(oldsize/2);\n    else if (force)\n    {\n        assert(oldsize > 0);\n#if !defined(_MSC_VER) || defined(__clang__)\n        unsigned log2 = 31 - __builtin_clz((unsigned)oldsize);\n#else\n        unsigned long log2;\n        _BitScanReverse(&log2, oldsize);\n#endif\n        AllocNodes(unsigned(1 << (log2 + 1)));\n        assert(_numofnodes_minus_one + 1 > oldsize);\n    }\n    else\n        return;\n    _usednodes = 0;\n    for (SQInteger i=0; i<oldsize; i++) {\n        _HashNode *old = nold+i;\n        if (!(sq_type(old->key) & OT_FREE_TABLE_SLOT))\n            NewSlot(old->key,old->val  VT_REF(old));\n    }\n    for(SQInteger k=0;k<oldsize;k++)\n        nold[k].~_HashNode();\n    SQ_FREE(_alloc_ctx, nold, oldsize*sizeof(_HashNode));\n}\n\nSQTable *SQTable::Clone()\n{\n    const uint32_t cnt = _numofnodes_minus_one+1;\n    SQTable *__restrict nt=Create(_opt_ss(this), cnt);\n#ifdef _FAST_CLONE\n    _HashNode *__restrict basesrc = _nodes;\n    _HashNode *__restrict basedst = nt->_nodes;\n    _HashNode *__restrict src = _nodes;\n    _HashNode *__restrict dst = nt->_nodes;\n    for(_HashNode *__restrict srcE=src + cnt; src != srcE; src++, dst++) {\n        dst->key = src->key;\n        dst->val = src->val;\n        VT_COPY_SINGLE(src, dst);\n        VT_TRACE_SINGLE(dst, dst->val, _ss(this)->_root_vm);\n        if(src->next) {\n            assert(src->next > basesrc);\n            dst->next = basedst + (src->next - basesrc);\n            assert(dst != dst->next);\n        }\n    }\n    assert(_firstfree >= basesrc);\n    assert(_firstfree != NULL);\n    nt->_firstfree = basedst + (_firstfree - basesrc);\n    nt->_usednodes = _usednodes;\n#else\n    SQInteger ridx=0;\n    SQObjectPtr key,val;\n    while((ridx=Next(true,ridx,key,val))!=-1){\n        nt->NewSlot(key,val VT_CODE(VT_COMMA &_nodes[ridx].varTrace));\n    }\n#endif\n    nt->_classTypeId = _classTypeId;\n    nt->SetDelegate(_delegate);\n    return nt;\n}\n\nSQTable::_HashNode *SQTable::_Get(const SQObjectPtr &key) const\n{\n    if (sq_type(key) == OT_STRING)\n        return _GetStr(_rawval(key), _string(key)->_hash & _numofnodes_minus_one);\n    else\n        return _Get(key, HashObj(key) & _numofnodes_minus_one);\n}\n\nbool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) const\n{\n    const _HashNode *n = _Get(key);\n    if (n) {\n        val = _realval(n->val);\n        return true;\n    }\n    return false;\n}\n\nbool SQTable::GetStrToInt(const SQObjectPtr &key,uint32_t &val) const//for class members\n{\n    assert(sq_type(key) == OT_STRING);\n    const _HashNode *n = _GetStr(_rawval(key), _string(key)->_hash & _numofnodes_minus_one);\n    if (!n)\n      return false;\n    assert(sq_type(n->val) == OT_INTEGER);\n    val = _integer(n->val);\n    return true;\n}\n\n#if SQ_VAR_TRACE_ENABLED == 1\nVarTrace * SQTable::GetVarTracePtr(const SQObjectPtr &key)\n{\n  _HashNode *n = _Get(key, HashObj(key) & _numofnodes_minus_one);\n  if (n)\n    return &(n->varTrace);\n  else\n    return NULL;\n}\n#endif\n\n\nbool SQTable::NewSlot(const SQObjectPtr &__restrict key,const SQObjectPtr &__restrict val  VT_DECL_ARG)\n{\n    SQHash h = HashObj(key) & _numofnodes_minus_one;\n    _HashNode *n = _Get(key, h);\n    if (n) {\n        n->val = val;\n        VT_CODE(if (var_trace_arg) n->varTrace = *var_trace_arg);\n        VT_TRACE_SINGLE(n, val, _ss(this)->_root_vm);\n        return false;\n    }\n    _HashNode *mp = &_nodes[h];\n    n = mp;\n\n    //key not found I'll insert it\n    //main pos is not free\n\n    if(!(sq_type(mp->key) & OT_FREE_TABLE_SLOT)) {\n        n = _firstfree;  /* get a free place */\n        SQHash mph = HashObj(mp->key) & _numofnodes_minus_one;\n        _HashNode *othern;  /* main position of colliding node */\n\n        if (mp > n && (othern = &_nodes[mph]) != mp){\n            /* yes; move colliding node into free position */\n            while (othern->next != mp){\n                assert(othern->next != NULL);\n                othern = othern->next;  /* find previous */\n            }\n            othern->next = n;  /* redo the chain with `n' in place of `mp' */\n            n->key = mp->key;\n            n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */\n            n->next = mp->next;\n            VT_COPY_SINGLE(mp, n);\n            mp->key.Null();\n            mp->key._type = OT_FREE_TABLE_SLOT;\n            mp->val.Null();\n            VT_CLEAR_SINGLE(mp);\n            mp->next = NULL;  /* now `mp' is free */\n        }\n        else{\n            /* new node will go into free position */\n            n->next = mp->next;  /* chain new position */\n            mp->next = n;\n            mp = n;\n        }\n    }\n    mp->key = key;\n\n    for (;;) {  /* correct `firstfree' */\n        if ((sq_type(_firstfree->key) & OT_FREE_TABLE_SLOT) && _firstfree->next == NULL) {\n            mp->val = val;\n            VT_CODE(if (var_trace_arg) mp->varTrace = *var_trace_arg);\n            VT_TRACE_SINGLE(mp, val, _ss(this)->_root_vm);\n\n            // update class type id\n            if (sq_isstring(key) && (_numofnodes_minus_one < (1<<TBL_CLASS_TYPE_MEMBER_BITS))) {\n                if (_classTypeId != 0 || _usednodes==0) {\n                    uint8_t insertPos = mp - _nodes;\n                    _classTypeId = class_type_hash_update_1(_classTypeId ? _classTypeId : CLASS_TYPE_HASH_INIT, insertPos);\n\n                    // Use SQString address as identifier, strings are unique, immutable and strored in a table.\n                    // That means that all script strings share the same reference to SQString.\n                    // 32 provides more than realistic address range.\n                    uint32_t strIdBits = uint32_t( (uintptr_t(_string(key)) >> 3) & 0xFFFFFFFF );\n                    _classTypeId = class_type_hash_update_4(_classTypeId, strIdBits);\n                }\n            } else {\n                _classTypeId = 0;\n            }\n\n            ++_usednodes;\n\n            return true;  /* OK; table still has a free place */\n        }\n        else if (_firstfree == _nodes) break;  /* cannot decrement from here */\n        else (_firstfree)--;\n    }\n    Rehash(true);\n    return NewSlot(key, val  VT_CODE(VT_COMMA var_trace_arg));\n}\n\nSQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &__restrict refpos, SQObjectPtr &__restrict outkey, SQObjectPtr &__restrict outval)\n{\n    uint32_t idx = (uint32_t)TranslateIndex(refpos);\n    while (idx <= _numofnodes_minus_one) {\n        if(!(sq_type(_nodes[idx].key) & OT_FREE_TABLE_SLOT)) {\n            //first found\n            _HashNode &n = _nodes[idx];\n            outkey = n.key;\n            outval = getweakrefs?(SQObject)n.val:_realval(n.val);\n            //return idx for the next iteration\n            return ++idx;\n        }\n        ++idx;\n    }\n    //nothing to iterate anymore\n    return -1;\n}\n\n\nbool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)\n{\n    _HashNode *n = _Get(key);\n    if (n) {\n        n->val = val;\n        VT_TRACE_SINGLE(n, val, _ss(this)->_root_vm);\n        return true;\n    }\n    return false;\n}\n\nvoid SQTable::_ClearNodes()\n{\n    for (_HashNode *__restrict i = _nodes, *e = i + _numofnodes_minus_one; i <= e; i++) {\n      i->key.Null();\n      i->key._type = OT_FREE_TABLE_SLOT;\n      i->val.Null();\n      i->next = NULL;\n      VT_CLEAR_SINGLE(i);\n    }\n}\n\nvoid SQTable::Finalize()\n{\n    _ClearNodes();\n    SetDelegate(NULL);\n}\n\nvoid SQTable::Clear(SQBool rehash)\n{\n    _ClearNodes();\n    _usednodes = 0;\n    _classTypeId = 0;\n    if (rehash)\n      Rehash(true);\n    else\n      _firstfree=&_nodes[_numofnodes_minus_one];\n}\n\nbool SQTable::IsBinaryEqual(SQTable *o)\n{\n    if (o->_usednodes != _usednodes || o->_classTypeId != _classTypeId)\n        return false;\n    if (o == this)\n        return true;\n    if (o->_usednodes == 0)\n        return true;\n\n    return memcmp(_nodes, o->_nodes, sizeof(_HashNode) * (_numofnodes_minus_one + 1)) == 0;\n}\n"
  },
  {
    "path": "squirrel/sqtable.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQTABLE_H_\n#define _SQTABLE_H_\n/*\n* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)\n* http://www.lua.org/copyright.html#4\n* http://www.lua.org/source/4.0.1/src_ltable.c.html\n*/\n\n#include \"sqstring.h\"\n#include \"vartrace.h\"\n\n#define hashptr(p)  (SQHash((SQInteger(p) >> 4)))\n\n#define TBL_CLASS_TYPE_MEMBER_BITS 5\n#define TBL_CLASS_TYPE_MEMBER_MASK ((1u<<TBL_CLASS_TYPE_MEMBER_BITS)-1)\n#define TBL_CLASS_CLASS_MASK ( (~(uint64_t(0))) ^ TBL_CLASS_TYPE_MEMBER_MASK )\n\ninline SQUnsignedInteger32 sq_float_hash32(float v)\n{\n    SQUnsignedInteger32 i;\n    memcpy(&i, &v, 4);\n    return i ^ (i >> 23);\n}\n\ninline SQHash HashObj(const SQObject &key)\n{\n    switch(sq_type(key)) {\n        case OT_STRING:     return _string(key)->_hash;\n        case OT_FLOAT:      return (SQHash)(sq_float_hash32(_float(key)));\n        case OT_BOOL: case OT_INTEGER:  return (SQHash)((SQInteger)_integer(key));\n        default:            return hashptr(key._unVal.pRefCounted);\n    }\n}\n\nstruct SQTable : public SQDelegable\n{\nprivate:\n    friend struct SQVM;\n    friend struct SQDeduplicateShrinker;\n    friend struct SQStreamSerializer;\n    struct _HashNode\n    {\n        _HashNode() { key._type = OT_FREE_TABLE_SLOT; next = NULL; }\n        SQObjectPtr val;\n        SQObjectPtr key;\n        _HashNode *next;\n        VT_DECL_SINGLE;\n    };\n    _HashNode *_firstfree;\n    _HashNode *_nodes;\n    uint32_t _numofnodes_minus_one;\n    uint32_t _usednodes;\n    SQAllocContext _alloc_ctx;\n    uint64_t _classTypeId;\n    ///////////////////////\n    void AllocNodes(SQInteger nSize);\n    void Rehash(bool force);\n    SQTable(SQSharedState *ss, SQInteger nInitialSize);\n    void _ClearNodes();\npublic:\n    static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize)\n    {\n        SQTable *newtable = (SQTable*)SQ_MALLOC(ss->_alloc_ctx, sizeof(SQTable));\n        new (newtable) SQTable(ss, nInitialSize);\n        newtable->_delegate = NULL;\n        return newtable;\n    }\n    void Finalize();\n    SQTable *Clone();\n    ~SQTable()\n    {\n        uint32_t cnt = _numofnodes_minus_one + 1;\n        _HashNode *__restrict lNodes = _nodes;\n        SetDelegate(NULL);\n        REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);\n        for (_HashNode *i = lNodes, *e = i + cnt; i != e; i++)\n          i->~_HashNode();\n        SQ_FREE(_alloc_ctx, lNodes, cnt  * sizeof(_HashNode));\n    }\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    SQObjectType GetType() {return OT_TABLE;}\n#endif\n    inline _HashNode *_GetStr(const SQRawObjectVal key, SQHash hash) const\n    {\n        _HashNode *n = &_nodes[hash];\n        do{\n            if(_rawval(n->key) == key && sq_type(n->key) == OT_STRING){\n                return n;\n            }\n        }while((n = n->next));\n        return NULL;\n    }\n    inline _HashNode *_Get(const SQObjectPtr &key, SQHash hash) const\n    {\n        _HashNode *n = &_nodes[hash];\n        do{\n            if(_rawval(n->key) == _rawval(key) && sq_type(n->key) == sq_type(key)){\n                return n;\n            }\n        }while((n = n->next));\n        return NULL;\n    }\n    //for compiler use\n    inline bool GetStr(const char* key,SQInteger keylen,SQObjectPtr &val) const\n    {\n        SQHash hash = _hashstr(key,keylen);\n        _HashNode *n = &_nodes[hash & _numofnodes_minus_one];\n        _HashNode *res = NULL;\n        do{\n            if (sq_type(n->key) == OT_STRING &&\n               (keylen == _string(n->key)->_len && strncmp(_stringval(n->key), key, keylen) == 0))\n            {\n                res = n;\n                break;\n            }\n        }while((n = n->next));\n        if (res) {\n            val = _realval(res->val);\n            return true;\n        }\n        return false;\n    }\n    _HashNode *_Get(const SQObjectPtr &key) const;\n    bool Get(const SQObjectPtr &key,SQObjectPtr &val) const;\n    bool GetStrToInt(const SQObjectPtr &key,uint32_t &val) const;//for class members\n\n    inline _HashNode *GetNodeFromTypeHint(uint64_t hint, const SQObjectPtr &key) const {\n        size_t nodeIdx = size_t(hint & TBL_CLASS_TYPE_MEMBER_MASK);\n        if (nodeIdx > _numofnodes_minus_one)\n            assert(!\"Node index is out of range\");\n        else if (!sq_isstring(_nodes[nodeIdx].key))\n            assert(!\"Node key is not a string\");\n        else if (_string(_nodes[nodeIdx].key) != _string(key))\n            assert(!\"Literal key mismatch\");\n        else\n            return _nodes + nodeIdx;\n        return nullptr;\n    }\n\n    VT_CODE(VarTrace * GetVarTracePtr(const SQObjectPtr &key));\n\n    void Remove(const SQObjectPtr &key);\n    bool Set(const SQObjectPtr &key, const SQObjectPtr &val);\n    //returns true if a new slot has been created false if it was already present\n    bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val  VT_DECL_ARG_DEF);\n    SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);\n\n    SQInteger CountUsed(){ return _usednodes;}\n    SQInteger AllocatedNodes(){ return _numofnodes_minus_one + 1; }\n    bool IsBinaryEqual(SQTable *o);\n    void Clear(SQBool rehash = SQTrue);\n    void Release()\n    {\n        sq_delete(_alloc_ctx, this, SQTable);\n    }\n\n};\n\n#endif //_SQTABLE_H_\n"
  },
  {
    "path": "squirrel/squserdata.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQUSERDATA_H_\n#define _SQUSERDATA_H_\n\nstruct SQUserData : SQDelegable\n{\n    SQUserData(SQSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); }\n    ~SQUserData()\n    {\n        REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this);\n        SetDelegate(NULL);\n    }\n    static SQUserData* Create(SQSharedState *ss, SQInteger size)\n    {\n        SQUserData* ud = (SQUserData*)SQ_MALLOC(ss->_alloc_ctx, sq_aligning(sizeof(SQUserData))+size);\n        new (ud) SQUserData(ss);\n        ud->_size = size;\n        ud->_typetag = 0;\n        return ud;\n    }\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    void Finalize(){SetDelegate(NULL);}\n    SQObjectType GetType(){ return OT_USERDATA;}\n#endif\n    void Release() {\n        if (_hook) _hook(_thread(_sharedstate->_root_vm),(SQUserPointer)sq_aligning(this + 1),_size);\n        SQInteger tsize = _size;\n        this->~SQUserData();\n        SQ_FREE(_sharedstate->_alloc_ctx, this, sq_aligning(sizeof(SQUserData)) + tsize);\n    }\n\n\n    SQInteger _size;\n    SQRELEASEHOOK _hook;\n    SQUserPointer _typetag;\n    //char _val[1];\n};\n\n#endif //_SQUSERDATA_H_\n"
  },
  {
    "path": "squirrel/squtils.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQUTILS_H_\n#define _SQUTILS_H_\n\n#include <memory>\n\ntypedef struct SQAllocContextT * SQAllocContext;\n\nvoid sq_vm_init_alloc_context(SQAllocContext * ctx);\nvoid sq_vm_destroy_alloc_context(SQAllocContext * ctx);\nvoid sq_vm_assign_to_alloc_context(SQAllocContext ctx, HSQUIRRELVM vm);\nvoid *sq_vm_malloc(SQAllocContext ctx, SQUnsignedInteger size);\nvoid *sq_vm_realloc(SQAllocContext ctx, void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size);\nvoid sq_vm_free(SQAllocContext ctx, void *p,SQUnsignedInteger size);\n\n#define sq_new(__ctx,__ptr,__type, ...) {__ptr=(__type *)sq_vm_malloc((__ctx),sizeof(__type));new (__ptr) __type(__VA_ARGS__);}\n#define sq_delete(__ctx,__ptr,__type) {__ptr->~__type();sq_vm_free((__ctx),__ptr,sizeof(__type));}\n#define SQ_MALLOC(__ctx,__size) sq_vm_malloc((__ctx),(__size));\n#define SQ_FREE(__ctx,__ptr,__size) sq_vm_free((__ctx),(__ptr),(__size));\n#define SQ_REALLOC(__ctx,__ptr,__oldsize,__size) sq_vm_realloc((__ctx),(__ptr),(__oldsize),(__size));\n\n#define sq_aligning(v) (((size_t)(v) + (SQ_ALIGNMENT-1)) & (~(SQ_ALIGNMENT-1)))\n\n#ifndef SQ_LIKELY\n  #if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)\n    #if defined(__cplusplus)\n      #define SQ_LIKELY(x)   __builtin_expect(!!(x), true)\n      #define SQ_UNLIKELY(x) __builtin_expect(!!(x), false)\n    #else\n      #define SQ_LIKELY(x)   __builtin_expect(!!(x), 1)\n      #define SQ_UNLIKELY(x) __builtin_expect(!!(x), 0)\n    #endif\n  #else\n    #define SQ_LIKELY(x)   (x)\n    #define SQ_UNLIKELY(x) (x)\n  #endif\n#endif\n\n\n//sqvector mini vector class, supports objects by value\ntemplate<typename T, typename SizeT = uint32_t> class sqvector\n{\npublic:\n    using size_type = SizeT;\n\n    sqvector(SQAllocContext ctx)\n        : _vals(NULL)\n        ,  _size(0)\n        , _allocated(0)\n        , _alloc_ctx(ctx)\n    {\n    }\n    sqvector(const sqvector<T>& v)\n        : _vals(NULL)\n        , _size(0)\n        , _allocated(0)\n        , _alloc_ctx(v._alloc_ctx)\n    {\n        copy(v);\n    }\n    void copy(const sqvector<T>& v)\n    {\n        if (_alloc_ctx != v._alloc_ctx) {\n            _releasedata();\n            _vals = NULL;\n            _allocated = 0;\n            _size = 0;\n            _alloc_ctx = v._alloc_ctx;\n        }\n        else if(_size) {\n            resize(0); //destroys all previous stuff\n        }\n        //resize(v._size);\n        if(v._size > _allocated) {\n            _realloc(v._size);\n        }\n        for(size_type i = 0; i < v._size; i++) {\n            new ((void *)&_vals[i]) T(v._vals[i]); //-V522\n        }\n        _size = v._size;\n    }\n    ~sqvector()\n    {\n        _releasedata();\n    }\n    void reserve(size_type newsize) { _realloc(newsize); }\n    void resize(size_type newsize, const T& fill = T())\n    {\n        if(newsize > _allocated)\n            _realloc(newsize);\n        if(newsize > _size) {\n            while(_size < newsize) {\n                new ((void *)&_vals[_size]) T(fill);\n                _size++;\n            }\n        }\n        else{\n            for(size_type i = newsize; i < _size; i++) {\n                _vals[i].~T();\n            }\n            _size = newsize;\n        }\n    }\n    void clear() { resize(0); }\n    void shrinktofit() { if(_size > 4) { _realloc(_size); } }\n    T& top() const { return _vals[_size - 1]; }\n    inline size_type size() const { return _size; }\n    bool empty() const { return (_size <= 0); }\n    inline T &push_back(const T& val = T())\n    {\n        if(_allocated <= _size)\n            _realloc(_size * 2);\n        return *(new ((void *)&_vals[_size++]) T(val));\n    }\n    inline T &push_back(T&& val)\n    {\n        if(_allocated <= _size)\n            _realloc(_size * 2);\n        return *(new ((void *)&_vals[_size++]) T(std::move(val)));\n    }\n    inline void pop_back()\n    {\n        _size--; _vals[_size].~T();\n    }\n    void insert(size_type idx, const T& val)\n    {\n        resize(_size + 1);\n        for(size_type i = _size - 1; i > idx; i--) {\n            _vals[i] = _vals[i - 1]; // -V1002\n        }\n        _vals[idx] = val; // -V1002\n    }\n    void remove(size_type idx)\n    {\n        _vals[idx].~T();\n        if(idx < (_size - 1)) {\n            memmove(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1));\n        }\n        _size--;\n    }\n    size_type capacity() { return _allocated; }\n    inline T &back() const { return _vals[_size - 1]; }\n    inline T& operator[](size_type pos) const{ return _vals[pos]; }\n    T* _vals;\n    SQAllocContext _alloc_ctx;\n\n    typedef T* iterator;\n    typedef const T* const_iterator;\n\n    iterator begin() { return &_vals[0]; }\n    const_iterator begin() const { return &_vals[0]; }\n    iterator end() { return &_vals[_size]; }\n    const_iterator end() const { return &_vals[_size]; }\nprivate:\n    void _realloc(size_type newsize)\n    {\n        newsize = (newsize > 0)?newsize:4;\n        _vals = (T*)SQ_REALLOC(_alloc_ctx, _vals, _allocated * sizeof(T), newsize * sizeof(T));\n        _allocated = newsize;\n    }\n    void _releasedata()\n    {\n        if(_allocated) {\n            for(size_type i = 0; i < _size; i++)\n                _vals[i].~T();\n            SQ_FREE(_alloc_ctx, _vals, (_allocated * sizeof(T)));\n        }\n    }\n    size_type _size;\n    size_type _allocated;\n};\n\n#endif //_SQUTILS_H_\n"
  },
  {
    "path": "squirrel/sqvm.cpp",
    "content": "/*\n    see copyright notice in squirrel.h\n*/\n#include \"sqpcheader.h\"\n#include <math.h>\n#include <stdlib.h>\n#include \"opcodes.h\"\n#include \"sqvm.h\"\n#include \"sqfuncproto.h\"\n#include \"sqclosure.h\"\n#include \"sqstring.h\"\n#include \"sqtable.h\"\n#include \"squserdata.h\"\n#include \"sqarray.h\"\n#include \"sqclass.h\"\n#include \"vartrace.h\"\n#include \"compiler/sqtypeparser.h\" // for sq_stringify_type_mask\n#include \"sq_safe_shift.h\"\n\n#define TARGET _stkbase[arg0]\n#define STK(a) _stkbase[(a)]\n#define RELOAD_STK() _stkbase = _stack._vals + _stackbase\n\n#define WATCHDOG_RAREFICATION 8000\n\nstatic inline void propagate_immutable(const SQObject &obj, SQObject &slot_val)\n{\n    if (sq_objflags(obj) & SQOBJ_FLAG_IMMUTABLE)\n        slot_val._flags |= SQOBJ_FLAG_IMMUTABLE;\n}\n\nstatic inline bool check_typemask(SQObjectType tp, SQInteger typemask)\n{\n  return (tp != OT_NULL) ? (typemask & tp) : (typemask & _RT_NULL);\n}\n\n\nbool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\n{\n    SQInteger res;\n    if((sq_type(o1)|sq_type(o2)) == OT_INTEGER)\n    {\n        SQInteger i1 = _integer(o1), i2 = _integer(o2);\n        switch(op) {\n            case BW_AND:    res = i1 & i2; break;\n            case BW_OR:     res = i1 | i2; break;\n            case BW_XOR:    res = i1 ^ i2; break;\n            case BW_SHIFTL: res = sq_safe_shift_left(i1, i2); break;\n            case BW_SHIFTR: res = sq_safe_shift_right(i1, i2); break;\n            case BW_USHIFTR:res = sq_safe_unsigned_shift_right(i1, i2); break;\n            default: { Raise_Error(\"internal vm error bitwise op failed\"); return false; }\n        }\n    }\n    else { Raise_Error(\"bitwise op between '%s' and '%s'\",GetTypeName(o1),GetTypeName(o2)); return false;}\n    trg = res;\n    return true;\n}\n\n#define _ARITH_(op,trg,o1,o2) \\\n{ \\\n    SQInteger tmask = sq_type(o1)|sq_type(o2); \\\n    switch(tmask) { \\\n        case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \\\n        case (OT_FLOAT|OT_INTEGER): \\\n        case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break; \\\n        default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\\\n    } \\\n}\n\n#define _ARITH_NOZERO(op,trg,o1,o2) \\\n{ \\\n    SQInteger tmask = sq_type(o1)|sq_type(o2); \\\n    switch(tmask) { \\\n        case OT_INTEGER: { SQInteger i2 = _integer(o2); \\\n            if (i2 == 0) { Raise_Error(\"division by zero\"); SQ_THROW(); } \\\n            else if (i2 == -1 && _integer(o1) == MIN_SQ_INTEGER) { Raise_Error(\"integer overflow\"); SQ_THROW(); } \\\n            trg = _integer(o1) op i2; } break; \\\n        case (OT_FLOAT|OT_INTEGER): \\\n        case (OT_FLOAT): { SQFloat f2 = tofloat(o2); if(f2 == (SQFloat)0.f) { Raise_Error(\"float division by zero\"); SQ_THROW(); } trg = tofloat(o1) op f2; } break;\\\n        default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\\\n    } \\\n}\n\n\nbool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\n{\n    SQInteger tmask = sq_type(o1)|sq_type(o2);\n    switch(tmask) {\n        case OT_INTEGER:{\n            SQInteger res, i1 = _integer(o1), i2 = _integer(o2);\n            switch(op) {\n            case '+': res = i1 + i2; break;\n            case '-': res = i1 - i2; break;\n            case '/': if (i2 == 0) { Raise_Error(\"integer division by zero\"); return false; }\n                    else if (i2 == -1 && i1 == MIN_SQ_INTEGER) { Raise_Error(\"integer overflow\"); return false; }\n                    res = i1 / i2;\n                    break;\n            case '*': res = i1 * i2; break;\n            case '%': if (i2 == 0) { Raise_Error(\"integer modulo by zero\"); return false; }\n                    else if (i2 == -1) { res = 0; break; }\n                    res = i1 % i2;\n                    break;\n            default: res = 0xDEADBEEF;\n            }\n            trg = res; }\n            break;\n        case (OT_FLOAT|OT_INTEGER):\n        case (OT_FLOAT):{\n            SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2);\n            switch(op) {\n            case '+': res = f1 + f2; break;\n            case '-': res = f1 - f2; break;\n            case '/':\n              if (f2 == 0.f) { Raise_Error(\"float division by zero\"); return false; }\n              res = f1 / f2;\n              break;\n            case '*': res = f1 * f2; break;\n            case '%':\n              if (f2 == 0.f) { Raise_Error(\"float modulo by zero\"); return false; }\n              res = SQFloat(fmod((double)f1,(double)f2));\n              break;\n            default: res = 0x0f;\n            }\n            trg = res; }\n            break;\n        default:\n            if(op == '+' && (tmask & _RT_STRING)){\n                if(!StringCat(o1, o2, trg)) return false;\n            }\n            else if(!ArithMetaMethod(op,o1,o2,trg)) {\n                return false;\n            }\n    }\n    return true;\n}\n\nSQVM::SQVM(SQSharedState *ss) :\n    _callstackdata(nullptr),\n    _stack(ss->_alloc_ctx),\n    _etraps(ss->_alloc_ctx)\n{\n    _sharedstate=ss;\n    _suspended = SQFalse;\n    _suspended_target = -1;\n    _suspended_root = SQFalse;\n    _suspended_traps = -1;\n    _foreignptr = NULL;\n    _nnativecalls = 0;\n    _nmetamethodscall = 0;\n    _lasterror.Null();\n    _errorhandler.Null();\n    _debughook = false;\n    _debughook_native = NULL;\n    _debughook_closure.Null();\n    _compile_line_hook = NULL;\n    _current_thread = -1;\n    _get_current_thread_id_func = NULL;\n    _sq_call_hook = NULL;\n    _watchdog_hook = NULL;\n    _openouters = NULL;\n    ci = NULL;\n    _releasehook = NULL;\n    INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nvoid SQVM::Finalize()\n{\n    if (_debughook)\n        CallDebugHook('x');\n\n    if(_releasehook) { _releasehook(this,_foreignptr,0); _releasehook = NULL; }\n    if(_openouters) CloseOuters(&_stack._vals[0]);\n    _roottable.Null();\n    _lasterror.Null();\n    _errorhandler.Null();\n    _debughook = false;\n    _debughook_native = NULL;\n    _compile_line_hook = NULL;\n    _debughook_closure.Null();\n    _get_current_thread_id_func = NULL;\n    _sq_call_hook = NULL;\n    _watchdog_hook = NULL;\n    temp_reg.Null();\n    _callstackdata.resize(0);\n    SQInteger size=_stack.size();\n    for(SQInteger i=0;i<size;i++)\n        _stack[i].Null();\n}\n\nSQVM::~SQVM()\n{\n    Finalize();\n    REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\n}\n\nbool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest)\n{\n    SQMetaMethod mm;\n    switch(op){\n        case '+': mm=MT_ADD; break;\n        case '-': mm=MT_SUB; break;\n        case '/': mm=MT_DIV; break;\n        case '*': mm=MT_MUL; break;\n        case '%': mm=MT_MODULO; break;\n        default: mm = MT_ADD; assert(0); break; //shutup compiler\n    }\n    if(is_delegable(o1) && _delegable(o1)->_delegate) {\n\n        SQObjectPtr closure;\n        if(_delegable(o1)->GetMetaMethod(this, mm, closure)) {\n            Push(o1);Push(o2);\n            return CallMetaMethod(closure,mm,2,dest);\n        }\n    }\n    Raise_Error(\"arith op %c on between '%s' and '%s'\",(char)op,GetTypeName(o1),GetTypeName(o2));\n    return false;\n}\n\nbool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)\n{\n    switch(sq_type(o)) {\n    case OT_INTEGER:\n        trg = -_integer(o);\n        return true;\n    case OT_FLOAT:\n        trg = -_float(o);\n        return true;\n    case OT_TABLE:\n    case OT_USERDATA:\n    case OT_INSTANCE:\n        if(_delegable(o)->_delegate) {\n            SQObjectPtr closure;\n            if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) {\n                Push(o);\n                if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false;\n                _Swap(trg,temp_reg);\n                return true;\n            }\n        }\n    default:break; //shutup compiler\n    }\n    Raise_Error(\"attempt to negate a %s\", GetTypeName(o));\n    return false;\n}\n\n#define _RET_SUCCEED(exp) { result = (exp); return true; }\nbool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)\n{\n    SQObjectType t1 = sq_type(o1), t2 = sq_type(o2);\n    if(t1 == t2) {\n        if(_rawval(o1) == _rawval(o2))_RET_SUCCEED(0);\n        SQObjectPtr res;\n        switch(t1){\n        case OT_STRING:\n            _RET_SUCCEED(strcmp(_stringval(o1),_stringval(o2)));\n        case OT_INTEGER:\n        case OT_BOOL:\n            _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:1);\n        case OT_FLOAT:\n            _RET_SUCCEED((_float(o1)<_float(o2))?-1:(_float(o1)==_float(o2))?0:1);\n        case OT_TABLE:\n        case OT_USERDATA:\n        case OT_INSTANCE:\n            if(_delegable(o1)->_delegate) {\n                SQObjectPtr closure;\n                if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) {\n                    Push(o1);Push(o2);\n                    if(CallMetaMethod(closure,MT_CMP,2,res)) {\n                        if(sq_type(res) != OT_INTEGER) {\n                            Raise_Error(\"_cmp must return an integer\");\n                            return false;\n                        }\n                        _RET_SUCCEED(_integer(res))\n                    }\n                    return false;\n                }\n            }\n            //continues through (no break needed)\n        default:\n            Raise_CompareError(o1, o2);\n            return false;\n        }\n    }\n    else{\n        if(sq_isnumeric(o1) && sq_isnumeric(o2)){\n            if((t1==OT_INTEGER) && (t2==OT_FLOAT)) {\n                if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }\n                else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }\n                _RET_SUCCEED(1);\n            }\n            else{\n                if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }\n                else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }\n                _RET_SUCCEED(1);\n            }\n        }\n        else if(t1==OT_NULL) {_RET_SUCCEED(-1);}\n        else if(t2==OT_NULL) {_RET_SUCCEED(1);}\n        else { Raise_CompareError(o1,o2); return false; }\n    }\n}\n\nbool SQVM::ObjCmpI(const SQObjectPtr &o1,const SQInteger o2,SQInteger &result)\n{\n    SQObjectType t1 = sq_type(o1);\n    if(t1 == OT_INTEGER) {\n        SQInteger i1 = _integer(o1);\n        result = (i1 == o2) ? 0 : (i1 < o2 ? -1 : 1);\n        return true;\n    }\n    else if (t1 == OT_FLOAT){\n        SQFloat f1 = _float(o1);\n        result = (f1 == o2) ? 0 : (f1 < o2 ? -1 : 1);\n        return true;\n    } else if(t1==OT_NULL) {_RET_SUCCEED(-1);}\n    else Raise_CompareError(o1, SQObjectPtr(o2));\n    return false;\n}\n\nbool SQVM::ObjCmpF(const SQObjectPtr &o1,const SQFloat o2,SQInteger &result)\n{\n    SQObjectType t1 = sq_type(o1);\n    if(t1 == OT_FLOAT) {\n        float f1 = _float(o1);\n        result = (f1 == o2) ? 0 : (f1 < o2 ? -1 : 1);\n        return true;\n    }\n    else if (t1 == OT_INTEGER){\n        SQInteger i1 = _integer(o1);\n        result = (i1 == o2) ? 0 : (i1 < o2 ? -1 : 1);\n        return true;\n    } else if(t1==OT_NULL) {_RET_SUCCEED(-1);}\n    else Raise_CompareError(o1, SQObjectPtr(o2));\n    return false;\n}\n\nbool SQVM::CMP_OP_RESI(CmpOP op, const SQObjectPtr &o1,const SQInteger o2, int &res)\n{\n    SQInteger r;\n    if(ObjCmpI(o1,o2,r)) {\n        switch(op) {\n            case CMP_G: res = (r > 0); return true;\n            case CMP_GE: res = (r >= 0); return true;\n            case CMP_L: res = (r < 0); return true;\n            case CMP_LE: res = (r <= 0); return true;\n            case CMP_3W: res = r; return true;\n        }\n        assert(0);\n    }\n    return false;\n}\n\nbool SQVM::CMP_OP_RESF(CmpOP op, const SQObjectPtr &o1,const SQFloat o2, int &res)\n{\n    SQInteger r;\n    if(ObjCmpF(o1,o2,r)) {\n        switch(op) {\n            case CMP_G: res = (r > 0); return true;\n            case CMP_GE: res = (r >= 0); return true;\n            case CMP_L: res = (r < 0); return true;\n            case CMP_LE: res = (r <= 0); return true;\n            case CMP_3W: res = r; return true;\n        }\n        assert(0);\n    }\n    return false;\n}\n\n\nbool SQVM::CMP_OP_RES(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2, int &res)\n{\n    SQInteger r;\n    if(ObjCmp(o1,o2,r)) {\n        switch(op) {\n            case CMP_G: res = (r > 0); return true;\n            case CMP_GE: res = (r >= 0); return true;\n            case CMP_L: res = (r < 0); return true;\n            case CMP_LE: res = (r <= 0); return true;\n            case CMP_3W: res = r; return true;\n        }\n        assert(0);\n    }\n    return false;\n}\n\nbool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)\n{\n    SQInteger r;\n    if(ObjCmp(o1,o2,r)) {\n        switch(op) {\n            case CMP_G: res = (r > 0); return true;\n            case CMP_GE: res = (r >= 0); return true;\n            case CMP_L: res = (r < 0); return true;\n            case CMP_LE: res = (r <= 0); return true;\n            case CMP_3W: res = r; return true;\n        }\n        assert(0);\n    }\n    return false;\n}\n\nbool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)\n{\n    char buf[48];\n\n    switch(sq_type(o)) {\n    case OT_STRING:\n        res = o;\n        return true;\n    case OT_FLOAT: {\n            int i = scsprintf(buf, sizeof(buf), \"%g\", _float(o));\n            for (; i >= 0; i--)\n                if (buf[i] == ',')\n                    buf[i] = '.';\n        }\n        break;\n    case OT_INTEGER:\n        scsprintf(buf, sizeof(buf), _PRINT_INT_FMT, _integer(o));\n        break;\n    case OT_BOOL:\n        scsprintf(buf, sizeof(buf), _integer(o) ? \"true\" : \"false\");\n        break;\n    case OT_NULL:\n        scsprintf(buf, sizeof(buf), \"null\");\n        break;\n    case OT_TABLE:\n    case OT_USERDATA:\n    case OT_INSTANCE:\n        if(_delegable(o)->_delegate) {\n            SQObjectPtr closure;\n            if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) {\n                Push(o);\n                if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {\n                    if(sq_type(res) == OT_STRING)\n                        return true;\n                }\n                else {\n                    return false;\n                }\n            }\n        }\n    default:\n        scsprintf(buf, sizeof(buf), \"(%s : 0x%p)\", GetTypeName(o), (void*)_rawval(o));\n    }\n    res = SQString::Create(_ss(this), buf);\n    return true;\n}\n\n\nbool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)\n{\n    SQObjectPtr a, b;\n    if(!ToString(str, a)) return false;\n    if(!ToString(obj, b)) return false;\n    SQInteger l = _string(a)->_len , ol = _string(b)->_len;\n    char *s = _sp(l + ol + 1);\n    memcpy(s, _stringval(a), l);\n    memcpy(s + l, _stringval(b), ol);\n    dest = SQString::Create(_ss(this), _spval, l + ol);\n    return true;\n}\n\nbool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)\n{\n    if(is_delegable(obj1) && _delegable(obj1)->_delegate) {\n        SQObjectPtr closure;\n        if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) {\n            Push(obj1);\n            return CallMetaMethod(closure,MT_TYPEOF,1,dest);\n        }\n    }\n    dest = SQString::Create(_ss(this),GetTypeName(obj1));\n    return true;\n}\n\nbool SQVM::Init(SQVM *friendvm, SQInteger stacksize)\n{\n    _stack.resize(stacksize + STACK_GROW_THRESHOLD);\n    _alloccallsstacksize = 4;\n    _callstackdata.resize(_alloccallsstacksize);\n    _callsstacksize = 0;\n    _callsstack = &_callstackdata[0];\n    _stackbase = 0;\n    _top = 0;\n    if(!friendvm) {\n        _roottable = SQTable::Create(_ss(this), 0);\n        sq_base_register(this);\n    }\n    else {\n        _roottable = friendvm->_roottable;\n        _errorhandler = friendvm->_errorhandler;\n        _debughook = friendvm->_debughook;\n        _debughook_native = friendvm->_debughook_native;\n        _debughook_closure = friendvm->_debughook_closure;\n        _compile_line_hook = friendvm->_compile_line_hook;\n        _current_thread = friendvm->_current_thread;\n        _get_current_thread_id_func = friendvm->_get_current_thread_id_func;\n        _sq_call_hook = friendvm->_sq_call_hook;\n        _watchdog_hook = friendvm->_watchdog_hook;\n    }\n\n\n    return true;\n}\n\n\ntemplate <bool debughookPresent>\nbool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)\n{\n    SQFunctionProto *func = closure->_function;\n\n    SQInteger paramssize = func->_nparameters;\n    const SQInteger newtop = stackbase + func->_stacksize;\n    SQInteger nargs = args;\n    if(func->_varparams)\n    {\n        paramssize--;\n        if (nargs < paramssize) {\n            Raise_Error(\"wrong number of parameters passed to '%s' %s:%d (%d passed, at least %d required)\",\n              sq_type(func->_name) == OT_STRING ? _stringval(func->_name) : \"unknown\",\n              sq_type(func->_sourcename) == OT_STRING ? _stringval(func->_sourcename) : \"unknown\",\n              int(func->_nlineinfos > 0 ? func->_lineinfos->_first_line : 0),\n              (int)nargs, (int)paramssize);\n            return false;\n        }\n\n        //dumpstack(stackbase);\n        SQInteger nvargs = nargs - paramssize;\n        SQArray *arr = SQArray::Create(_ss(this),nvargs);\n        SQInteger pbase = stackbase+paramssize;\n        SQUnsignedInteger32 mask = func->_param_type_masks ? func->_param_type_masks[paramssize] : ~0u;\n\n        for(SQInteger n = 0; n < nvargs; n++) {\n            if (!check_typemask(sq_type(_stack._vals[pbase]), mask)) {\n                Raise_ParamTypeError(n + paramssize, mask, sq_type(_stack._vals[pbase]),\n                    sq_type(func->_name) == OT_STRING ? _stringval(func->_name) : nullptr);\n                return false;\n            }\n\n            arr->_values[n] = _stack._vals[pbase];\n            _stack._vals[pbase].Null();\n            pbase++;\n\n        }\n        _stack._vals[stackbase+paramssize] = arr;\n        //dumpstack(stackbase);\n    }\n    else if (paramssize != nargs) {\n        SQInteger ndef = func->_ndefaultparams;\n        SQInteger diff;\n        if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) {\n            for(SQInteger n = ndef - diff; n < ndef; n++) {\n                _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];\n            }\n        }\n        else {\n            Raise_Error(\"wrong number of parameters passed to '%s' %s:%d (%d passed, %d required)\",\n              sq_type(func->_name) == OT_STRING ? _stringval(func->_name) : \"unknown\",\n              sq_type(func->_sourcename) == OT_STRING ? _stringval(func->_sourcename) : \"unknown\",\n              int(func->_nlineinfos > 0 ? func->_lineinfos->_first_line : 0),\n              (int)nargs, (int)paramssize);\n            return false;\n        }\n    }\n\n    if (SQUnsignedInteger32 *paramTypeMasks = func->_param_type_masks) {\n        SQInteger len = func->_varparams ? paramssize : nargs;\n        for (SQInteger i = 1; i < len; i++) {\n            SQUnsignedInteger32 mask = paramTypeMasks[i];\n            if (!check_typemask(sq_type(_stack._vals[stackbase + i]), mask)) {\n                Raise_ParamTypeError(i, mask, sq_type(_stack._vals[stackbase + i]),\n                    sq_type(func->_name) == OT_STRING ? _stringval(func->_name) : nullptr);\n                return false;\n            }\n        }\n    }\n\n\n    if(closure->_env) {\n        _stack._vals[stackbase] = closure->_env->_obj;\n    }\n\n    if(!EnterFrame(stackbase, newtop, tailcall)) return false;\n\n    ci->_closure  = closure;\n    ci->_literals = func->_literals;\n    ci->_ip       = func->_instructions;\n    ci->_target   = (SQInt32)target;\n    if constexpr (debughookPresent)\n    {\n        if (_debughook) {\n            CallDebugHook('c');\n        }\n    }\n\n    if (closure->_function->_bgenerator) {\n        SQFunctionProto *f = closure->_function;\n        SQGenerator *gen = SQGenerator::Create(_ss(this), closure);\n        if(!gen->Yield(this,f->_stacksize))\n            return false;\n        SQObjectPtr temp;\n        Return<debughookPresent>(1, target, temp);\n        _stack._vals[_stackbase + target] = gen;\n    }\n\n\n    return true;\n}\n\ntemplate <bool debughookPresent>\nbool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)\n{\n    SQBool    _isroot      = ci->_root;\n    SQInteger callerbase   = _stackbase - ci->_prevstkbase;\n    if constexpr (debughookPresent)\n    {\n        if (_debughook) {\n            for(SQInteger i=0; i<ci->_ncalls; i++) {\n                CallDebugHook('r');\n            }\n        }\n    }\n\n    SQObjectPtr *dest;\n    if (_isroot) {\n        dest = &(retval);\n    } else if (ci->_target == -1) {\n        dest = NULL;\n    } else {\n        dest = &_stack._vals[callerbase + ci->_target];\n    }\n    if (dest) {\n        if(_arg0 != 0xFF) {\n            *dest = _stack._vals[_stackbase+_arg1];\n        }\n        else {\n            dest->Null();\n        }\n    }\n    LeaveFrame();\n\n    return _isroot ? true : false;\n}\n\n#define _RET_ON_FAIL(exp) { if(!exp) return false; }\n\nbool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)\n{\n    SQObjectPtr trg;\n    _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));\n    target = a;\n    a = trg;\n    return true;\n}\n\nbool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix)\n{\n    if (self._flags & SQOBJ_FLAG_IMMUTABLE) {\n        Raise_Error(\"trying to modify immutable '%s'\",GetTypeName(self));\n        return false;\n    }\n    SQObjectPtr tmp, tself = self, tkey = key;\n    SQObjectPtr *__restrict instanceValue = nullptr;\n    if (sq_type(tself) == OT_INSTANCE)\n    {\n        SQInstance*__restrict instance = _instance(tself);\n        const SQClass *__restrict classType = instance->_class;\n        const SQTable::_HashNode *n = classType->_members->_Get(tkey);\n        if (n && _isfield(n->val))\n            instanceValue = instance->_values + _member_idx(n->val);\n        else if (n && _isnativefield(n->val)) {\n            // read -> arith -> write back for native fields\n            instance->GetNativeField(_member_idx(n->val), tmp);\n            _RET_ON_FAIL(ARITH_OP(op, target, tmp, incr))\n            if (!instance->SetNativeField(_member_idx(n->val), target)) {\n                Raise_Error(\"type mismatch in native field assignment\");\n                return false;\n            }\n            if (postfix)\n                target = tmp;\n            return true;\n        }\n    } else if (sq_type(tself) == OT_TABLE) {\n        SQTable::_HashNode *node = _table(tself)->_Get(tkey);\n        if (node)\n            instanceValue = &node->val;\n    } else if (sq_type(tself) == OT_ARRAY){\n        if (sq_isnumeric(key)) {\n           SQArray * __restrict array = _array(tself);\n           uint32_t nidx  = tointeger(tkey);\n           if (nidx < (SQInteger)array->_values.size())\n              instanceValue = &array->_values[nidx];\n        }\n    }\n    if (instanceValue)\n        tmp = _realval(*instanceValue);\n    else\n    {\n        //delegates and OT_USERDATA option. Basically FallbackGet/FallbackSet\n        if (!Get(tself, tkey, tmp, 0)) { return false; }\n    }\n    _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))\n    if (instanceValue)\n        *instanceValue = target;\n    else\n        if (!Set(tself, tkey, target)) { return false; }\n    if (postfix) target = tmp;\n    return true;\n}\n\n#define arg0 (_i_._arg0)\n#define arg1 (_i_._arg1)\n#define sarg1 (((SQInt32)_i_._arg1))\n#define farg1 (_i_._farg1)\n#define arg2 (_i_._arg2)\n#define arg3 (_i_._arg3)\n#define sarg3 ((SQInteger)((signed char)_i_._arg3))\n#define sarg0 ((SQInteger)((signed char)_i_._arg0))\n\nSQRESULT SQVM::Suspend()\n{\n    if (_suspended)\n        return sq_throwerror(this, \"cannot suspend an already suspended vm\");\n    if (_nnativecalls!=2)\n        return sq_throwerror(this, \"cannot suspend through native calls/metamethods\");\n    return SQ_SUSPEND_FLAG;\n}\n\n\n#define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }\n#define _CHECK_FREEZE() { if (o1._flags & SQOBJ_FLAG_IMMUTABLE) { o2._flags |= SQOBJ_FLAG_IMMUTABLE; o3._flags |= SQOBJ_FLAG_IMMUTABLE; } }\nbool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr\n&o3,SQObjectPtr &o4,int exitpos,int &jump)\n{\n    SQInteger nrefidx;\n    switch(sq_type(o1)) {\n    case OT_TABLE:\n        if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);\n        _CHECK_FREEZE();\n        o4 = (SQInteger)nrefidx; _FINISH(1);\n    case OT_ARRAY:\n        if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);\n        _CHECK_FREEZE();\n        o4 = (SQInteger) nrefidx; _FINISH(1);\n    case OT_STRING:\n        if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\n        o4 = (SQInteger)nrefidx; _FINISH(1);\n    case OT_CLASS:\n        if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\n        _CHECK_FREEZE();\n        o4 = (SQInteger)nrefidx; _FINISH(1);\n    case OT_USERDATA:\n    case OT_INSTANCE:\n        if(_delegable(o1)->_delegate) {\n            SQObjectPtr itr;\n            SQObjectPtr closure;\n            if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) {\n                Push(o1);\n                Push(o4);\n                if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {\n                    o4 = o2 = itr;\n                    if(sq_type(itr) == OT_NULL) _FINISH(exitpos);\n                    if(!Get(o1, itr, o3, 0)) {\n                        Raise_Error(\"_nexti returned an invalid idx\");\n                        return false;\n                    }\n                    _CHECK_FREEZE();\n                    _FINISH(1);\n                }\n                else {\n                    return false;\n                }\n            }\n            if ((nrefidx = (_delegable(o1)->_delegate)->Next(false, o4, o2, o3)) == -1)\n              _FINISH(exitpos);\n\n            _instance(o1)->Get(o2, o3);\n            _CHECK_FREEZE();\n            o4 = (SQInteger)nrefidx;\n            _FINISH(1);\n        }\n        break;\n    case OT_GENERATOR:\n        if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos);\n        if(_generator(o1)->_state == SQGenerator::eSuspended) {\n            SQInteger idx = 0;\n            if(sq_type(o4) == OT_INTEGER) {\n                idx = _integer(o4) + 1;\n            }\n            o2 = idx;\n            o4 = idx;\n            _generator(o1)->Resume(this, o3);\n            _FINISH(0);\n        }\n    default:\n        Raise_Error(\"cannot iterate %s\", GetTypeName(o1));\n    }\n    return false;\n}\n#undef _CHECK_FREEZE\n\n#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))\n\n#define SYNC_IP() do { if (ci) ci->_ip = _ip; } while(0)\n#define RELOAD_IP() do { _ip = ci->_ip; RELOAD_STK(); } while(0)\n\n#define SQ_THROW() { SYNC_IP(); goto exception_trap; }\n\n#define _GUARD(exp) { if(!exp) { SQ_THROW();} }\n\nbool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)\n{\n    SQInteger nouters;\n    SQClosure *closure = SQClosure::Create(_ss(this), func);\n    if((nouters = func->_noutervalues)) {\n        for(SQInteger i = 0; i<nouters; i++) {\n            SQOuterVar &v = func->_outervalues[i];\n            switch(v._type){\n            case otLOCAL:\n                FindOuter(closure->_outervalues[i], &_stack._vals[_stackbase + _integer(v._src)]);\n                break;\n            case otOUTER:\n                closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)];\n                break;\n            }\n        }\n    }\n    SQInteger ndefparams;\n    if((ndefparams = func->_ndefaultparams)) {\n        for(SQInteger i = 0; i < ndefparams; i++) {\n            SQInteger spos = func->_defaultparams[i];\n            closure->_defaultparams[i] = _stack._vals[_stackbase + spos];\n\n            #if SQ_RUNTIME_TYPE_CHECK\n            int nparams = func->_nparameters;\n            int begin = nparams - ndefparams;\n            if (SQUnsignedInteger32 *paramTypeMasks = func->_param_type_masks)\n                if (!check_typemask(sq_type(closure->_defaultparams[i]), paramTypeMasks[begin + i])) {\n                    char buf[160];\n                    sq_stringify_type_mask(buf, sizeof(buf), paramTypeMasks[begin + i]);\n                    Raise_Error(\"default param (%d) type '%s' differs from the declared type '%s'\",\n                        int(i + begin), GetTypeName(closure->_defaultparams[i]), buf);\n                    return false;\n                }\n            #endif\n        }\n    }\n    target = closure;\n    return true;\n\n}\n\n\nbool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass)\n{\n    SQClass *base = NULL;\n    if (baseclass != -1) {\n        if (sq_type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) {\n            Raise_Error(\"trying to inherit from a %s\",GetTypeName(_stack._vals[_stackbase+baseclass]));\n            return false;\n        }\n        base = _class(_stack._vals[_stackbase + baseclass]);\n    }\n    SQClass *cls = SQClass::Create(this, base);\n    if (!cls)\n        return false;\n    target = cls;\n    return true;\n}\n\nbool SQVM::IsEqual(const SQObject &o1,const SQObject &o2)\n{\n    SQObjectType t1 = sq_type(o1), t2 = sq_type(o2);\n    if(t1 == t2) {\n        if (t1 == OT_FLOAT)\n            return (_float(o1) == _float(o2));\n        else\n            return (_rawval(o1) == _rawval(o2));\n    }\n    else {\n        if(sq_isnumeric(o1) && sq_isnumeric(o2))\n            return (tofloat(o1) == tofloat(o2));\n        else\n            return false;\n    }\n}\n\nbool SQVM::IsFalse(const SQObject &o)\n{\n    return _rawval(o) == 0 ||\n        (sq_type(o) == OT_FLOAT && _float(o) == SQFloat(0.0)) ||\n        (sq_type(o) == OT_INTEGER && _integer(o) == 0); // should be optimized out if _SQ64 && sizeof(SQInteger) == 8\n}\n\nbool SQVM::IsInstanceOf(const SQObject &obj, const SQClass *cls)\n{\n    if (sq_type(obj) == OT_INSTANCE) {\n        return _instance(obj)->InstanceOf(cls);\n    }\n    else if (cls->_is_builtin_type) {\n        SQObjectType obj_type = sq_type(obj);\n\n        // Special handling for closures and native closures - both map to Function class\n        if (cls->_builtin_type_id == OT_CLOSURE && (obj_type == OT_CLOSURE || obj_type == OT_NATIVECLOSURE))\n            return true;\n\n        return (obj_type == cls->_builtin_type_id);\n    }\n    else\n        return false;\n}\n\n#if defined(SQ_USED_MEM_COUNTER_DECL)\n  SQ_USED_MEM_COUNTER_DECL\n#endif\n\n\n#if SQ_WATCHDOG_ENABLED\n#define SQ_WATCHDOG_CHECK() \\\n    do { \\\n        if (_watchdog_hook && ++watchdogCounter > WATCHDOG_RAREFICATION) { \\\n            watchdogCounter = 0; \\\n            if (!_watchdog_hook(this, false)) { \\\n                Raise_Error(\"Watchdog: too long execution of quirrel script\"); \\\n                SQ_THROW(); \\\n            } \\\n        } \\\n    } while (0)\n#else\n#define SQ_WATCHDOG_CHECK()\n#endif\n\n\nextern SQInstructionDesc g_InstrDesc[];\n\ntemplate <bool debughookPresent>\nbool SQVM::Execute(const SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool invoke_err_handler,ExecutionType et)\n{\n    ValidateThreadAccess();\n\n    #if SQ_CHECK_THREAD >= SQ_CHECK_THREAD_LEVEL_FAST\n    if (_get_current_thread_id_func)\n    {\n      if (!_nnativecalls)\n        _current_thread = _get_current_thread_id_func();\n      else\n        assert(_current_thread == _get_current_thread_id_func());\n    }\n    #endif\n\n    SQUnsignedInteger32 watchdogCounter = 0;\n    (void)watchdogCounter;\n\n    if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(\"Native stack overflow\"); return false; }\n    _nnativecalls++;\n    AutoDec ad(&_nnativecalls);\n    SQInteger traps = 0;\n    SQInteger prevci_idx = _callsstacksize;\n\n    switch(et) {\n        case ET_CALL: {\n            temp_reg = closure;\n            if(!StartCall<debughookPresent>(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) {\n                //call the handler if there are no calls in the stack, if not relies on the previous node\n                if(ci == NULL) CallErrorHandler(_lasterror);\n                return false;\n            }\n            if(_callsstacksize == prevci_idx) {\n                outres = _stack._vals[_stackbase + (_top-nargs)];\n                return true;\n            }\n            ci->_root = SQTrue;\n                      }\n            break;\n        case ET_RESUME_GENERATOR:\n            if(!_generator(closure)->Resume(this, outres)) {\n                return false;\n            }\n            ci->_root = SQTrue;\n            traps += ci->_etraps;\n            break;\n        case ET_RESUME_VM:\n        case ET_RESUME_THROW_VM:\n            traps = _suspended_traps;\n            ci->_root = _suspended_root;\n            _suspended = SQFalse;\n            if(et  == ET_RESUME_THROW_VM) { goto exception_trap; }\n            break;\n    }\n\nexception_restore:\n    //\n    {\n        int prevLineNum = -1;\n        int lineHint = 0;\n        SQInstruction *_ip = ci->_ip;\n        SQObjectPtr *_stkbase = _stack._vals + _stackbase;\n\n        for(;;)\n        {\n            if constexpr (debughookPresent) {\n                if (_debughook) {\n                    SQFunctionProto *funcProto = _closure(ci->_closure)->_function;\n                    bool isStepPoint;\n                    int curLineNum = funcProto->GetLine(_ip, &lineHint, &isStepPoint);\n                    if (curLineNum != prevLineNum) {\n                        prevLineNum = curLineNum;\n                        if (isStepPoint) {\n                            SYNC_IP();\n                            CallDebugHook('l', curLineNum);\n                            RELOAD_IP();\n                        }\n                    }\n                }\n            }\n\n            const SQInstruction &_i_ = *_ip++;\n            //dumpstack(_stackbase);\n            //printf(\"\\n%s[%d] %s %d %d %d %d\\n\",_stringval(_closure(ci->_closure)->_function->_name), ci->_ip-1-_closure(ci->_closure)->_function->_instructions,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);\n            switch(_i_.op)\n            {\n            case _OP_DATA_NOP: continue;\n            case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;\n            case _OP_LOADINT:\n#ifndef _SQ64\n                TARGET = (SQInteger)arg1; continue;\n#else\n                TARGET = (SQInteger)((SQInt32)arg1); continue;\n#endif\n            case _OP_LOADFLOAT: TARGET = farg1; continue;\n            case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;\n            case _OP_TAILCALL:{\n                SQObjectPtr &t = STK(arg1);\n                if (sq_type(t) == OT_CLOSURE\n                    && (!_closure(t)->_function->_bgenerator)){\n                    SQObjectPtr clo = t;\n                    SQInteger last_top = _top;\n                    if(_openouters) CloseOuters(_stkbase);\n                    for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);\n                    SYNC_IP();\n                    _GUARD(StartCall<debughookPresent>(_closure(clo), ci->_target, arg3, _stackbase, true));\n                    if (last_top >= _top) {\n                      _top = last_top;\n                    }\n                    RELOAD_IP();\n                    continue;\n                }\n                              }\n            case _OP_CALL:\n            case _OP_NULLCALL:\n            {\n                    SQObjectPtr clo = STK(arg1);\n                    int tgt0 = arg0 == 255 ? -1 : arg0;\n                    bool nullcall = (_i_.op == _OP_NULLCALL);\n                    switch (sq_type(clo)) {\n                    case OT_CLOSURE:\n                        SYNC_IP();\n                        _GUARD(StartCall<debughookPresent>(_closure(clo), tgt0, arg3, _stackbase+arg2, false));\n                        RELOAD_IP();\n                        continue;\n                    case OT_NATIVECLOSURE: {\n                        bool suspend;\n                        bool tailcall;\n                        SYNC_IP();\n                        _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo, tgt0, suspend, tailcall));\n                        RELOAD_STK();\n                        if(suspend){\n                            _suspended = SQTrue;\n                            _suspended_target = tgt0;\n                            _suspended_root = ci->_root;\n                            _suspended_traps = traps;\n                            outres = clo;\n                            SYNC_IP();\n                            return true;\n                        }\n                        if(tgt0 != -1 && !tailcall) {\n                            STK(tgt0) = clo;\n                        }\n                        RELOAD_IP();\n                                           }\n                        continue;\n                    case OT_CLASS:{\n                        SQClass *theclass = _class(clo);\n\n                        if (theclass->_is_builtin_type) {\n                            // For built-in types, call the constructor directly (no instance creation)\n                            SQObjectPtr ctor;\n                            if (!theclass->GetConstructor(ctor)) {\n                                Raise_Error(\"built-in type '%s' has no constructor\", IdType2Name(theclass->_builtin_type_id));\n                                SQ_THROW();\n                            }\n\n                            assert(sq_type(ctor) == OT_NATIVECLOSURE);\n                            SQInteger stkbase = _stackbase+arg2;\n                            _stack._vals[stkbase].Null();  // 'this'\n                            bool dummy;\n                            SYNC_IP();\n                            _GUARD(CallNative(_nativeclosure(ctor), arg3, stkbase, ctor, tgt0, dummy, dummy));\n                            RELOAD_STK();\n                            if (tgt0 != -1) {\n                                STK(tgt0) = ctor;\n                            }\n                        } else {\n                            // Regular script class - create instance then call constructor\n                            SQObjectPtr inst, ctor;\n                            _GUARD(CreateClassInstance(theclass,inst,ctor));\n                            if(tgt0 != -1) {\n                                STK(tgt0) = inst;\n                            }\n                            SQInteger stkbase;\n                            switch(sq_type(ctor)) {\n                                case OT_CLOSURE:\n                                    stkbase = _stackbase+arg2;\n                                    _stack._vals[stkbase] = inst;\n                                    SYNC_IP();\n                                    _GUARD(StartCall<debughookPresent>(_closure(ctor), -1, arg3, stkbase, false));\n                                    RELOAD_IP();\n                                    break;\n                                case OT_NATIVECLOSURE:\n                                    bool dummy;\n                                    stkbase = _stackbase+arg2;\n                                    _stack._vals[stkbase] = inst;\n                                    SYNC_IP();\n                                    _GUARD(CallNative(_nativeclosure(ctor), arg3, stkbase, ctor, -1, dummy, dummy));\n                                    RELOAD_STK();\n                                    break;\n                                case OT_NULL:\n                                    if (arg3 > 1) {\n                                        Raise_Error(\"cannot call default constructor with arguments\");\n                                        SQ_THROW();\n                                    }\n                                    break;\n                                default:\n                                    // cannot happen, but still...\n                                    assert(!\"invalid constructor type\");\n                                    Raise_Error(\"invalid constructor type %s\", IdType2Name(sq_type(ctor)));\n                                    SQ_THROW();\n                                    break;\n                            }\n                        }\n                        }\n                        break;\n                    case OT_TABLE:\n                    case OT_USERDATA:\n                    case OT_INSTANCE:{\n                        SQObjectPtr mmclosure;\n                        if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,mmclosure)) {\n                            Push(clo);\n                            for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));\n                            if(!CallMetaMethod(mmclosure, MT_CALL, arg3+1, clo)) SQ_THROW();\n                            RELOAD_STK();\n                            if(tgt0 != -1) {\n                                STK(tgt0) = clo;\n                            }\n                            break;\n                        }\n\n                        //Raise_Error(\"attempt to call '%s'\", GetTypeName(clo));\n                        //SQ_THROW();\n                      }\n                    default:\n                        if (nullcall && sq_type(clo)==OT_NULL) {\n                            if(tgt0 != -1) {\n                                STK(tgt0).Null();\n                            }\n                        } else {\n                            Raise_Error(\"attempt to call '%s'\", GetTypeName(clo));\n                            SQ_THROW();\n                        }\n                    }\n                }\n                  continue;\n            case _OP_PREPCALL:\n            case _OP_PREPCALLK: {\n                    SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);\n                    SQObjectPtr &o = STK(arg2);\n                    if (!Get(o, key, temp_reg,0)) {\n                        SQ_THROW();\n                    }\n                    STK(arg3) = o;\n                    _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                }\n                continue;\n            case _OP_GETK:{\n                SQUnsignedInteger getFlagsByOp = (arg3 & OP_GET_FLAG_ALLOW_TYPE_METHODS) ? 0 : GET_FLAG_NO_TYPE_METHODS;\n                if (arg3 & OP_GET_FLAG_TYPE_METHODS_ONLY)\n                    getFlagsByOp |= GET_FLAG_TYPE_METHODS_ONLY;\n                if (arg3 & OP_GET_FLAG_NO_ERROR) {\n                    SQInteger fb = GetImpl(STK(arg2), ci->_literals[arg1], temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | getFlagsByOp);\n                    if (fb == SLOT_STATUS_OK) {\n                        _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                    } else if (fb == SLOT_STATUS_ERROR) {\n                        SQ_THROW();\n                    } else if (!(arg3 & OP_GET_FLAG_KEEP_VAL)) {\n                        TARGET.Null();\n                    }\n                } else {\n                    if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, getFlagsByOp)) {\n                        SQ_THROW();\n                    }\n                    _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                }\n                continue;\n            }\n            case _OP_MOVE: TARGET = STK(arg1); continue;\n            case _OP_NEWSLOT:\n                _GUARD(NewSlot(STK(arg2), STK(arg1), STK(arg3), false));\n                if(arg0 != 0xFF) TARGET = STK(arg3);\n                continue;\n            case _OP_NEWSLOTK:\n                _GUARD(NewSlot(STK(arg2), ci->_literals[arg1], STK(arg3), false));\n                if(arg0 != 0xFF) TARGET = STK(arg3);\n                continue;\n            case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\n            case _OP_SET_LITERAL: {\n                uint64_t *__restrict hintP = ((uint64_t*__restrict )(_ip++)); //-V1032\n                uint64_t hint = *hintP;\n                const SQObjectPtr &from = STK(arg2), &__restrict key = ci->_literals[arg1], &val = STK(arg3);\n                auto sqType = sq_type(from);\n                if (sqType == OT_INSTANCE && !(from._flags & SQOBJ_FLAG_IMMUTABLE))//for wrong access go to normal Set\n                {\n                    SQInstance *__restrict instance = _instance(from);\n                    const SQClass *__restrict classType = instance->_class;\n                    uint32_t memberIdx;\n                    //todo:key is string literal, so we better store it's index in literal, or it's hash, rather than use SQObjectPtr from generated previous LOAD command\n                    const SQTable *__restrict members = classType->_members;\n                    //some class ID. Ideally it is 32bit key, which is correct only when locked\n                    //we can achieve that. When unlocked - class has _locked == 0. When _locked != 0, it is class Index+1 in VM (can be just some hash_set, or even just 32 bit hash from pointer)\n                    //however, right now we rely on 40 bit hint - which is class pointer. still working good\n                    const uint64_t classTypeId = classType->lockedTypeId();\n                    if (SQ_LIKELY(classTypeId && SQClass::classTypeFromHint(hint) == classTypeId))\n                    {\n                        memberIdx = uint32_t(hint>>uintptr_t(SQClass::CLASS_BITS));\n                        //todo: validate cache in debug build!\n                        //val = hintedMemberIdx ? members->_nodex + hintedMemberIdx-1 : nullptr;\n                    } else\n                    {\n                        if (!members->GetStrToInt(key, memberIdx)) {\n                            memberIdx = 0u;\n                        } else {\n                            uint32_t kind = memberIdx & MEMBER_KIND_MASK;\n                            if (kind != MEMBER_TYPE_FIELD && kind != MEMBER_TYPE_NATIVE_FIELD)\n                                memberIdx = 0u;\n                        }\n                        //store hint back\n                        *hintP = ((uint64_t(memberIdx)<<uintptr_t(SQClass::CLASS_BITS))|classTypeId);\n                    }\n                    if (SQ_LIKELY(memberIdx != 0u))\n                    {\n                        if (_isfieldi(memberIdx))\n                            instance->SetMemberField(memberIdx, val);\n                        else if (SQ_UNLIKELY(!instance->SetNativeField(_member_idxi(memberIdx), val))) {\n                            Raise_Error(\"type mismatch in native field assignment\");\n                            SQ_THROW();\n                        }\n                    } else {\n                        SQInteger fb = FallBackSet(from,key,val);\n                        if (SQ_UNLIKELY(fb != SLOT_STATUS_OK)) {\n                            if (fb == SLOT_STATUS_NO_MATCH)\n                                Raise_IdxError(key);\n                            SQ_THROW();\n                        }\n                    }\n                }\n                else if (sqType == OT_TABLE &&  !(from._flags & SQOBJ_FLAG_IMMUTABLE))//for wrong access go to normal Set\n                {\n                    SQTable *__restrict tbl = _table(from);\n                    uint64_t cid = tbl->_classTypeId;\n                    SQTable::_HashNode *node = nullptr;\n\n                    if (SQ_LIKELY(cid)) {\n                        if (SQ_LIKELY((cid & TBL_CLASS_CLASS_MASK) == (hint & TBL_CLASS_CLASS_MASK))) {\n                            node = tbl->GetNodeFromTypeHint(hint, key);\n                        } else {\n                            node = tbl->_GetStr(_rawval(key), _string(key)->_hash & tbl->_numofnodes_minus_one);\n                            if (SQ_LIKELY(node)) {\n                                size_t nodeIdx = node - tbl->_nodes;\n                                assert(nodeIdx <= TBL_CLASS_TYPE_MEMBER_MASK);\n                                *hintP = ((cid & TBL_CLASS_CLASS_MASK) | nodeIdx);\n                            }\n                        }\n                    }\n                    if (node) {\n                        node->val = val;\n                    } else {\n                        // fallback no unoptimized version\n                        if (!Set(from, key, val)) { SQ_THROW(); }\n                    }\n                }\n                else // default implementation\n                {\n                    if (!Set(from, key, val)) { SQ_THROW(); }\n                }\n                if (arg0 != 0xFF) TARGET = val;\n                continue;\n            }\n            case _OP_SET:\n                if (!Set(STK(arg2), STK(arg1), STK(arg3))) { SQ_THROW(); }\n                if (arg0 != 0xFF) TARGET = STK(arg3);\n                continue;\n            case _OP_SETI: case _OP_SETK:\n                if (!Set(STK(arg2), _i_.op == _OP_SETI ? SQObjectPtr(SQInteger(arg1)) : ci->_literals[arg1], STK(arg3))) { SQ_THROW(); }\n                if (arg0 != 0xFF) TARGET = STK(arg3);\n                continue;\n            case _OP_GET_LITERAL:{\n                uint64_t *__restrict hintP = ((uint64_t*__restrict )(_ip++)); //-V1032\n                uint64_t hint = *hintP;\n                const SQUnsignedInteger getFlagsByOp = GET_FLAG_NO_TYPE_METHODS;\n                const SQObjectPtr &__restrict from = STK(arg2), &__restrict key = ci->_literals[arg1];\n                auto sqType = sq_type(from);\n\n                //Or we can disallow table access by table.key\n                if (sqType == OT_INSTANCE)\n                {\n                    const SQInstance *__restrict instance = _instance(from);\n                    const SQClass *__restrict classType = instance->_class;\n                    uint32_t memberIdx;\n                    //todo:key is string literal, so we better store it's index in literal, or it's hash, rather than use SQObjectPtr from generated previous LOAD command\n                    const SQTable *__restrict members = classType->_members;\n                    //some class ID. Ideally it is 32bit key, which is correct only when locked\n                    //we can achieve that. When unlocked - class has _locked == 0. When _locked != 0, it is class Index+1 in VM (can be just some hash_set, or even just 32 bit hash from pointer)\n                    //however, right now we rely on 40 bit hint - which is class pointer. still working good\n                    const uint64_t classTypeId = classType->lockedTypeId();\n                    if (SQ_LIKELY(classTypeId && SQClass::classTypeFromHint(hint) == classTypeId))\n                    {\n                        memberIdx = uint32_t(hint>>uintptr_t(SQClass::CLASS_BITS));\n                        //todo: validate cache in debug build!\n                        //val = hintedMemberIdx ? members->_nodex + hintedMemberIdx-1 : nullptr;\n                    } else\n                    {\n                        //this is optimized version, can be just memberIdx = members->Get(key, tmp_reg) ? _integer(tmp_reg) : 0u;\n                        if (!members->GetStrToInt(key, memberIdx))\n                            memberIdx = 0u;\n                        //store hint back\n                        *hintP = ((uint64_t(memberIdx)<<uintptr_t(SQClass::CLASS_BITS))|classTypeId);\n                    }\n                    if (SQ_LIKELY(memberIdx != 0u))\n                    {\n                        instance->GetMember(memberIdx, temp_reg);\n                    } else {\n                        SQInteger fb = FallBackGet(from,key,temp_reg);\n                        if (SQ_UNLIKELY(fb != SLOT_STATUS_OK)) {\n                            if (fb == SLOT_STATUS_NO_MATCH)\n                                Raise_IdxError(key);\n                            SQ_THROW();\n                        }\n                    }\n                    propagate_immutable(from, temp_reg);\n                }\n                else if (sqType == OT_TABLE)\n                {\n                    SQTable *__restrict tbl = _table(from);\n                    uint64_t cid = tbl->_classTypeId;\n                    SQTable::_HashNode *node = nullptr;\n\n                    if (SQ_LIKELY(cid)) {\n                        if (SQ_LIKELY((cid & TBL_CLASS_CLASS_MASK) == (hint & TBL_CLASS_CLASS_MASK))) {\n                            node = tbl->GetNodeFromTypeHint(hint, key);\n                        } else {\n                            node = tbl->_GetStr(_rawval(key), _string(key)->_hash & tbl->_numofnodes_minus_one);\n                            if (SQ_LIKELY(node)) {\n                                size_t nodeIdx = node - tbl->_nodes;\n                                assert(nodeIdx <= TBL_CLASS_TYPE_MEMBER_MASK);\n                                *hintP = ((cid & TBL_CLASS_CLASS_MASK) | nodeIdx);\n                            }\n                        }\n                    }\n                    if (node) {\n                        temp_reg = _realval(node->val);\n                        propagate_immutable(from, temp_reg);\n                    }\n                    else {\n                        // fallback no unoptimized version\n                        if (!Get(from, key, temp_reg, getFlagsByOp)) {\n                            SQ_THROW();\n                        }\n                    }\n                }\n                else\n                {\n                    if (!Get(from, key, temp_reg, getFlagsByOp)) {\n                        SQ_THROW();\n                    }\n                }\n                _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                continue;\n            }\n            case _OP_GET:{\n                SQUnsignedInteger getFlagsByOp = (arg3 & OP_GET_FLAG_ALLOW_TYPE_METHODS) ? 0 : GET_FLAG_NO_TYPE_METHODS;\n                if (arg3 & OP_GET_FLAG_TYPE_METHODS_ONLY)\n                    getFlagsByOp |= GET_FLAG_TYPE_METHODS_ONLY;\n                if (arg3 & OP_GET_FLAG_NO_ERROR) {\n                    SQInteger fb = GetImpl(STK(arg2), STK(arg1), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | getFlagsByOp);\n                    if (fb == SLOT_STATUS_OK) {\n                        _Swap(TARGET,temp_reg);\n                    } else if (fb == SLOT_STATUS_ERROR) {\n                        SQ_THROW();\n                    } else if (!(arg3 & OP_GET_FLAG_KEEP_VAL)) {\n                        TARGET.Null();\n                    }\n                } else {\n                    if (!Get(STK(arg2), STK(arg1), temp_reg, getFlagsByOp)) {\n                        SQ_THROW();\n                    }\n                    _Swap(TARGET,temp_reg);//TARGET = temp_reg;\n                }\n                continue;\n            }\n            case _OP_EQ:\n                TARGET = IsEqual(STK(arg2),COND_LITERAL);\n                continue;\n            case _OP_NE:\n                TARGET = !IsEqual(STK(arg2),COND_LITERAL);\n                continue;\n            case _OP_ADD:\n              _ARITH_(+,TARGET,STK(arg2),STK(arg1));\n              continue;\n            case _OP_ADDI: {SQObjectPtr ai((SQInteger)arg1); _ARITH_(+,TARGET,STK(arg2), ai); continue;}\n            case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1)); continue;\n            case _OP_MOD: _GUARD(ARITH_OP('%',TARGET,STK(arg2),STK(arg1))); continue;\n            case _OP_BITW:  _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;\n            case _OP_RETURN:\n                SQ_WATCHDOG_CHECK();\n                if((ci)->_generator) {\n                    (ci)->_generator->Kill();\n                }\n                if(Return<debughookPresent>(arg0, arg1, temp_reg)){\n                    assert(traps==0);\n                    //outres = temp_reg;\n                    _Swap(outres,temp_reg);\n                    return true;\n                }\n                RELOAD_IP();\n                continue;\n            case _OP_LOADNULLS:{ SQInt32 n=arg1-1; assert(n>=0); do { STK(arg0+n).Null(); } while (--n >= 0); }continue;\n            case _OP_LOADROOT:\n                TARGET = _roottable;\n                continue;\n            case _OP_LOADBOOL: TARGET = arg1?true:false; continue;\n            case _OP_LOADCALLEE:\n            TARGET = ci->_closure;\n            if (arg2)\n            {\n                STK(arg2) = STK(arg3);\n            }\n            continue;\n            case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;\n            case _OP_JMP: _ip += sarg1; continue;\n            case _OP_JCMP: {\n                int r;\n                const uint8_t uArg3 = arg3;\n                _GUARD(CMP_OP_RES((CmpOP)(uArg3&7),STK(arg2),STK(arg0),r));\n                if(uint8_t(bool(r)) == (uArg3>>3)) {\n                    SQ_WATCHDOG_CHECK();\n                    _ip+=(sarg1);\n                }\n                }\n                continue;\n            case _OP_JCMPK: {\n                int r;\n                const uint8_t uArg3 = arg3;\n                _GUARD(CMP_OP_RES((CmpOP)(uArg3&7),STK(arg2),ci->_literals[arg0],r));\n                if(uint8_t(bool(r)) == (uArg3>>3)) {\n                    SQ_WATCHDOG_CHECK();\n                    _ip+=(sarg1);\n                }\n                }\n                continue;\n            case _OP_JCMPI: {\n                int r;\n                //todo: optimize comparison with int\n                const uint8_t uArg3 = arg3;\n                _GUARD(CMP_OP_RESI((CmpOP)(uArg3&7),STK(arg2), (SQInteger)sarg1, r));\n                if(uint8_t(bool(r)) == (uArg3>>3)) {\n                    SQ_WATCHDOG_CHECK();\n                    _ip+=(sarg0);\n                }\n                }\n                continue;\n            case _OP_JCMPF: {\n                int r;\n                //todo: optimize comparison with float\n                const uint8_t uArg3 = arg3;\n                _GUARD(CMP_OP_RESF((CmpOP)(uArg3&7),STK(arg2), farg1, r));\n                if(uint8_t(bool(r)) == (uArg3>>3)) {\n                    SQ_WATCHDOG_CHECK();\n                    _ip+=(sarg0);\n                }\n                }\n                continue;\n            case _OP_JZ: {\n              SQ_WATCHDOG_CHECK();\n              if(uint8_t(IsFalse(STK(arg0))) != arg2) {\n                  _ip+=(sarg1);\n              }\n            } continue;\n            case _OP_GETOUTER: {\n                SQClosure *cur_cls = _closure(ci->_closure);\n                SQOuter *otr = _outer(cur_cls->_outervalues[arg1]);\n                TARGET = *(otr->_valptr);\n                if (arg2)\n                    STK(arg2) = STK(arg3);\n                }\n            continue;\n            case _OP_SETOUTER: {\n                SQClosure *cur_cls = _closure(ci->_closure);\n                SQOuter   *otr = _outer(cur_cls->_outervalues[arg1]);\n                *(otr->_valptr) = STK(arg2);\n                if(arg0 != 0xFF) {\n                    TARGET = STK(arg2);\n                }\n                }\n            continue;\n            case _OP_NEWOBJ:\n                switch(arg3) {\n                    case NEWOBJ_TABLE: TARGET = SQTable::Create(_ss(this), arg1 ? arg1 + 1 : 0); continue;\n                    case NEWOBJ_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\n                    case NEWOBJ_CLASS: _GUARD(CLASS_OP(TARGET,arg1)); continue;\n                    default: assert(0); continue;\n                }\n            case _OP_APPENDARRAY:\n                {\n                    // No need to check for immutability here since it is only used for array initialization\n                    SQObject val;\n                    val._unVal.raw = 0;\n                    val._flags = 0;\n                switch(arg2) {\n                case AAT_STACK:\n                    val = STK(arg1); break;\n                case AAT_LITERAL:\n                    val = ci->_literals[arg1]; break;\n                case AAT_INT:\n                    val._type = OT_INTEGER;\n#ifndef _SQ64\n                    val._unVal.nInteger = (SQInteger)arg1;\n#else\n                    val._unVal.nInteger = (SQInteger)((SQInt32)arg1);\n#endif\n                    break;\n                case AAT_FLOAT:\n                    val._type = OT_FLOAT;\n                    val._unVal.fFloat = *((const SQFloat *)&arg1);\n                    break;\n                case AAT_BOOL:\n                    val._type = OT_BOOL;\n                    val._unVal.nInteger = arg1;\n                    break;\n                default: val._type = OT_INTEGER; assert(0); break;\n\n                }\n                _array(STK(arg0))->Append(val); continue;\n                }\n            case _OP_COMPARITH:\n            case _OP_COMPARITH_K: {\n                SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16);\n                _GUARD(DerefInc(arg3, TARGET, STK(selfidx), _i_.op == _OP_COMPARITH_K ? ci->_literals[arg2] : STK(arg2), STK(arg1&0x0000FFFF), false));\n                }\n                continue;\n            case _OP_INC: {\n                SQObjectPtr o(sarg3);\n                _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));\n                } continue;\n            case _OP_INCL: {\n                SQObjectPtr &a = STK(arg1);\n                if(sq_type(a) == OT_INTEGER) {\n                    a._unVal.nInteger = _integer(a) + sarg3;\n                }\n                else {\n                    SQObjectPtr o(sarg3);\n                    _ARITH_(+,a,a,o);\n                }\n                } continue;\n            case _OP_PINC: {\n                SQObjectPtr o(sarg3);\n                _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));\n                } continue;\n            case _OP_PINCL: {\n                SQObjectPtr &a = STK(arg1);\n                if(sq_type(a) == OT_INTEGER) {\n                    TARGET = a;\n                    a._unVal.nInteger = _integer(a) + sarg3;\n                }\n                else {\n                    SQObjectPtr o(sarg3);\n                    _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));\n                }\n                } continue;\n            case _OP_CMP:   _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET))  continue;\n            case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_NO_TYPE_METHODS); continue;\n            case _OP_INSTANCEOF:\n                if (sq_type(STK(arg1)) != OT_CLASS) {\n                    Raise_Error(\"cannot apply instanceof between a %s and a %s\",GetTypeName(STK(arg1)),GetTypeName(STK(arg2)));\n                    SQ_THROW();\n                }\n                TARGET = IsInstanceOf(STK(arg2), _class(STK(arg1)));\n                continue;\n            case _OP_AND:{\n                if(IsFalse(STK(arg2))) {\n                    TARGET = STK(arg2);\n                    _ip += (sarg1);\n                }\n\n                }\n                continue;\n            case _OP_OR:{\n                if(!IsFalse(STK(arg2))) {\n                    TARGET = STK(arg2);\n                    _ip += (sarg1);\n                }\n                }\n                continue;\n            case _OP_NULLCOALESCE:\n                if (!sq_isnull(STK(arg2))) {\n                    TARGET = STK(arg2);\n                    _ip += (sarg1);\n                }\n                continue;\n            case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;\n            case _OP_NOT:{\n                TARGET = IsFalse(STK(arg1));\n            } continue;\n            case _OP_BWNOT:\n                if(sq_type(STK(arg1)) == OT_INTEGER) {\n                    SQInteger t = _integer(STK(arg1));\n                    TARGET = SQInteger(~t);\n                    continue;\n                }\n                Raise_Error(\"attempt to perform a bitwise op on a %s\", GetTypeName(STK(arg1)));\n                SQ_THROW();\n            case _OP_CLOSURE: {\n                SQClosure *c = ci->_closure._unVal.pClosure;\n                SQFunctionProto *fp = c->_function;\n                if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }\n                continue;\n            }\n            case _OP_YIELD:{\n                if(ci->_generator) {\n                    if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);\n                    if (_openouters) CloseOuters(_stkbase);\n                    SYNC_IP();\n                    _GUARD(ci->_generator->Yield(this,arg2));\n                    traps -= ci->_etraps;\n                    if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg;\n                }\n                else { Raise_Error(\"trying to yield a '%s', only generator can be yielded\", GetTypeName(ci->_closure)); SQ_THROW();}\n                if(Return<debughookPresent>(arg0, arg1, temp_reg)){\n                    assert(traps == 0);\n                    outres = temp_reg;\n                    return true;\n                }\n                RELOAD_IP();\n                }\n                continue;\n            case _OP_RESUME:\n                if(sq_type(STK(arg1)) != OT_GENERATOR){ Raise_Error(\"trying to resume a '%s',only genenerator can be resumed\", GetTypeName(STK(arg1))); SQ_THROW();}\n                SYNC_IP();\n                _GUARD(_generator(STK(arg1))->Resume(this, TARGET));\n                traps += ci->_etraps;\n                RELOAD_IP();\n                continue;\n            case _OP_PREFOREACH:{\n                STK(arg2).Null();STK(arg2+1).Null();STK(arg2+2).Null();\n                auto &arg0Stack = STK(arg0);\n                int tojump;\n                SYNC_IP();\n                _GUARD(FOREACH_OP(arg0Stack,STK(arg2),STK(arg2+1),STK(arg2+2),2,tojump));\n                RELOAD_IP();\n                if (tojump == 1)\n                    _ip ++;\n                else if (tojump == 2) // empty\n                    _ip += sarg1;\n                }\n                continue;\n            case _OP_POSTFOREACH:\n                assert(sq_type(STK(arg0)) == OT_GENERATOR);\n                if(_generator(STK(arg0))->_state == SQGenerator::eDead)\n                    _ip += sarg1;\n                continue;\n            case _OP_FOREACH:{\n                const int jumpToBodyOffset = sarg1;\n                auto &arg0Stack = STK(arg0);\n                const bool isGenerator = sq_type(arg0Stack) == OT_GENERATOR;\n                if (isGenerator)\n                    _ip += jumpToBodyOffset - 1;  // so generator will resume at postforeach\n                SYNC_IP();\n                int tojump;\n                _GUARD(FOREACH_OP(arg0Stack,STK(arg2),STK(arg2+1),STK(arg2+2),2,tojump));\n                RELOAD_IP();\n                assert((tojump == 0 && isGenerator) || (tojump != 0 && !isGenerator));\n                if (tojump == 1)\n                    _ip += jumpToBodyOffset;\n                }continue;\n            case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue;\n            case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue;\n            case _OP_PUSHTRAP:{\n                _etraps.push_back(SQExceptionTrap(_top,_stackbase, _ip+arg1, arg0)); traps++;\n                ci->_etraps++;\n                              }\n                continue;\n            case _OP_POPTRAP: {\n                for(SQInteger i = 0; i < arg0; i++) {\n                    _etraps.pop_back(); traps--;\n                    ci->_etraps--;\n                }\n                              }\n                continue;\n            case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\n            case _OP_NEWSLOTA:\n                _GUARD(NewSlot(STK(arg1),STK(arg2),STK(arg3),(arg0&NEW_SLOT_STATIC_FLAG)?true:false));\n                continue;\n            case _OP_GETBASE:{\n                SQClosure *clo = _closure(ci->_closure);\n                if(clo->_base) {\n                    TARGET = clo->_base;\n                }\n                else {\n                    TARGET.Null();\n                }\n                continue;\n            }\n            case _OP_CLOSE:\n                if(_openouters) CloseOuters(&(STK(arg1)));\n                continue;\n            case _OP_PATCH_DOCOBJ: {\n                SQObjectPtr &o = TARGET;\n                SQObjectPtr findKey;\n                SQObjectPtr foundValue;\n                findKey._unVal.raw = arg1;\n                findKey._type = OT_USERPOINTER;\n                SQTable * tbl = _table(_sharedstate->doc_objects);\n                if (tbl->Get(findKey, foundValue)) {\n                    SQObjectPtr replaceWithKey;\n                    replaceWithKey._unVal.pUserPointer = o._unVal.pUserPointer;\n                    replaceWithKey._type = OT_USERPOINTER;\n                    tbl->NewSlot(replaceWithKey, foundValue);\n                    tbl->Remove(findKey);\n                }\n                continue;\n                }\n            case _OP_LOAD_STATIC_MEMO:\n                // _staticmemos[arg1] -> STK(arg0), jump to ((arg2 << 8) + arg3)\n                STK(arg0) = _closure(ci->_closure)->_function->_staticmemos[arg1];\n                _ip += (arg2 << 8) + arg3;  //-V595\n                continue;\n            case _OP_SAVE_STATIC_MEMO: {\n                // STK(arg0) -> _staticmemos[arg1], STK(arg0) -> STK(loadInstr->_arg0),\n                // modify instruction op at -((arg2 << 8) + arg3) to _OP_LOAD_STATIC_MEMO\n                SQObjectPtr & staticmemo = STK(arg0);\n                SQObjectType tp = sq_type(staticmemo);\n                bool isAutoMemo = (arg1 & STATIC_MEMO_AUTO_FLAG) != 0;\n                SQInteger staticIdx = arg1 & STATIC_MEMO_IDX_MASK;\n                if (isAutoMemo && (tp == OT_ARRAY || tp == OT_TABLE || tp == OT_INSTANCE || tp == OT_CLASS)) {\n                    // don't auto-memoize mutable containers - might change observable behavior\n                    // but still copy result to the LOAD instruction's target register if needed\n                    SQInstruction * loadInstr = (_ip - (arg2 << 8) - arg3);\n                    if (loadInstr->_arg0 != arg0)\n                        STK(loadInstr->_arg0) = staticmemo;\n                    continue;\n                }\n                staticmemo._flags |= SQOBJ_FLAG_IMMUTABLE;\n\n                SQObjectPtr & storedStatic = _closure(ci->_closure)->_function->_staticmemos[staticIdx]; //-V595\n                storedStatic = staticmemo;\n\n                if (ISREFCOUNTED(tp)) {\n                #ifdef NO_GARBAGE_COLLECTOR\n                    __AddRef(storedStatic._type, storedStatic._unVal);\n                #else\n                    _ss(this)->_refs_table.AddRef(storedStatic);\n                #endif\n                }\n\n                SQInstruction * loadInstr = (_ip - (arg2 << 8) - arg3);  //-V595\n                if (loadInstr->_arg0 != arg0)\n                    STK(loadInstr->_arg0) = staticmemo;\n                loadInstr->_arg1 = staticIdx; // strip STATIC_MEMO_AUTO_FLAG\n                loadInstr->op = _OP_LOAD_STATIC_MEMO;\n                continue;\n                }\n            case _OP_FREEZE:\n                STK(arg1)._flags |= SQOBJ_FLAG_IMMUTABLE;\n                TARGET = STK(arg1);\n                continue;\n            case _OP_CHECK_TYPE:\n                if (!check_typemask(sq_type(STK(arg0)), arg1)) {\n                    char buf[160];\n                    sq_stringify_type_mask(buf, sizeof(buf), arg1);\n                    Raise_Error(\"type '%s' differs from the declared type '%s'\", GetTypeName(STK(arg0)), buf);\n                    SQ_THROW();\n                }\n                //TARGET = STK(arg2);\n                continue;\n            }\n\n        }\n    }\nexception_trap:\n    {\n        SQObjectPtr currerror = _lasterror;\n//      dumpstack(_stackbase);\n        SQInteger last_top = _top;\n\n        if ((_ss(this)->_notifyallexceptions || (!traps && invoke_err_handler)) && !sq_isnull(currerror))\n            CallErrorHandler(currerror);\n\n        while( ci ) {\n            if(ci->_etraps > 0) {\n                SQExceptionTrap &et = _etraps.top();\n                ci->_ip = et._ip;\n                _top = et._stacksize;\n                _stackbase = et._stackbase;\n                _stack._vals[_stackbase + et._extarget] = currerror;\n                _etraps.pop_back(); traps--; ci->_etraps--;\n                while(last_top >= _top) _stack._vals[last_top--].Null();\n                goto exception_restore;\n            }\n            else if (_debughook) {\n                    //notify debugger of a \"return\"\n                    //even if it really an exception unwinding the stack\n                    for(SQInteger i = 0; i < ci->_ncalls; i++) {\n                        CallDebugHook('r');\n                    }\n            }\n            if(ci->_generator) ci->_generator->Kill();\n            bool mustbreak = ci && ci->_root;\n            LeaveFrame();\n            if(mustbreak) break;\n        }\n\n        _lasterror = currerror;\n        return false;\n    }\n    assert(0);\n    return false;\n}\n\nbool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &__restrict out_inst_res, SQObjectPtr &__restrict constructor)\n{\n    SQInstance *inst = theclass->CreateInstance(this);\n    if (!inst)\n        return false;\n\n    out_inst_res = inst;\n    if (!theclass->GetConstructor(constructor)) {\n        constructor.Null();\n    }\n    return true;\n}\n\nvoid SQVM::CallErrorHandler(const SQObjectPtr &error)\n{\n  if (ci)\n    ci->_ip--;\n\n  if (_debughook_native && ci)\n  {\n    SQObjectPtr errStrHolder;\n    const char *errStr;\n    if (sq_type(error) == OT_STRING) {\n      errStr = _stringval(error);\n    } else {\n      errStrHolder = PrintObjVal(error);\n      errStr = _stringval(errStrHolder);\n    }\n\n    if (ci->_closure._type == OT_NATIVECLOSURE)\n    {\n      _debughook_native(this, 'e', \"\", 0, errStr);\n    }\n    else\n    {\n      SQFunctionProto *func = _closure(ci->_closure)->_function;\n      if (func)\n      {\n        const char *src = sq_type(func->_sourcename) == OT_STRING ? _stringval(func->_sourcename) : NULL;\n        SQInteger line = func->GetLine(ci->_ip);\n        _debughook_native(this, 'e', src, line, errStr);\n      }\n    }\n  }\n\n    if(sq_type(_errorhandler) != OT_NULL) {\n        SQObjectPtr out;\n        assert(_top+2 <= _stack.size());\n        Push(_roottable); Push(error);\n        Call(_errorhandler, 2, _top-2, out,SQFalse);\n        Pop(2);\n    }\n\n  if (ci)\n    ci->_ip++;\n}\n\n\nvoid SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)\n{\n    _debughook = false;\n    if (!ci) {\n        if (_debughook_native)\n            _debughook_native(this, type, \"\", -1, \"\");\n        else {\n            SQObjectPtr temp_reg; // -V688\n            SQInteger nparams = 5;\n            Push(_roottable);\n            Push(SQObjectPtr(type));\n            Push(SQObjectPtr(SQString::Create(_ss(this), \"\")));\n            Push(SQObjectPtr(SQInteger(-1)));\n            Push(SQObjectPtr(SQString::Create(_ss(this), \"\")));\n            Call(_debughook_closure, nparams, _top - nparams, temp_reg, SQFalse);\n            Pop(nparams);\n        }\n        _debughook = true;\n        return;\n    }\n\n    SQFunctionProto *func=_closure(ci->_closure)->_function;\n    if(_debughook_native) {\n        const char *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL;\n        const char *fname = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL;\n        SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip);\n        _debughook_native(this,type,src,line,fname);\n    }\n    else {\n        SQObjectPtr temp_reg;\n        SQInteger nparams=5;\n        Push(_roottable);\n        Push(SQObjectPtr(type));\n        Push(func->_sourcename);\n        Push(SQObjectPtr(forcedline ? forcedline : func->GetLine(ci->_ip)));\n        Push(func->_name);\n        Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse);\n        Pop(nparams);\n    }\n    _debughook = true;\n}\n\nbool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target,bool &suspend, bool &tailcall)\n{\n    SQInteger nparamscheck = nclosure->_nparamscheck;\n    SQInteger newtop = newbase + nargs + nclosure->_noutervalues;\n\n    if (_nnativecalls + 1 > MAX_NATIVE_CALLS) {\n        Raise_Error(\"Native stack overflow\");\n        return false;\n    }\n\n    if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) ||\n        ((nparamscheck < 0) && (nargs < (-nparamscheck)))))\n    {\n        if (nparamscheck > 0) {\n            Raise_Error(\"wrong number of parameters passed to native closure '%s' (%d passed, %d required)\",\n                sq_type(nclosure->_name) == OT_STRING ? _stringval(nclosure->_name) : \"unknown\",\n                (int)nargs, (int)nparamscheck);\n        } else {\n            Raise_Error(\"wrong number of parameters passed to native closure '%s' (%d passed, at least %d required)\",\n                sq_type(nclosure->_name) == OT_STRING ? _stringval(nclosure->_name) : \"unknown\",\n                (int)nargs, (int)-nparamscheck);\n        }\n\n        return false;\n    }\n\n    SQInteger tcs;\n    SQIntVec &tc = nclosure->_typecheck;\n    if((tcs = tc.size())) {\n        for(SQInteger i = 0; i < nargs && i < tcs; i++) {\n            if((tc._vals[i] != -1) && !check_typemask(sq_type(_stack._vals[newbase+i]), tc._vals[i])) {\n                Raise_ParamTypeError(i,tc._vals[i], sq_type(_stack._vals[newbase+i]),\n                    sq_type(nclosure->_name) == OT_STRING ? _stringval(nclosure->_name) : nullptr);\n                return false;\n            }\n        }\n    }\n\n    if(!EnterFrame(newbase, newtop, false)) return false;\n    ci->_closure  = nclosure;\n    ci->_target = target;\n\n    SQInteger outers = nclosure->_noutervalues;\n    for (SQInteger i = 0; i < outers; i++) {\n        _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i];\n    }\n    if(nclosure->_env) {\n        _stack._vals[newbase] = nclosure->_env->_obj;\n    }\n\n    _nnativecalls++;\n    SQInteger ret = (nclosure->_function)(this);\n    _nnativecalls--;\n\n    suspend = false;\n    tailcall = false;\n    if (ret == SQ_TAILCALL_FLAG) {\n        tailcall = true;\n        return true;\n    }\n    else if (ret == SQ_SUSPEND_FLAG) {\n        suspend = true;\n    }\n    else if (ret < 0) {\n        LeaveFrame();\n        Raise_Error(_lasterror);\n        return false;\n    }\n    if(ret) {\n        retval = _stack._vals[_top-1];\n    }\n    else {\n        retval.Null();\n    }\n    LeaveFrame();\n\n#if SQ_RUNTIME_TYPE_CHECK\n    if (target != -1) {\n        if (!check_typemask(sq_type(retval), nclosure->_result_type_mask)) {\n            char buf[160];\n            sq_stringify_type_mask(buf, sizeof(buf), nclosure->_result_type_mask);\n            Raise_Error(\"Function '%s' returned invalid type '%s', expected '%s'\",\n                sq_isstring(nclosure->_name) ? _stringval(nclosure->_name) : \"<unknown>\",\n                GetTypeName(retval), buf);\n            return false;\n        }\n    } else if (nclosure->_nodiscard) {\n        Raise_Error(\"Discarding return value of function '%s' with 'nodiscard' attribute\", sq_isstring(nclosure->_name) ? _stringval(nclosure->_name) : \"<unknown>\");\n        return false;\n    }\n#endif\n\n    return true;\n}\n\nbool SQVM::TailCall(SQClosure *closure, SQInteger parambase,SQInteger nparams)\n{\n    SQInteger last_top = _top;\n    SQObjectPtr clo(closure);\n    if (ci->_root)\n    {\n        Raise_Error(\"root calls cannot invoke tailcalls\");\n        return false;\n    }\n    for (SQInteger i = 0; i < nparams; i++) _stack._vals[_stackbase + i] = _stack._vals[_stackbase + parambase + i];\n    bool ret = StartCall<true>(closure, ci->_target, nparams, _stackbase, true);\n    if (last_top >= _top) {\n        _top = last_top;\n    }\n    return ret;\n}\n\n\nbool SQVM::GetVarTrace(const SQObjectPtr &self, const SQObjectPtr &key, char * buf, int buf_size)\n{\n#if SQ_VAR_TRACE_ENABLED == 1\n\n  SQObjectPtr tmp;\n  VarTrace * vt = NULL;\n  const char * reason = \"\";\n\n  if (_ss(this)->_varTraceEnabled == false)\n  {\n    reason = \"vartrace is disabled for this VM\";\n  }\n  else\n  {\n    switch (sq_type(self))\n    {\n    case OT_TABLE:\n      if (_table(self)->Get(key, tmp))\n        vt = _table(self)->GetVarTracePtr(key);\n      else\n        reason = \"key not found\";\n      break;\n    case OT_ARRAY:\n      if (sq_isnumeric(key))\n      {\n        if (_array(self)->Get(tointeger(key), tmp))\n          vt = _array(self)->GetVarTracePtr(tointeger(key));\n        else\n          reason = \"index not found\";\n      }\n      break;\n\n    default:\n      reason = \"not a table or array\";\n      break;\n    }\n  }\n\n  if (vt)\n  {\n    vt->printStack(buf, buf_size);\n    return true;\n  }\n  else\n  {\n    *buf = 0;\n    strncat(buf, reason, buf_size);\n    buf[buf_size - 1] = 0;\n    return false;\n  }\n\n#else\n\n  (void)self;\n  (void)key;\n\n  strncpy(buf, \"vartrace is disabled - use build with SQ_VAR_TRACE_ENABLED=1 option set\", buf_size);\n  buf[buf_size-1] = 0;\n\n  return false;\n\n#endif\n}\n\nbool SQVM::Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags)\n{\n    SQInteger fb = GetImpl(self, key, dest, getflags);\n    return fb == SLOT_STATUS_OK;\n}\n\nSQInteger SQVM::GetImpl(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags)\n{\n    if (getflags & GET_FLAG_TYPE_METHODS_ONLY) {\n        if (InvokeTypeMethod(self, key, dest)) {\n          propagate_immutable(self, dest);\n          return SLOT_STATUS_OK;\n        }\n        if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);\n        return SLOT_STATUS_NO_MATCH;\n    }\n    switch(sq_type(self)){\n    case OT_TABLE:\n        if(_table(self)->Get(key,dest)) {\n            propagate_immutable(self, dest);\n            return SLOT_STATUS_OK;\n        }\n        break;\n    case OT_ARRAY:\n        if (sq_isnumeric(key)) {\n            if (_array(self)->Get(tointeger(key), dest)) {\n                propagate_immutable(self, dest);\n                return SLOT_STATUS_OK;\n            }\n            if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0)\n                Raise_IdxError(key);\n            return SLOT_STATUS_NO_MATCH;\n        }\n        break;\n    case OT_INSTANCE:\n        if(_instance(self)->Get(key,dest)) {\n            propagate_immutable(self, dest);\n            return SLOT_STATUS_OK;\n        }\n        break;\n    case OT_CLASS:\n        if(_class(self)->Get(key,dest)) {\n            propagate_immutable(self, dest);\n            return SLOT_STATUS_OK;\n        }\n        break;\n    case OT_STRING:\n        if(sq_isnumeric(key)){\n            SQInteger n = tointeger(key);\n            SQInteger len = _string(self)->_len;\n            if (n < 0) { n += len; }\n            if (n >= 0 && n < len) {\n                dest = SQInteger(_stringval(self)[n]);\n                return SLOT_STATUS_OK;\n            }\n            if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);\n            return SLOT_STATUS_NO_MATCH;\n        }\n        break;\n    default:break; //shut up compiler\n    }\n    if ((getflags & GET_FLAG_RAW) == 0) {\n        switch(FallBackGet(self,key,dest)) {\n            case SLOT_STATUS_OK:\n                propagate_immutable(self, dest);\n                return SLOT_STATUS_OK; //okie\n            case SLOT_STATUS_NO_MATCH: break; //keep falling back\n            case SLOT_STATUS_ERROR: return SLOT_STATUS_ERROR; // the metamethod failed\n        }\n    }\n    if (!(getflags & (GET_FLAG_RAW | GET_FLAG_NO_TYPE_METHODS)))\n    {\n        if(InvokeTypeMethod(self,key,dest)) {\n            propagate_immutable(self, dest);\n            return SLOT_STATUS_OK;\n        }\n    }\n    if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);\n    return SLOT_STATUS_NO_MATCH;\n}\n\nSQClass* SQVM::GetBuiltInClassForType(SQObjectType type)\n{\n    switch(type) {\n        case OT_INTEGER: return _class(_sharedstate->_integer_class);\n        case OT_FLOAT: return _class(_sharedstate->_float_class);\n        case OT_BOOL: return _class(_sharedstate->_bool_class);\n        case OT_STRING: return _class(_sharedstate->_string_class);\n        case OT_ARRAY: return _class(_sharedstate->_array_class);\n        case OT_TABLE: return _class(_sharedstate->_table_class);\n        case OT_CLOSURE:\n        case OT_NATIVECLOSURE: return _class(_sharedstate->_function_class);\n        case OT_GENERATOR: return _class(_sharedstate->_generator_class);\n        case OT_THREAD: return _class(_sharedstate->_thread_class);\n        case OT_CLASS: return _class(_sharedstate->_class_class);\n        case OT_INSTANCE: return _class(_sharedstate->_instance_class);\n        case OT_WEAKREF: return _class(_sharedstate->_weakref_class);\n        case OT_USERDATA: return _class(_sharedstate->_userdata_class);\n        case OT_NULL: return _class(_sharedstate->_null_class);\n        default: return NULL;\n    }\n}\n\nbool SQVM::InvokeTypeMethod(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\n{\n    SQClass *builtin_class = GetBuiltInClassForType(sq_type(self));\n    if (!builtin_class)\n        return false;\n    return builtin_class->Get(key, dest);\n}\n\n\nSQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)\n{\n    switch(sq_type(self)){\n    case OT_TABLE:\n    case OT_USERDATA:\n        //delegation\n        if(_delegable(self)->_delegate) {\n            if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0)) return SLOT_STATUS_OK;\n        }\n        else {\n            return SLOT_STATUS_NO_MATCH;\n        }\n        //go through\n    case OT_INSTANCE: {\n        SQObjectPtr closure;\n        if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) {\n            Push(self);Push(key);\n            _nmetamethodscall++;\n            AutoDec ad(&_nmetamethodscall);\n            if(Call(closure, 2, _top - 2, dest, SQFalse)) {\n                Pop(2);\n                return SLOT_STATUS_OK;\n            }\n            else {\n                Pop(2);\n                if(sq_type(_lasterror) != OT_NULL) { //NULL means \"clean failure\" (not found)\n                    if (_nmetamethodscall <= 1)\n                        Raise_MetamethodError(\"_get\");\n                    return SLOT_STATUS_ERROR;\n                }\n            }\n        }\n        }\n        break;\n    default: break;//shutup GCC 4.x\n    }\n    // no metamethod or no fallback type\n    return SLOT_STATUS_NO_MATCH;\n}\n\nbool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\n{\n    if (self._flags & SQOBJ_FLAG_IMMUTABLE) {\n        Raise_Error(\"trying to modify immutable '%s'\",GetTypeName(self));\n        return false;\n    }\n\n    switch(sq_type(self)){\n    case OT_TABLE:\n        if(_table(self)->Set(key,val)) return true;\n        break;\n    case OT_INSTANCE: {\n        SQInteger res = _instance(self)->Set(key,val);\n        if (res == SLOT_STATUS_OK)\n            return true;\n        if (res == SLOT_STATUS_ERROR) {\n            // This error happens only if SetNativeField() failed.\n            // The only possible cause is type mismatch.\n            Raise_Error(\"type mismatch in native field assignment\");\n            return false;\n        }\n        // SLOT_STATUS_NO_MATCH, fallthrough\n        break;\n    }\n    case OT_ARRAY:\n        if(!sq_isnumeric(key)) { Raise_Error(\"indexing %s with %s\",GetTypeName(self),GetTypeName(key)); return false; }\n        if(!_array(self)->Set(tointeger(key),val)) {\n            Raise_IdxError(key);\n            return false;\n        }\n        return true;\n    case OT_USERDATA: break; // must fall back\n    default:\n        Raise_Error(\"trying to set '%s'\",GetTypeName(self));\n        return false;\n    }\n\n    switch(FallBackSet(self,key,val)) {\n        case SLOT_STATUS_OK: return true; //okie\n        case SLOT_STATUS_NO_MATCH: break; //keep falling back\n        case SLOT_STATUS_ERROR: return false; // the metamethod failed\n    }\n    Raise_IdxError(key);\n    return false;\n}\n\nSQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)\n{\n    switch(sq_type(self)) {\n        case OT_TABLE:\n            if(_table(self)->_delegate) {\n                if(Set(SQObjectPtr(_table(self)->_delegate),key,val)) return SLOT_STATUS_OK;\n            }\n            //keps on going\n        case OT_INSTANCE:\n        case OT_USERDATA:{\n            SQObjectPtr closure;\n            SQObjectPtr t;\n            if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) {\n                Push(self);Push(key);Push(val);\n                _nmetamethodscall++;\n                AutoDec ad(&_nmetamethodscall);\n                if(Call(closure, 3, _top - 3, t, SQFalse)) {\n                    Pop(3);\n                    return SLOT_STATUS_OK;\n                }\n                else {\n                    Pop(3);\n                    if(sq_type(_lasterror) != OT_NULL) { //NULL means \"clean failure\" (not found)\n                        if (_nmetamethodscall <= 1)\n                            Raise_MetamethodError(\"_set\");\n                        return SLOT_STATUS_ERROR;\n                    }\n                }\n            }\n        }\n        break;\n        default: break;//shutup GCC 4.x\n    }\n    // no metamethod or no fallback type\n    return SLOT_STATUS_NO_MATCH;\n}\n\nbool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\n{\n    SQObjectPtr temp_reg;\n    SQObjectPtr newobj;\n    switch(sq_type(self)){\n    case OT_TABLE:\n        newobj = _table(self)->Clone();\n        goto cloned_mt;\n    case OT_INSTANCE: {\n        newobj = _instance(self)->Clone(_ss(this));\ncloned_mt:\n        SQObjectPtr closure;\n        if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) {\n            Push(newobj);\n            Push(self);\n            if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg))\n                return false;\n        }\n        }\n        target = newobj;\n        return true;\n    case OT_ARRAY:\n        target = _array(self)->Clone();\n        return true;\n    case OT_USERDATA:\n    case OT_CLASS:\n        Raise_Error(\"cloning a %s\", GetTypeName(self));\n        return false;\n    default:\n        target = self;\n        return true;\n    }\n}\n\n\nbool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\n{\n    if (self._flags & SQOBJ_FLAG_IMMUTABLE) {\n        Raise_Error(\"trying to modify immutable '%s'\",GetTypeName(self));\n        return false;\n    }\n\n    switch(sq_type(self)) {\n    case OT_TABLE: {\n        bool rawcall = true;\n        if(_table(self)->_delegate) {\n            SQObjectPtr res;\n            if(!_table(self)->Get(key,res)) {\n                SQObjectPtr closure;\n                if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\n                    Push(self);Push(key);Push(val);\n                    if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\n                        return false;\n                    }\n                    rawcall = false;\n                }\n                else {\n                    rawcall = true;\n                }\n            }\n        }\n        if(rawcall) _table(self)->NewSlot(key,val); //cannot fail\n\n        break;}\n    case OT_INSTANCE: {\n        SQObjectPtr res;\n        SQObjectPtr closure;\n        if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {\n            Push(self);Push(key);Push(val);\n            if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {\n                return false;\n            }\n            break;\n        }\n        Raise_Error(\"class instances do not support the new slot operator\");\n        return false;\n        break;}\n    case OT_CLASS:\n        if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\n            if(_class(self)->isLocked()) {\n                Raise_Error(\"trying to modify a class that has already been instantiated, inherited or is locked manually\");\n                return false;\n            }\n            else {\n                SQObjectPtr oval(PrintObjVal(key));\n                Raise_Error(\"the property %s already exists\",_stringval(oval));\n                return false;\n            }\n        }\n        break;\n    default:\n        Raise_Error(\"indexing %s with %s\",GetTypeName(self),GetTypeName(key));\n        return false;\n        break;\n    }\n    return true;\n}\n\n\n\nbool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)\n{\n    if (self._flags & SQOBJ_FLAG_IMMUTABLE) {\n        Raise_Error(\"trying to modify immutable '%s'\",GetTypeName(self));\n        return false;\n    }\n\n    switch(sq_type(self)) {\n    case OT_TABLE:\n    case OT_INSTANCE:\n    case OT_USERDATA: {\n        SQObjectPtr t;\n        SQObjectPtr closure;\n        if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) {\n            Push(self);Push(key);\n            return CallMetaMethod(closure,MT_DELSLOT,2,res);\n        }\n        else {\n            if(sq_type(self) == OT_TABLE) {\n                if(_table(self)->Get(key,t)) {\n                    _table(self)->Remove(key);\n                }\n                else {\n                    Raise_IdxError(key);\n                    return false;\n                }\n            }\n            else {\n                Raise_Error(\"cannot delete a slot from %s\",GetTypeName(self));\n                return false;\n            }\n        }\n        res = t;\n        }\n        break;\n    default:\n        Raise_Error(\"attempt to delete a slot from a %s\",GetTypeName(self));\n        return false;\n    }\n    return true;\n}\n\nbool SQVM::Call(const SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool invoke_err_handler)\n{\n    switch(sq_type(closure)) {\n    case OT_CLOSURE:\n        return _debughook ?\n            Execute<true>(closure, nparams, stackbase, outres, invoke_err_handler) :\n            Execute<false>(closure, nparams, stackbase, outres, invoke_err_handler);\n    case OT_NATIVECLOSURE:{\n        bool dummy;\n        return CallNative(_nativeclosure(closure), nparams, stackbase, outres, -1, dummy, dummy);\n    }\n    case OT_CLASS: {\n        SQClass *theclass = _class(closure);\n\n        if (theclass->_is_builtin_type) {\n            // For built-in types, call the constructor directly (no instance creation)\n            SQObjectPtr constr;\n            if (!theclass->GetConstructor(constr)) {\n                Raise_Error(\"built-in type '%s' has no constructor\", IdType2Name(theclass->_builtin_type_id));\n                return false;\n            }\n\n            assert(sq_type(constr) == OT_NATIVECLOSURE);\n            _stack[stackbase].Null();  // 'this'\n            bool dummy;\n            return CallNative(_nativeclosure(constr), nparams, stackbase, outres, -1, dummy, dummy);\n        } else {\n            // Regular script class - create instance then call constructor\n            SQObjectPtr constr;\n            SQObjectPtr temp;\n            if (!CreateClassInstance(theclass,outres,constr))\n                return false;\n            SQObjectType ctype = sq_type(constr);\n            if (ctype == OT_NATIVECLOSURE || ctype == OT_CLOSURE) {\n                _stack[stackbase] = outres;\n                return Call(constr,nparams,stackbase,temp,invoke_err_handler);\n            }\n            return true;\n        }\n    }\n    default:\n        Raise_Error(\"attempt to call '%s'\", GetTypeName(closure));\n        return false;\n    }\n}\n\nbool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod SQ_UNUSED_ARG(mm),SQInteger nparams,SQObjectPtr &outres)\n{\n    _nmetamethodscall++;\n    if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\n        _nmetamethodscall--;\n        Pop(nparams);\n        return true;\n    }\n    _nmetamethodscall--;\n    Pop(nparams);\n    return false;\n}\n\nvoid SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex)\n{\n    SQOuter **pp = &_openouters;\n    SQOuter *p;\n    SQOuter *otr;\n\n    while ((p = *pp) != NULL && p->_valptr >= stackindex) {\n        if (p->_valptr == stackindex) {\n            target = SQObjectPtr(p);\n            return;\n        }\n        pp = &p->_next;\n    }\n    otr = SQOuter::Create(_ss(this), stackindex);\n    otr->_next = *pp;\n    otr->_idx  = (stackindex - _stack._vals);\n    __ObjAddRef(otr);\n    *pp = otr;\n    target = SQObjectPtr(otr);\n}\n\nbool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)\n{\n    if( !tailcall ) {\n        if( _callsstacksize == _alloccallsstacksize ) {\n            GrowCallStack();\n        }\n        ci = &_callsstack[_callsstacksize++];\n        ci->_prevstkbase = (SQInt32)(newbase - _stackbase);\n        ci->_prevtop = (SQInt32)(_top - _stackbase);\n        ci->_etraps = 0;\n        ci->_ncalls = 1;\n        ci->_generator = NULL;\n        ci->_root = SQFalse;\n    }\n    else {\n        ci->_ncalls++;\n    }\n\n    _stackbase = newbase;\n    _top = newtop;\n\n    if(newtop + STACK_GROW_THRESHOLD > (SQInteger)_stack.size()) {\n        if(!_nmetamethodscall) {\n            SQInteger newsize = newtop + (STACK_GROW_THRESHOLD << 1);\n            if (newsize > MAX_SQ_STACK_SIZE) {\n                Raise_Error(\"stack overflow, cannot resize stack\");\n                return false;\n            }\n            _stack.resize(newsize);\n            RelocateOuters();\n        }\n        // TODO: this exception should never occur and will be removed soon\n        else if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) {\n            Raise_Error(\"stack overflow, cannot resize stack while in a metamethod, stack.size = %d, required = %d\",\n                int(_stack.size()), int(newtop + MIN_STACK_OVERHEAD));\n            return false;\n        }\n    }\n    return true;\n}\n\n\nvoid SQVM::Release()\n{\n  sq_delete(_sharedstate->_alloc_ctx, this, SQVM);\n}\n\n\nvoid SQVM::LeaveFrame() {\n    SQInteger last_top = _top;\n    SQInteger last_stackbase = _stackbase;\n    SQInteger css = --_callsstacksize;\n\n    /* First clean out the call stack frame */\n    ci->_closure.Null();\n    _stackbase -= ci->_prevstkbase;\n    _top = _stackbase + ci->_prevtop;\n    ci = (css) ? &_callsstack[css-1] : NULL;\n\n    if(_openouters) CloseOuters(&(_stack._vals[last_stackbase]));\n    while (last_top >= _top) {\n        _stack._vals[last_top--].Null();\n    }\n}\n\nvoid SQVM::RelocateOuters()\n{\n    SQOuter *p = _openouters;\n    while (p) {\n        p->_valptr = _stack._vals + p->_idx;\n        p = p->_next;\n    }\n}\n\nvoid SQVM::CloseOuters(SQObjectPtr *stackindex) {\n  SQOuter *p;\n  while ((p = _openouters) != NULL && p->_valptr >= stackindex) {\n    p->_value = *(p->_valptr);\n    p->_valptr = &p->_value;\n    _openouters = p->_next;\n    __ObjRelease(p);\n  }\n}\n\nvoid SQVM::Remove(SQInteger n) {\n    n = (n >= 0)?n + _stackbase - 1:_top + n;\n    for(SQInteger i = n; i < _top; i++){\n        _stack[i] = _stack[i+1];\n    }\n    _stack[_top].Null();\n    _top--;\n}\n\nvoid SQVM::Pop() {\n    ValidateThreadAccess();\n\n    _stack[--_top].Null();\n}\n\nvoid SQVM::Pop(SQInteger n) {\n    ValidateThreadAccess();\n\n    for(SQInteger i = 0; i < n; i++){\n        _stack[--_top].Null();\n    }\n}\n\nvoid SQVM::PushNull() {\n    ValidateThreadAccess();\n\n    _stack[_top++].Null();\n}\nvoid SQVM::Push(const SQObjectPtr &o) {\n    ValidateThreadAccess();\n\n    _stack[_top++] = o;\n}\nvoid SQVM::Push(SQObjectPtr &&o) {\n    ValidateThreadAccess();\n\n    _stack[_top++] = std::move(o);\n}\nSQObjectPtr &SQVM::Top() { return _stack[_top-1]; }\nSQObjectPtr &SQVM::PopGet() {\n    ValidateThreadAccess();\n    return _stack[--_top];\n}\nSQObjectPtr &SQVM::GetUp(SQInteger n) {\n    ValidateThreadAccess();\n    return _stack[_top+n];\n}\nSQObjectPtr &SQVM::GetAt(SQInteger n) {\n    ValidateThreadAccess();\n    return _stack[n];\n}\n\n#ifdef _DEBUG_DUMP\nvoid SQVM::dumpstack(SQInteger stackbase,bool dumpall)\n{\n    SQInteger size=dumpall?_stack.size():_top;\n    SQInteger n=0;\n    printf(\"\\n>>>>stack dump<<<<\\n\");\n    CallInfo &ci=_callsstack[_callsstacksize-1];\n    printf(\"IP: %p\\n\",ci._ip);\n    printf(\"prev stack base: %d\\n\",ci._prevstkbase);\n    printf(\"prev top: %d\\n\",ci._prevtop);\n    for(SQInteger i=0;i<size;i++){\n        SQObjectPtr &obj=_stack[i];\n        if(stackbase==i)printf(\">\");else printf(\" \");\n        printf(\"[\" _PRINT_INT_FMT \"]:\",n);\n        switch(sq_type(obj)){\n        case OT_FLOAT:          printf(\"FLOAT %.3f\",_float(obj));break;\n        case OT_INTEGER:        printf(\"INTEGER \" _PRINT_INT_FMT,_integer(obj));break;\n        case OT_BOOL:           printf(\"BOOL %s\",_integer(obj)?\"true\":\"false\");break;\n        case OT_STRING:         printf(\"STRING %s\",_stringval(obj));break;\n        case OT_NULL:           printf(\"NULL\");  break;\n        case OT_TABLE:          printf(\"TABLE %p[%p]\",_table(obj),_table(obj)->_delegate);break;\n        case OT_ARRAY:          printf(\"ARRAY %p\",_array(obj));break;\n        case OT_CLOSURE:        printf(\"CLOSURE [%p]\",_closure(obj));break;\n        case OT_NATIVECLOSURE:  printf(\"NATIVECLOSURE\");break;\n        case OT_USERDATA:       printf(\"USERDATA %p[%p]\",_userdataval(obj),_userdata(obj)->_delegate);break;\n        case OT_GENERATOR:      printf(\"GENERATOR %p\",_generator(obj));break;\n        case OT_THREAD:         printf(\"THREAD [%p]\",_thread(obj));break;\n        case OT_USERPOINTER:    printf(\"USERPOINTER %p\",_userpointer(obj));break;\n        case OT_CLASS:          printf(\"CLASS %p\",_class(obj));break;\n        case OT_INSTANCE:       printf(\"INSTANCE %p\",_instance(obj));break;\n        case OT_WEAKREF:        printf(\"WEAKREF %p\",_weakref(obj));break;\n        default:\n            assert(0);\n            break;\n        };\n        printf(\"\\n\");\n        ++n;\n    }\n}\n\n\n\n#endif\n"
  },
  {
    "path": "squirrel/sqvm.h",
    "content": "/*  see copyright notice in squirrel.h */\n#ifndef _SQVM_H_\n#define _SQVM_H_\n\n#include \"opcodes.h\"\n#include \"sqobject.h\"\n#define MAX_NATIVE_CALLS 100\n#define MIN_STACK_OVERHEAD 15\n\n// keep 256 stack slots reserved for locals and function arguments,\n// and another 256 slots for stack operations from native code\n#define STACK_GROW_THRESHOLD (256 * 2)\n\n#define MAX_SQ_STACK_SIZE 100000\n\n#define SQ_SUSPEND_FLAG -666\n#define SQ_TAILCALL_FLAG -777\n\n#define GET_FLAG_RAW                0x00000001\n#define GET_FLAG_DO_NOT_RAISE_ERROR 0x00000002\n#define GET_FLAG_NO_TYPE_METHODS    0x00000004\n#define GET_FLAG_TYPE_METHODS_ONLY  0x00000008\n\n//base lib\nvoid sq_base_register(HSQUIRRELVM v);\n\nstruct SQExceptionTrap{\n    SQExceptionTrap() {}\n    SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;}\n    SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et;  }\n    SQExceptionTrap &operator=(const SQExceptionTrap &et) = default;\n    SQInteger _stackbase;\n    SQInteger _stacksize;\n    SQInstruction *_ip;\n    SQInteger _extarget;\n};\n\ntypedef sqvector<SQExceptionTrap> ExceptionsTraps;\n\nstruct SQVM : public CHAINABLE_OBJ\n{\n    struct CallInfo{\n        SQInstruction *_ip;\n        SQObjectPtr *_literals;\n        SQObjectPtr _closure;\n        SQGenerator *_generator;\n        SQInt32 _etraps;\n        SQInt32 _prevstkbase;\n        SQInt32 _prevtop;\n        SQInt32 _target;\n        SQInt32 _ncalls;\n        SQBool _root;\n    };\n\ntypedef sqvector<CallInfo> CallInfoVec;\npublic:\n    void DebugHookProxy(SQInteger type, const char * sourcename, SQInteger line, const char * funcname);\n    static void _DebugHookProxy(HSQUIRRELVM v, SQInteger type, const char * sourcename, SQInteger line, const char * funcname);\n    enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM,ET_RESUME_THROW_VM };\n    SQVM(SQSharedState *ss);\n    ~SQVM();\n    bool Init(SQVM *friendvm, SQInteger stacksize);\n\n    template <bool debughookPresent>\n    bool Execute(const SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool invoke_err_handler, ExecutionType et = ET_CALL);\n\n    //starts a native call return when the NATIVE closure returns\n    bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target, bool &suspend,bool &tailcall);\n    bool TailCall(SQClosure *closure, SQInteger firstparam, SQInteger nparams);\n    //starts a SQUIRREL call in the same \"Execution loop\"\n    template <bool debughookPresent>\n    bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);\n    bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);\n    //call a generic closure pure SQUIRREL or NATIVE\n    bool Call(const SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool invoke_err_handler);\n    SQRESULT Suspend();\n\n    bool GetVarTrace(const SQObjectPtr &self, const SQObjectPtr &key, char * buf, int buf_size);\n\n    void CallDebugHook(SQInteger type,SQInteger forcedline=0);\n    void CallErrorHandler(const SQObjectPtr &e);\n    SQInteger GetImpl(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags);\n    bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags);\n    SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);\n    bool InvokeTypeMethod(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);\n    SQClass* GetBuiltInClassForType(SQObjectType type);\n    bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val);\n    SQInteger FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val);\n    bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic);\n    bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res);\n    bool Clone(const SQObjectPtr &self, SQObjectPtr &target);\n    bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res);\n    bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest);\n    static bool IsEqual(const SQObject &o1,const SQObject &o2);\n    static bool IsInstanceOf(const SQObject &obj, const SQClass *cls);\n    bool ToString(const SQObjectPtr &o,SQObjectPtr &res);\n    SQString *PrintObjVal(const SQObject &o);\n\n\n    void Raise_Error(const char *s, ...);\n    void Raise_Error(const SQObjectPtr &desc);\n    void Raise_IdxError(const SQObjectPtr &o);\n    void Raise_MetamethodError(const char *mmname);\n    void Raise_CompareError(const SQObject &o1, const SQObject &o2);\n    void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type,const char *funcname = nullptr);\n\n    void FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex);\n    void RelocateOuters();\n    void CloseOuters(SQObjectPtr *stackindex);\n\n    bool TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest);\n    bool CallMetaMethod(SQObjectPtr &closure, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres);\n    bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest);\n    template <bool debughookPresent>\n    bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval);\n\n    bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\n    bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);\n    bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);\n    bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);\n    bool CMP_OP_RES(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,int &res);\n    bool CMP_OP_RESI(CmpOP op, const SQObjectPtr &o1,const SQInteger o2,int &res);\n    bool CMP_OP_RESF(CmpOP op, const SQObjectPtr &o1,const SQFloat o2,int &res);\n    bool ObjCmpI(const SQObjectPtr &o1, const SQInteger o2,SQInteger &res);\n    bool ObjCmpF(const SQObjectPtr &o1, const SQFloat o2,SQInteger &res);\n    bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func);\n    bool CLASS_OP(SQObjectPtr &target,SQInteger base);\n    //return true if the loop is finished\n    bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,int exitpos,int &jump);\n    bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);\n    bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix);\n#ifdef _DEBUG_DUMP\n    void dumpstack(SQInteger stackbase=-1, bool dumpall = false);\n#endif\n\n#ifndef NO_GARBAGE_COLLECTOR\n    void Mark(SQCollectable **chain);\n    SQObjectType GetType() {return OT_THREAD;}\n#endif\n    void Finalize();\n    void GrowCallStack() {\n        SQInteger newsize = _alloccallsstacksize*2;\n        _callstackdata.resize(newsize);\n        _callsstack = &_callstackdata[0];\n        _alloccallsstacksize = newsize;\n    }\n    bool EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall);\n    void LeaveFrame();\n    void Release();\n\n    //stack functions for the api\n    void Remove(SQInteger n);\n\n    static bool IsFalse(const SQObject &o);\n\n    void Pop();\n    void Pop(SQInteger n);\n    void Push(const SQObjectPtr &o);\n    void Push(SQObjectPtr &&o);\n    void PushNull();\n    SQObjectPtr &Top();\n    SQObjectPtr &PopGet();\n    SQObjectPtr &GetUp(SQInteger n);\n    SQObjectPtr &GetAt(SQInteger n);\n\n    #if SQ_CHECK_THREAD >= SQ_CHECK_THREAD_LEVEL_DEEP\n    inline void ValidateThreadAccess() {\n        assert(!_get_current_thread_id_func || check_thread_access==0 || check_thread_access==_get_current_thread_id_func());\n    }\n    #else\n    inline void ValidateThreadAccess() {}\n    #endif\n\n    inline bool CanAccessFromThisThread() {\n        #if SQ_CHECK_THREAD >= SQ_CHECK_THREAD_LEVEL_FAST\n        if (_nnativecalls && _get_current_thread_id_func)\n            return _get_current_thread_id_func() == _current_thread;\n        #endif\n        return true;\n    }\n\n    SQObjectPtrVec _stack;\n\n    SQInteger _top;\n    SQInteger _stackbase;\n    SQOuter *_openouters;\n    SQObjectPtr _roottable;\n    SQObjectPtr _lasterror;\n    SQObjectPtr _errorhandler;\n\n    bool _debughook;\n    SQDEBUGHOOK _debughook_native;\n    SQObjectPtr _debughook_closure;\n    SQInteger _current_thread;\n    SQGETTHREAD _get_current_thread_id_func;\n    SQCOMPILELINEHOOK _compile_line_hook;\n    SQSQCALLHOOK _sq_call_hook;\n    SQWATCHDOGHOOK _watchdog_hook;\n\n    SQObjectPtr temp_reg;\n\n\n    CallInfo* _callsstack;\n    SQInteger _callsstacksize;\n    SQInteger _alloccallsstacksize;\n    sqvector<CallInfo>  _callstackdata;\n\n    ExceptionsTraps _etraps;\n    CallInfo *ci;\n    SQUserPointer _foreignptr;\n    //VMs sharing the same state\n    SQSharedState *_sharedstate;\n    SQInteger _nnativecalls;\n    SQInteger _nmetamethodscall;\n    SQRELEASEHOOK _releasehook;\n    //suspend infos\n    SQBool _suspended;\n    SQBool _suspended_root;\n    SQInteger _suspended_target;\n    SQInteger _suspended_traps;\n\n    int64_t check_thread_access = 0;\n};\n\nstruct AutoDec{\n    AutoDec(SQInteger *n) { _n = n; }\n    ~AutoDec() { (*_n)--; }\n    SQInteger *_n;\n};\n\ninline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));}\n\n#define _ss(_vm_) (_vm_)->_sharedstate\n\n#ifndef NO_GARBAGE_COLLECTOR\n#define _opt_ss(_vm_) (_vm_)->_sharedstate\n#else\n// This change is needed to make use of alloc_ctx\n// Without alloc_ctx NULL can be returned\n#define _opt_ss(_vm_) (_vm_)->_sharedstate\n#endif\n\n#endif //_SQVM_H_\n"
  },
  {
    "path": "squirrel/vartrace.cpp",
    "content": "#include \"sqpcheader.h\"\n#include <sqconfig.h>\n\n#if SQ_VAR_TRACE_ENABLED == 1\n\n#include \"squtils.h\"\n#include \"sqvm.h\"\n#include \"vartrace.h\"\n\n#define VT_FLAG_STRING (1<<0)\n#define VT_FLAG_ELLIPSIS (1<<1)\n\n\nbool VarTrace::isStacksEqual(int a, int b)\n{\n  for (int i = 0; i < VAR_TRACE_CALLSTACK_DEPTH; i++)\n  {\n    if (history[a].stack[i].line == STACK_NOT_INITIALIZED && history[b].stack[i].line == STACK_NOT_INITIALIZED)\n      return true;\n\n    if (history[a].stack[i].line != history[b].stack[i].line ||\n      history[a].stack[i].fileName != history[b].stack[i].fileName)\n    {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nvoid VarTrace::saveStack(const SQObject & value, const SQObject &vm_ref)\n{\n  // NULL vm may happen for objects created during SQSharedState initialization\n  assert(sq_isthread(vm_ref) || sq_isnull(vm_ref));\n\n  if (!sq_isthread(vm_ref))\n    return;\n\n  HSQUIRRELVM vm = static_cast<HSQUIRRELVM>(vm_ref._unVal.pRefCounted);\n  saveStack(value, vm);\n}\n\n\nvoid VarTrace::saveStack(const SQObject & value, HSQUIRRELVM vm)\n{\n  if (!_ss(vm)->_varTraceEnabled)\n    return;\n\n  setCnt++;\n\n  SQStackInfos si;\n  SQInteger level = 0;\n\n#if VAR_TRACE_SAVE_VALUES != 0\n  history[pos].count = 1;\n  const int valSize = sizeof(history[pos].val);\n  history[pos].val[valSize - 2] = 0;\n\n  SQObjectPtr obj(value);\n  SQObjectPtr res;\n  if (vm->ToString(obj, res))\n  {\n    const char *valueAsString = sq_objtostring(&res);\n    if (valueAsString)\n    {\n      strncpy(history[pos].val, valueAsString, valSize);\n\n      history[pos].flags = (history[pos].val[valSize - 2] != 0 ? VT_FLAG_ELLIPSIS : 0) |\n        (sq_isstring(value) ? VT_FLAG_STRING : 0);\n\n      history[pos].val[valSize - 1] = 0;\n    }\n  }\n#endif\n\n  int count = 0;\n  while (SQ_SUCCEEDED(sq_stackinfos(vm, level, &si)))\n  {\n    const char *src = \"unknown\";\n    if (si.source)\n      src = si.source;\n    history[pos].stack[count].fileName = src;\n    history[pos].stack[count].line = int(si.line);\n    if (int(si.line) != -1)\n      count++;\n\n    if (count >= VAR_TRACE_CALLSTACK_DEPTH)\n      break;\n\n    level++;\n  }\n\n  if (count < VAR_TRACE_CALLSTACK_DEPTH)\n    history[pos].stack[count].line = STACK_NOT_INITIALIZED;\n\n  int prevPos = (pos - 1 + VAR_TRACE_HISTORY_SIZE) % VAR_TRACE_HISTORY_SIZE;\n\n#if VAR_TRACE_SAVE_VALUES != 0\n  if (memcmp(&history[pos].val, &history[prevPos].val, sizeof(history[prevPos].val)) == 0 &&\n      isStacksEqual(pos, prevPos))\n  {\n    history[pos].stack[0].line = STACK_NOT_INITIALIZED;\n    history[prevPos].count++;\n  }\n  else\n  {\n    pos++;\n    if (pos >= VAR_TRACE_HISTORY_SIZE)\n      pos = 0;\n  }\n#else\n  pos++;\n  if (pos >= VAR_TRACE_HISTORY_SIZE)\n    pos = 0;\n#endif\n}\n\n#define VT_MAX(a, b) ((a) > (b) ? (a) : (b))\n#define VT_APRINTF(...) { written += scsprintf(buf + written, VT_MAX(size - written, 0), __VA_ARGS__); }\n\nvoid VarTrace::printStack(char * buf, int size)\n{\n  size--;\n  int written = 0;\n  *buf = 0;\n\n  for (int h = 0; h < VAR_TRACE_HISTORY_SIZE; h++)\n  {\n    int historyPos = (-h + pos + VAR_TRACE_HISTORY_SIZE * 2 - 1) % VAR_TRACE_HISTORY_SIZE;\n    HistoryRecord & hist = history[historyPos];\n\n    bool stackPresent = hist.stack[0].line != STACK_NOT_INITIALIZED;\n    if (size > written)\n      VT_APRINTF(\"%d:\", h);\n\n#if VAR_TRACE_SAVE_VALUES != 0\n    bool showCount = history[historyPos].count > 1 && stackPresent;\n\n    if (showCount)\n      VT_APRINTF(\" x%d\", history[historyPos].count);\n\n    if (stackPresent)\n      VT_APRINTF((history[historyPos].flags & VT_FLAG_STRING) ? \" value='%s%s'\" : \" value=%s%s\",\n        history[historyPos].val,\n        (history[historyPos].flags & VT_FLAG_ELLIPSIS) ? \"...\" : \"\");\n\n    VT_APRINTF(\"\\n\");\n#endif\n    VT_APRINTF(\"\\n\");\n\n    for (int i = 0; i < VAR_TRACE_CALLSTACK_DEPTH; i++)\n    {\n      if (hist.stack[i].line == STACK_NOT_INITIALIZED)\n        break;\n\n      if (size > written)\n        VT_APRINTF(\"  %s:%d\\n\", hist.stack[i].fileName, hist.stack[i].line);\n    }\n\n    VT_APRINTF(\"\\n\");\n  }\n\n  VT_APRINTF(\"set counter = %d\\n\", setCnt);\n}\n\n#endif\n"
  },
  {
    "path": "squirrel/vartrace.h",
    "content": "#pragma once\n\n#include <memory.h> // memset\n#include <squirrel.h>\n#include \"squtils.h\"\n\n#define VAR_TRACE_SAVE_VALUES 0\n\n#define VAR_TRACE_CALLSTACK_DEPTH 4\n#define VAR_TRACE_HISTORY_SIZE 4\n#define STACK_NOT_INITIALIZED (-2)\n\n\nstruct VarTrace\n{\n  struct VarStackRecord\n  {\n    const char * fileName;\n    int line;\n  };\n\n  struct HistoryRecord\n  {\n    VarStackRecord stack[VAR_TRACE_CALLSTACK_DEPTH];\n#if VAR_TRACE_SAVE_VALUES != 0\n    int count;\n    char val[31];\n    char flags;\n#endif\n  };\n\n  int pos;\n  int setCnt;\n  HistoryRecord history[VAR_TRACE_HISTORY_SIZE];\n\n  VarTrace()\n  {\n    memset(this, 0, sizeof(*this));\n    clear();\n  }\n\n  void clear()\n  {\n    pos = 0;\n    setCnt = 0;\n#if VAR_TRACE_SAVE_VALUES != 0\n    history[0].count = 0;\n#endif\n    for (int i = 0; i < VAR_TRACE_HISTORY_SIZE; i++)\n    {\n      history[i].stack[0].line = STACK_NOT_INITIALIZED;\n#if VAR_TRACE_SAVE_VALUES != 0\n      history[i].val[0] = 0;\n#endif\n    }\n  }\n\n  void saveStack(const SQObject & value, const SQObject &vm);\n  void saveStack(const SQObject & value, HSQUIRRELVM vm);\n  void printStack(char * buf, int size);\n\nprivate:\n  bool isStacksEqual(int a, int b);\n};\n\n#if SQ_VAR_TRACE_ENABLED == 1\n\n#define VT_CODE(code) code\n#define VT_COMMA ,\n#define VT_DECL_VEC SQVarTraceVec varTrace\n#define VT_DECL_CTR(ss_) , varTrace(ss_)\n#define VT_DECL_SINGLE VarTrace varTrace\n#define VT_DECL_ARG VT_COMMA VarTrace * var_trace_arg\n#define VT_DECL_ARG_DEF VT_DECL_ARG = NULL\n#define VT_ARG VT_COMMA var_trace\n#define VT_ARG_PARAM var_trace\n#define VT_REF(ptr) VT_COMMA &(ptr->varTrace)\n#define VT_RESIZE(x) varTrace.resize(x)\n#define VT_RESERVE(x) varTrace.reserve(x)\n#define VT_TRACE(x, val, vm) varTrace[x].saveStack(val, vm)\n#define VT_TRACE_SINGLE(ptr, val, vm) ptr->varTrace.saveStack(val, vm)\n#define VT_CLEAR_SINGLE(ptr) ptr->varTrace.clear()\n#define VT_INSERT(x, val, vm) { VarTrace tmp; varTrace.insert(x, tmp); VT_TRACE(x, val, vm); }\n#define VT_PUSHBACK(val, vm) { VarTrace tmp; varTrace.push_back(tmp); VT_TRACE(varTrace.size() - 1, val, vm); }\n#define VT_POPBACK() varTrace.pop_back()\n#define VT_REMOVE(x) varTrace.remove(x)\n#define VT_CLONE_FROM_TO(from, to) to->varTrace.copy(from->varTrace)\n#define VT_COPY_SINGLE(from, to) to->varTrace = from->varTrace\n\n\ntypedef sqvector<VarTrace> SQVarTraceVec;\n\n#else\n\n#define VT_CODE(code)\n#define VT_COMMA\n#define VT_DECL_VEC\n#define VT_DECL_CTR(ss_)\n#define VT_DECL_SINGLE\n#define VT_DECL_ARG\n#define VT_DECL_ARG_DEF\n#define VT_ARG VT_COMMA\n#define VT_ARG_PARAM\n#define VT_REF(ptr)\n#define VT_RESIZE(x)\n#define VT_RESERVE(x)\n#define VT_TRACE(x, val, vm)\n#define VT_TRACE_SINGLE(ptr, val, vm)\n#define VT_CLEAR_SINGLE(ptr)\n#define VT_INSERT(x, val, vm)\n#define VT_PUSHBACK(val, vm)\n#define VT_POPBACK()\n#define VT_REMOVE(x)\n#define VT_CLONE_FROM_TO(from, to)\n#define VT_COPY_SINGLE(from, to)\n\n#endif\n"
  },
  {
    "path": "squirrel/vartracestub.cpp",
    "content": "#include \"vartrace.h\"\n\nvoid VarTrace::printStack(char *, int) {}\n"
  },
  {
    "path": "squirrel-config.cmake.in",
    "content": "@PACKAGE_INIT@\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/squirrel-config-version.cmake\")\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/squirrel-targets.cmake\")\n"
  },
  {
    "path": "testData/ast/ast_render/all_syntax.nut",
    "content": "from \"math\" import sin, cos as cosine\nfrom \"string\" import *\nimport \"datetime\"\nimport \"debug\" as Debug\n\nlet { getlocals, doc } = require(\"debug\")\n\n{\n  null;\n  null;\n  null;\n}\n\nif (__FILE__ && __LINE__)\n  null;\n\nprintln();\n\nlocal tab = {}\n\nenum Enum1 {}\nenum Enum2 { AA }\nenum Enum3 { AA, }\nenum Enum4 { AA BB }\nenum Enum5 { AA, BB }\nenum Enum6 { AA, BB, }\nenum Enum7 { AA = -101, BB, }\nenum Enum8 { AA = 102, BB = \"enum_str1\", }\nenum Enum9 { AA BB = \"enum_str2\", }\nglobal enum Enum10 {CC = null}\n\n\n#allow-auto-freeze\n\nconst cn0 = 201\nconst cn1 = \"const_str1\"\nconst cn2 = [\"const_str2\", \"const_str3\"]\nconst cn3 = {abc = \"const_str4\"}\nglobal const cn4 = true\n\nlocal a0;\nlocal m0, m1;\nlocal a1 = null\nlocal a2 = 123_456\nlocal a3 = 123.25\nlocal a4 = 3.5e12\nlocal a5 = 3.5e+12\nlocal a6 = 3.5e-12\nlocal a7 = -3.5e-12\nlocal a8 = true\nlocal a9 = false\nlocal a10 = \"\\tlocal_str1\\uFDF0\"\nlocal a11 = @\"local_str2\nlocal_str3\"\nlocal a12 = $\"a9={a9}\"\nlocal a13 = (123_458).tofloat()\nlocal a14 = (12.45).tostring()\nlocal m3 = 301, m4 = 302\nlocal a15 = Enum9.AA\nlocal a16 = m4 = 303\n\n\nlet b0 = 0x401\nlet b1 = 0x402_FF_AA\nlet b2 = 'B'\nlet b3 = '\\n'\nlet b4 = '\\t'.tochar()\n\n\nlet e0 = []\nlet e1 = [501]\nlet e2 = [502,]\nlet e3 = [503,504]\nlet e4 = [505,506,]\n\nlet e5 = [507,\n          508,\n         ]\n\nlet e6 = [509\n          510]\n\nlet e7 = [511 512]\n\n\nlet t0 = {}\nlet t1 = {x = 601}\nlet t2 = {\"x\": 602}\nlet t3 = {[\"x\"] = 603}\nlet t4 = {[null] = 604}\nlet t5 = {[({y = 605})] = 606}\nlet t6 = {a2}\nlet t7 = {a3 a8}\nlet t8 = {x = 1}.__merge({y = 607})\nlet t9 = clone {z = 608}\n\n\ntab.x <- \"new_slot_str1\"\ntab[\"y\"] <- \"new_slot_str2\"\n\n\nlocal { abc } = cn3\n{\n  local { y, } = t8\n}\n{\n  local { y = 609, x } = t2\n  println(x)\n}\n\n{\n  local { y: int = 609, x: string|int|null } = t2\n  println(x)\n}\n\nlocal [d1, d2] = e3\nlocal [d11: int, d12: (int | null)] = e3\nlocal [d21, d22: (int | null)] = e3\nlocal [d31: int, d32] = e3\n\nfunction type_test1(x: int): int {\n  return 1 + x\n}\n\nfunction type_test2(x: int, ...: float): int {\n  return 1 + x\n}\n\nfunction type_test3(x: number|null): null|number {\n  return 1.0 + (x ?? 5)\n}\n\nfunction type_test4(x: number|null = null): null|number {\n  return 1.0 + (x ?? 6)\n}\n\nfunction type_test5(x: (number |\n                        null)): (null\n                                 | number) {\n  return 1.0 + (x ?? 5)\n}\n\nfunction type_test6(x: (number|null) = null): (int|float) {\n  return 1.0 + (x ?? 6)\n}\n\nfunction type_test7(x: bool|number|int|float|string|table|array|userdata|function|generator|userpointer|thread|instance|class|weakref|null, y: any): any {\n  return x + y\n}\n\nlet type_test8 = @(x: bool|number|int|float|string|table|array|userdata|function|generator|userpointer|thread|instance|class|weakref|null, y: any): any (\n  x + y\n)\n\nlet type_test9 = @type_test9(x: bool|number|int|null, y: any): any (\n  x + y\n)\n\nlet type_test10 = (@ [pure,] type_test10(x: bool|number|int|null, y: any): any (\n  x + y\n))\n\n\nlet x901: int = 5\nlocal t902: table = {}\nlocal t903: table|array = {}\n\n\nclass C4 {\n  static x = true\n  y = false\n  constructor() {}\n  function fn1() {}\n  fn2 = function() { this.fn1() }\n  fn3 = function fn3() { this.fn1() }\n  fn4 = @() \"class_str1\"\n  fn5 = @fn5() \"class_str2\"\n  _call = function (name) {\n    this[name]();\n    this.constructor();\n    ::tab.y <- 610\n  }\n}\n\nlet instance = C4()\ninstance.fn4()\ninstance?.fn4()\ninstance?[\"fn4\"]()\ninstance.fn4?()\nif (instance instanceof C4) {\n  println(\"instance instanceof C4\")\n}\n\n\nfunction gfn1() {}\nlocal gfn2 = function() { this.gfn1() }\nlet gfn3 = function gfn3() { this.gfn1() }\nlocal gfn4 = @() \"lambda_str1\"\nlet gfn5 = @gfn5() \"lambda_str2\"\nlocal _call = function (name) { this[name]() }\nlet gfn_pure = @[pure] gfn5() \"lambda_str3\"\nlet gfn_nodiscard = @[nodiscard] gfn6() \"lambda_str4\"\nlet gfn_pure_nodiscard = @[pure, nodiscard] gfn7() \"lambda_str5\"\n\nfunction fa1(x) { return x }\nfunction fa2(x, y) { return x + y; }\nfunction fa3(x, y, z) { return x + y * z; }\nfunction fa4(x, ...) { return x + vargv.len(); }\nfunction fa5(x = [1, 2]) { return x?[1]; }\nfunction fa6(x, y = null) { return y; }\nfunction fa7(x, y = {a = 4}, ) { return y; }\nfunction fa8(x, y = {a = 5}) { return y; }\nfunction [pure,] pure_fn(x) {return x * x}\nfunction [nodiscard,pure,] pure_nodiscard_fn(x) {return x * x}\nfunction coroutine_fn() {\n  yield 1100;\n  yield 1200;\n}\n\nprintln(resume coroutine_fn())\n\n\nfunction des1({x}) { return x + 1 }\nfunction des2([x]) { return x + 1 }\nfunction des3([x], {y}) { return x + y }\nfunction des4([x, z, w,], {y}) { return x + y }\nfunction des5(x, {y = null}) { return x + (y ?? 2) }\nfunction des6(x, {y = null, z: int|float = 1000}) { return x + (y ?? 2) + z }\n\nfunction [nodiscard, pure] des7([x: function = @() @() @() null, t, r: string = \"abc555\", g = \"abc666\"], {y = null, z: int|float = 1000,}, ...) {\n  let {p, i} = t\n  println()\n  return x + (y ?? 2) + z;\n}\n\nlet i0 = 1 + 2\nlet i1 = 1 - 2\nlet i2 = 1 * 2\nlet i3 = 1 / 2\nlet i4 = 1 % 2\nlet i5 = 1 ^ 2\nlet i6 = 1 & 2\nlet i7 = 1 | 2\nlet i8 = 1 || 2\nlet i9 = 1 && 2\nlet i10 = 1 == 2\nlet i11 = 1 != 2\nlet i12 = 1 < 2\nlet i13 = 1 > 2\nlet i14 = 1 <= 2\nlet i15 = 1 >= 2\nlet i16 = 1 <=> 2\nlet i17 = -(123)\nlet i18 = ~(123)\nlet i19 = !(123)\nlet i20 = typeof 123\nlet i21 = const 123\nlet i22 = static 123\nlet i23 = \"x\" in {x = 5}\nlet i24 = \"x\" not in {x = 6}\nlet i25 = 1 >> 2\nlet i26 = 1 << 2\nlet i27 = 1 >>> 2\nlet i28 = 1 ?? 2\n\n\nlocal iv = 123\niv++\niv--\n--iv\n++iv\niv += 123\niv -= 123\niv *= 123\niv /= 123\niv %= 123\n//iv |= 123\n//iv ^= 123\n//iv &= 123\n//iv ||= 123\n//iv ^^= 123\n//iv &&= 123\n\n/* comment */\n\nif (base) {\n  println(\"base != null\")\n}\n\n{\n  ;;;;;;\n}\n\n\nif (701 == 701)\n  fa1(701)\n\n\nif (702 == 703)\n  fa1(702)\nelse\n  fa2(703, 704)\n\n\nif (705 == 706)\n  fa1(707)\nelse if (708 == 709)\n  fa2(710, 711)\nelse\n  fa2(712, 713)\n\n\nif (local cv = iv)\n  println(cv)\n\n\nif (local cv: int|null = iv)\n  println(cv)\nelse\n  println(cv - 1)\n\n\nif (let cv: int = iv; cv > -1000000)\n  println(cv)\n\n\nif (local cv = iv)\n  println(cv)\nelse if (local cv2 = iv)\n  println(\"fail\")\n\n\nwhile (iv--)\n  fa1(714)\n\n\ndo\n  fa1(715)\nwhile (iv++ < 3)\n\n\nforeach (i in e1)\n  fa1(i)\n\n\nforeach (k, v in t7)\n  fa2(k, v)\n\n\nfor (;;)\n  break\n\n\nfor (local iter = 0; iter < 4; ++iter)\n  continue;\n\nfor (local iter = 0; iter < 4; iter += 2, iter--)\n  continue;\n\n\ntry\n  fa1(716)\ncatch (e)\n  fa1(717)\n\n\ntry\n  throw null\ncatch (e)\n  fa1(718)\n\n\n#forbid-auto-freeze\n\nlocal w = getlocals()\nlocal res = []\nforeach (k, v in w)\n  res.append($\"{k} = {[\"integer\", \"bool\", \"string\", \"float\"].indexof(type(v)) >= 0 ? v : type(v)}\")\n\nres.sort()\nforeach (_, v in res)\n  println(v)\n\n\nclass A {\n  @@\"Class docstring\"\n  function x() { return 0; }\n}\n\nlet instance_a = A()\n\nfunction test() {\n  return {\n    @@\"Table docstring\"\n    x = 4\n    fn = function() {\n      @@\"Function docstring\"\n      return 1234\n    }\n  }\n}\n\nprintln(doc(A))\nprintln(doc(instance_a))\nprintln(doc(test()))\nprintln(doc(test().fn))\n\n\nprintln(\"done\")\n"
  },
  {
    "path": "testData/ast/ast_render/all_syntax.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-ImportStmt module 'math'\n| |-'sin'\n| `-'cos' as 'cosine'\n|-ImportStmt module 'string'\n|   '*'\n|-ImportStmt module 'datetime'\n|-ImportStmt module 'debug' as 'Debug'\n|-DestructuringDecl type = 'table'\n| |-Initializer\n| |   CallExpr\n| |   |-Callee\n| |   |   Id 'require'\n| |   `-Arguments\n| |       Argument #1\n| |         LiteralExpr LK_STRING \"debug\"\n| |-VarDecl 'let', name = 'getlocals', type = 'any'\n| `-VarDecl 'let', name = 'doc', type = 'any'\n|-Block isRoot = 0, isBody = 0\n| |-ExprStatement\n| |   LiteralExpr LK_NULL\n| |-ExprStatement\n| |   LiteralExpr LK_NULL\n| `-ExprStatement\n|     LiteralExpr LK_NULL\n|-IfStatement\n| |-Condition\n| |   BinExpr '&&'\n| |   |-Left\n| |   |   LiteralExpr LK_STRING \"testData/ast/ast_render/all_syntax.nut\"\n| |   `-Right\n| |       LiteralExpr LK_INT 14\n| `-ThenBranch\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         LiteralExpr LK_NULL\n|-ExprStatement\n|   CallExpr\n|     Callee\n|       Id 'println'\n|-VarDecl 'local', name = 'tab', type = 'any'\n|   Initializer\n|     TableExpr\n|-EnumDecl name = 'Enum1', isGlobal = 0\n|-EnumDecl name = 'Enum2', isGlobal = 0\n|   Member 'AA'\n|     LiteralExpr LK_INT 0\n|-EnumDecl name = 'Enum3', isGlobal = 0\n|   Member 'AA'\n|     LiteralExpr LK_INT 0\n|-EnumDecl name = 'Enum4', isGlobal = 0\n| |-Member 'AA'\n| |   LiteralExpr LK_INT 0\n| `-Member 'BB'\n|     LiteralExpr LK_INT 1\n|-EnumDecl name = 'Enum5', isGlobal = 0\n| |-Member 'AA'\n| |   LiteralExpr LK_INT 0\n| `-Member 'BB'\n|     LiteralExpr LK_INT 1\n|-EnumDecl name = 'Enum6', isGlobal = 0\n| |-Member 'AA'\n| |   LiteralExpr LK_INT 0\n| `-Member 'BB'\n|     LiteralExpr LK_INT 1\n|-EnumDecl name = 'Enum7', isGlobal = 0\n| |-Member 'AA'\n| |   LiteralExpr LK_INT -101\n| `-Member 'BB'\n|     LiteralExpr LK_INT 0\n|-EnumDecl name = 'Enum8', isGlobal = 0\n| |-Member 'AA'\n| |   LiteralExpr LK_INT 102\n| `-Member 'BB'\n|     LiteralExpr LK_STRING \"enum_str1\"\n|-EnumDecl name = 'Enum9', isGlobal = 0\n| |-Member 'AA'\n| |   LiteralExpr LK_INT 0\n| `-Member 'BB'\n|     LiteralExpr LK_STRING \"enum_str2\"\n|-EnumDecl name = 'Enum10', isGlobal = 1\n|   Member 'CC'\n|     LiteralExpr LK_NULL\n|-DirectiveStmt\n|-ConstDecl name = 'cn0', isGlobal = 0\n|   LiteralExpr LK_INT 201\n|-ConstDecl name = 'cn1', isGlobal = 0\n|   LiteralExpr LK_STRING \"const_str1\"\n|-ConstDecl name = 'cn2', isGlobal = 0\n|   ArrayExpr\n|   |-Element #1\n|   |   LiteralExpr LK_STRING \"const_str2\"\n|   `-Element #2\n|       LiteralExpr LK_STRING \"const_str3\"\n|-ConstDecl name = 'cn3', isGlobal = 0\n|   TableExpr\n|     Field\n|     |-Key\n|     |   LiteralExpr LK_STRING \"abc\"\n|     `-Value\n|         LiteralExpr LK_STRING \"const_str4\"\n|-ConstDecl name = 'cn4', isGlobal = 1\n|   LiteralExpr LK_BOOL true\n|-VarDecl 'local', name = 'a0', type = 'any'\n|-DeclGroup\n| |-VarDecl 'local', name = 'm0', type = 'any'\n| `-VarDecl 'local', name = 'm1', type = 'any'\n|-VarDecl 'local', name = 'a1', type = 'any'\n|   Initializer\n|     LiteralExpr LK_NULL\n|-VarDecl 'local', name = 'a2', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 123456\n|-VarDecl 'local', name = 'a3', type = 'any'\n|   Initializer\n|     LiteralExpr LK_FLOAT 123.250000\n|-VarDecl 'local', name = 'a4', type = 'any'\n|   Initializer\n|     LiteralExpr LK_FLOAT 3499999887360.000000\n|-VarDecl 'local', name = 'a5', type = 'any'\n|   Initializer\n|     LiteralExpr LK_FLOAT 3499999887360.000000\n|-VarDecl 'local', name = 'a6', type = 'any'\n|   Initializer\n|     LiteralExpr LK_FLOAT 0.000000\n|-VarDecl 'local', name = 'a7', type = 'any'\n|   Initializer\n|     LiteralExpr LK_FLOAT -0.000000\n|-VarDecl 'local', name = 'a8', type = 'any'\n|   Initializer\n|     LiteralExpr LK_BOOL true\n|-VarDecl 'local', name = 'a9', type = 'any'\n|   Initializer\n|     LiteralExpr LK_BOOL false\n|-VarDecl 'local', name = 'a10', type = 'any'\n|   Initializer\n|     LiteralExpr LK_STRING \"\tlocal_str1ﷰ\"\n|-VarDecl 'local', name = 'a11', type = 'any'\n|   Initializer\n|     LiteralExpr LK_STRING \"local_str2\nlocal_str3\"\n|-VarDecl 'local', name = 'a12', type = 'any'\n|   Initializer\n|     CallExpr\n|     |-Callee\n|     |   GetFieldExpr '.' fieldName = 'subst'\n|     |     Receiver\n|     |       LiteralExpr LK_STRING \"a9={0}\"\n|     `-Arguments\n|         Argument #1\n|           Id 'a9'\n|-VarDecl 'local', name = 'a13', type = 'any'\n|   Initializer\n|     CallExpr\n|       Callee\n|         GetFieldExpr '.' fieldName = 'tofloat'\n|           Receiver\n|             UnExpr '('\n|               LiteralExpr LK_INT 123458\n|-VarDecl 'local', name = 'a14', type = 'any'\n|   Initializer\n|     CallExpr\n|       Callee\n|         GetFieldExpr '.' fieldName = 'tostring'\n|           Receiver\n|             UnExpr '('\n|               LiteralExpr LK_FLOAT 12.450000\n|-DeclGroup\n| |-VarDecl 'local', name = 'm3', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 301\n| `-VarDecl 'local', name = 'm4', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 302\n|-VarDecl 'local', name = 'a15', type = 'any'\n|   Initializer\n|     GetFieldExpr '.' fieldName = 'AA'\n|       Receiver\n|         Id 'Enum9'\n|-VarDecl 'local', name = 'a16', type = 'any'\n|   Initializer\n|     BinExpr '='\n|     |-Left\n|     |   Id 'm4'\n|     `-Right\n|         LiteralExpr LK_INT 303\n|-VarDecl 'let', name = 'b0', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 1025\n|-VarDecl 'let', name = 'b1', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 67305386\n|-VarDecl 'let', name = 'b2', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 66\n|-VarDecl 'let', name = 'b3', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 10\n|-VarDecl 'let', name = 'b4', type = 'any'\n|   Initializer\n|     CallExpr\n|       Callee\n|         GetFieldExpr '.' fieldName = 'tochar'\n|           Receiver\n|             LiteralExpr LK_INT 9\n|-VarDecl 'let', name = 'e0', type = 'any'\n|   Initializer\n|     ArrayExpr\n|-VarDecl 'let', name = 'e1', type = 'any'\n|   Initializer\n|     ArrayExpr\n|       Element #1\n|         LiteralExpr LK_INT 501\n|-VarDecl 'let', name = 'e2', type = 'any'\n|   Initializer\n|     ArrayExpr\n|       Element #1\n|         LiteralExpr LK_INT 502\n|-VarDecl 'let', name = 'e3', type = 'any'\n|   Initializer\n|     ArrayExpr\n|     |-Element #1\n|     |   LiteralExpr LK_INT 503\n|     `-Element #2\n|         LiteralExpr LK_INT 504\n|-VarDecl 'let', name = 'e4', type = 'any'\n|   Initializer\n|     ArrayExpr\n|     |-Element #1\n|     |   LiteralExpr LK_INT 505\n|     `-Element #2\n|         LiteralExpr LK_INT 506\n|-VarDecl 'let', name = 'e5', type = 'any'\n|   Initializer\n|     ArrayExpr\n|     |-Element #1\n|     |   LiteralExpr LK_INT 507\n|     `-Element #2\n|         LiteralExpr LK_INT 508\n|-VarDecl 'let', name = 'e6', type = 'any'\n|   Initializer\n|     ArrayExpr\n|     |-Element #1\n|     |   LiteralExpr LK_INT 509\n|     `-Element #2\n|         LiteralExpr LK_INT 510\n|-VarDecl 'let', name = 'e7', type = 'any'\n|   Initializer\n|     ArrayExpr\n|     |-Element #1\n|     |   LiteralExpr LK_INT 511\n|     `-Element #2\n|         LiteralExpr LK_INT 512\n|-VarDecl 'let', name = 't0', type = 'any'\n|   Initializer\n|     TableExpr\n|-VarDecl 'let', name = 't1', type = 'any'\n|   Initializer\n|     TableExpr\n|       Field\n|       |-Key\n|       |   LiteralExpr LK_STRING \"x\"\n|       `-Value\n|           LiteralExpr LK_INT 601\n|-VarDecl 'let', name = 't2', type = 'any'\n|   Initializer\n|     TableExpr\n|       Field\n|       |-Key\n|       |   LiteralExpr LK_STRING \"x\"\n|       `-Value\n|           LiteralExpr LK_INT 602\n|-VarDecl 'let', name = 't3', type = 'any'\n|   Initializer\n|     TableExpr\n|       Field\n|       |-Key\n|       |   LiteralExpr LK_STRING \"x\"\n|       `-Value\n|           LiteralExpr LK_INT 603\n|-VarDecl 'let', name = 't4', type = 'any'\n|   Initializer\n|     TableExpr\n|       Field\n|       |-Key\n|       |   LiteralExpr LK_NULL\n|       `-Value\n|           LiteralExpr LK_INT 604\n|-VarDecl 'let', name = 't5', type = 'any'\n|   Initializer\n|     TableExpr\n|       Field\n|       |-Key\n|       |   UnExpr '('\n|       |     TableExpr\n|       |       Field\n|       |       |-Key\n|       |       |   LiteralExpr LK_STRING \"y\"\n|       |       `-Value\n|       |           LiteralExpr LK_INT 605\n|       `-Value\n|           LiteralExpr LK_INT 606\n|-VarDecl 'let', name = 't6', type = 'any'\n|   Initializer\n|     TableExpr\n|       Field\n|       |-Key\n|       |   LiteralExpr LK_STRING \"a2\"\n|       `-Value\n|           Id 'a2'\n|-VarDecl 'let', name = 't7', type = 'any'\n|   Initializer\n|     TableExpr\n|     |-Field\n|     | |-Key\n|     | |   LiteralExpr LK_STRING \"a3\"\n|     | `-Value\n|     |     Id 'a3'\n|     `-Field\n|       |-Key\n|       |   LiteralExpr LK_STRING \"a8\"\n|       `-Value\n|           Id 'a8'\n|-VarDecl 'let', name = 't8', type = 'any'\n|   Initializer\n|     CallExpr\n|     |-Callee\n|     |   GetFieldExpr '.' fieldName = '__merge'\n|     |     Receiver\n|     |       TableExpr\n|     |         Field\n|     |         |-Key\n|     |         |   LiteralExpr LK_STRING \"x\"\n|     |         `-Value\n|     |             LiteralExpr LK_INT 1\n|     `-Arguments\n|         Argument #1\n|           TableExpr\n|             Field\n|             |-Key\n|             |   LiteralExpr LK_STRING \"y\"\n|             `-Value\n|                 LiteralExpr LK_INT 607\n|-VarDecl 'let', name = 't9', type = 'any'\n|   Initializer\n|     UnExpr 'CLONE'\n|       TableExpr\n|         Field\n|         |-Key\n|         |   LiteralExpr LK_STRING \"z\"\n|         `-Value\n|             LiteralExpr LK_INT 608\n|-ExprStatement\n|   BinExpr '<-'\n|   |-Left\n|   |   GetFieldExpr '.' fieldName = 'x'\n|   |     Receiver\n|   |       Id 'tab'\n|   `-Right\n|       LiteralExpr LK_STRING \"new_slot_str1\"\n|-ExprStatement\n|   BinExpr '<-'\n|   |-Left\n|   |   GetSlotExpr '['\n|   |   |-Receiver\n|   |   |   Id 'tab'\n|   |   `-Key\n|   |       LiteralExpr LK_STRING \"y\"\n|   `-Right\n|       LiteralExpr LK_STRING \"new_slot_str2\"\n|-DestructuringDecl type = 'table'\n| |-Initializer\n| |   Id 'cn3'\n| `-VarDecl 'local', name = 'abc', type = 'any'\n|-Block isRoot = 0, isBody = 0\n|   DestructuringDecl type = 'table'\n|   |-Initializer\n|   |   Id 't8'\n|   `-VarDecl 'local', name = 'y', type = 'any'\n|-Block isRoot = 0, isBody = 0\n| |-DestructuringDecl type = 'table'\n| | |-Initializer\n| | |   Id 't2'\n| | |-VarDecl 'local', name = 'y', type = 'any'\n| | |   Initializer\n| | |     LiteralExpr LK_INT 609\n| | `-VarDecl 'local', name = 'x', type = 'any'\n| `-ExprStatement\n|     CallExpr\n|     |-Callee\n|     |   Id 'println'\n|     `-Arguments\n|         Argument #1\n|           Id 'x'\n|-Block isRoot = 0, isBody = 0\n| |-DestructuringDecl type = 'table'\n| | |-Initializer\n| | |   Id 't2'\n| | |-VarDecl 'local', name = 'y', type = 'int'\n| | |   Initializer\n| | |     LiteralExpr LK_INT 609\n| | `-VarDecl 'local', name = 'x', type = 'int|string|null'\n| `-ExprStatement\n|     CallExpr\n|     |-Callee\n|     |   Id 'println'\n|     `-Arguments\n|         Argument #1\n|           Id 'x'\n|-DestructuringDecl type = 'array'\n| |-Initializer\n| |   Id 'e3'\n| |-VarDecl 'local', name = 'd1', type = 'any'\n| `-VarDecl 'local', name = 'd2', type = 'any'\n|-DestructuringDecl type = 'array'\n| |-Initializer\n| |   Id 'e3'\n| |-VarDecl 'local', name = 'd11', type = 'int'\n| `-VarDecl 'local', name = 'd12', type = 'int|null'\n|-DestructuringDecl type = 'array'\n| |-Initializer\n| |   Id 'e3'\n| |-VarDecl 'local', name = 'd21', type = 'any'\n| `-VarDecl 'local', name = 'd22', type = 'int|null'\n|-DestructuringDecl type = 'array'\n| |-Initializer\n| |   Id 'e3'\n| |-VarDecl 'local', name = 'd31', type = 'int'\n| `-VarDecl 'local', name = 'd32', type = 'any'\n|-VarDecl 'let', name = 'type_test1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test1', pure = 0, nodiscard = 0, resultType = 'int'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'int'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   LiteralExpr LK_INT 1\n|             `-Right\n|                 Id 'x'\n|-VarDecl 'let', name = 'type_test2', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test2', pure = 0, nodiscard = 0, resultType = 'int'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'int'\n|     | |-Parameter #2 name = 'vargv', type = 'float'  (vararg)\n|     | `-Vararg...\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   LiteralExpr LK_INT 1\n|             `-Right\n|                 Id 'x'\n|-VarDecl 'let', name = 'type_test3', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test3', pure = 0, nodiscard = 0, resultType = 'number|null'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'number|null'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   LiteralExpr LK_FLOAT 1.000000\n|             `-Right\n|                 UnExpr '('\n|                   BinExpr '??'\n|                   |-Left\n|                   |   Id 'x'\n|                   `-Right\n|                       LiteralExpr LK_INT 5\n|-VarDecl 'let', name = 'type_test4', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test4', pure = 0, nodiscard = 0, resultType = 'number|null'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'number|null'  (has default)\n|     |     DefaultValue\n|     |       LiteralExpr LK_NULL\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   LiteralExpr LK_FLOAT 1.000000\n|             `-Right\n|                 UnExpr '('\n|                   BinExpr '??'\n|                   |-Left\n|                   |   Id 'x'\n|                   `-Right\n|                       LiteralExpr LK_INT 6\n|-VarDecl 'let', name = 'type_test5', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test5', pure = 0, nodiscard = 0, resultType = 'number|null'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'number|null'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   LiteralExpr LK_FLOAT 1.000000\n|             `-Right\n|                 UnExpr '('\n|                   BinExpr '??'\n|                   |-Left\n|                   |   Id 'x'\n|                   `-Right\n|                       LiteralExpr LK_INT 5\n|-VarDecl 'let', name = 'type_test6', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test6', pure = 0, nodiscard = 0, resultType = 'number'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'number|null'  (has default)\n|     |     DefaultValue\n|     |       LiteralExpr LK_NULL\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   LiteralExpr LK_FLOAT 1.000000\n|             `-Right\n|                 UnExpr '('\n|                   BinExpr '??'\n|                   |-Left\n|                   |   Id 'x'\n|                   `-Right\n|                       LiteralExpr LK_INT 6\n|-VarDecl 'let', name = 'type_test7', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'type_test7', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'bool|number|string|table|array|userdata|function|generator|userpointer|thread|instance|class|weakref|null'\n|     | `-Parameter #2 name = 'y', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 Id 'y'\n|-VarDecl 'let', name = 'type_test8', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = 'type_test8', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'bool|number|string|table|array|userdata|function|generator|userpointer|thread|instance|class|weakref|null'\n|     | `-Parameter #2 name = 'y', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             UnExpr '('\n|               BinExpr '+'\n|               |-Left\n|               |   Id 'x'\n|               `-Right\n|                   Id 'y'\n|-VarDecl 'let', name = 'type_test9', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = 'type_test9', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'bool|number|null'\n|     | `-Parameter #2 name = 'y', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             UnExpr '('\n|               BinExpr '+'\n|               |-Left\n|               |   Id 'x'\n|               `-Right\n|                   Id 'y'\n|-VarDecl 'let', name = 'type_test10', type = 'any'\n|   Initializer\n|     UnExpr '('\n|       FunctionExpr 'lambda' name = 'type_test10', pure = 1, nodiscard = 0, resultType = 'any'\n|       |-Parameters count = 2\n|       | |-Parameter #1 name = 'x', type = 'bool|number|null'\n|       | `-Parameter #2 name = 'y', type = 'any'\n|       `-Body\n|           Block isRoot = 0, isBody = 1\n|             ReturnStatement\n|               UnExpr '('\n|                 BinExpr '+'\n|                 |-Left\n|                 |   Id 'x'\n|                 `-Right\n|                     Id 'y'\n|-VarDecl 'let', name = 'x901', type = 'int'\n|   Initializer\n|     LiteralExpr LK_INT 5\n|-VarDecl 'local', name = 't902', type = 'table'\n|   Initializer\n|     TableExpr\n|-VarDecl 'local', name = 't903', type = 'table|array'\n|   Initializer\n|     TableExpr\n|-VarDecl 'let', name = 'C4', type = 'any'\n|   Initializer\n|     ClassExpr\n|     |-Key: <anonymous>\n|     `-Members\n|       |-LiteralExpr LK_BOOL true\n|       |-LiteralExpr LK_BOOL false\n|       |-FunctionExpr name = 'constructor', pure = 0, nodiscard = 0, resultType = 'any'\n|       | |-Parameters count = 0\n|       | `-Body\n|       |     Block isRoot = 0, isBody = 1\n|       |-FunctionExpr name = 'fn1', pure = 0, nodiscard = 0, resultType = 'any'\n|       | |-Parameters count = 0\n|       | `-Body\n|       |     Block isRoot = 0, isBody = 1\n|       |-FunctionExpr name = '(all_syntax.nut:174)', pure = 0, nodiscard = 0, resultType = 'any'\n|       | |-Parameters count = 0\n|       | `-Body\n|       |     Block isRoot = 0, isBody = 1\n|       |       ExprStatement\n|       |         CallExpr\n|       |           Callee\n|       |             GetFieldExpr '.' fieldName = 'fn1'\n|       |               Receiver\n|       |                 Id 'this'\n|       |-FunctionExpr name = 'fn3', pure = 0, nodiscard = 0, resultType = 'any'\n|       | |-Parameters count = 0\n|       | `-Body\n|       |     Block isRoot = 0, isBody = 1\n|       |       ExprStatement\n|       |         CallExpr\n|       |           Callee\n|       |             GetFieldExpr '.' fieldName = 'fn1'\n|       |               Receiver\n|       |                 Id 'this'\n|       |-FunctionExpr 'lambda' name = '(all_syntax.nut:176)', pure = 0, nodiscard = 0, resultType = 'any'\n|       | |-Parameters count = 0\n|       | `-Body\n|       |     Block isRoot = 0, isBody = 1\n|       |       ReturnStatement\n|       |         LiteralExpr LK_STRING \"class_str1\"\n|       |-FunctionExpr 'lambda' name = 'fn5', pure = 0, nodiscard = 0, resultType = 'any'\n|       | |-Parameters count = 0\n|       | `-Body\n|       |     Block isRoot = 0, isBody = 1\n|       |       ReturnStatement\n|       |         LiteralExpr LK_STRING \"class_str2\"\n|       `-FunctionExpr name = '(all_syntax.nut:178)', pure = 0, nodiscard = 0, resultType = 'any'\n|         |-Parameters count = 1\n|         |   Parameter #1 name = 'name', type = 'any'\n|         `-Body\n|             Block isRoot = 0, isBody = 1\n|             |-ExprStatement\n|             |   CallExpr\n|             |     Callee\n|             |       GetSlotExpr '['\n|             |       |-Receiver\n|             |       |   Id 'this'\n|             |       `-Key\n|             |           Id 'name'\n|             |-ExprStatement\n|             |   CallExpr\n|             |     Callee\n|             |       GetFieldExpr '.' fieldName = 'constructor'\n|             |         Receiver\n|             |           Id 'this'\n|             `-ExprStatement\n|                 BinExpr '<-'\n|                 |-Left\n|                 |   GetFieldExpr '.' fieldName = 'y'\n|                 |     Receiver\n|                 |       GetFieldExpr '.' fieldName = 'tab'\n|                 |         Receiver\n|                 |           RootTableAccessExpr\n|                 `-Right\n|                     LiteralExpr LK_INT 610\n|-VarDecl 'let', name = 'instance', type = 'any'\n|   Initializer\n|     CallExpr\n|       Callee\n|         Id 'C4'\n|-ExprStatement\n|   CallExpr\n|     Callee\n|       GetFieldExpr '.' fieldName = 'fn4'\n|         Receiver\n|           Id 'instance'\n|-ExprStatement\n|   CallExpr\n|     Callee\n|       GetFieldExpr '?.' fieldName = 'fn4'\n|         Receiver\n|           Id 'instance'\n|-ExprStatement\n|   CallExpr\n|     Callee\n|       GetSlotExpr '?['\n|       |-Receiver\n|       |   Id 'instance'\n|       `-Key\n|           LiteralExpr LK_STRING \"fn4\"\n|-ExprStatement\n|   CallExpr\n|     Callee\n|       GetFieldExpr '.' fieldName = 'fn4'\n|         Receiver\n|           Id 'instance'\n|-IfStatement\n| |-Condition\n| |   BinExpr 'INSTANCEOF'\n| |   |-Left\n| |   |   Id 'instance'\n| |   `-Right\n| |       Id 'C4'\n| `-ThenBranch\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'println'\n|         `-Arguments\n|             Argument #1\n|               LiteralExpr LK_STRING \"instance instanceof C4\"\n|-VarDecl 'let', name = 'gfn1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'gfn1', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|-VarDecl 'local', name = 'gfn2', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(all_syntax.nut:196)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ExprStatement\n|             CallExpr\n|               Callee\n|                 GetFieldExpr '.' fieldName = 'gfn1'\n|                   Receiver\n|                     Id 'this'\n|-VarDecl 'let', name = 'gfn3', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'gfn3', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ExprStatement\n|             CallExpr\n|               Callee\n|                 GetFieldExpr '.' fieldName = 'gfn1'\n|                   Receiver\n|                     Id 'this'\n|-VarDecl 'local', name = 'gfn4', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = '(all_syntax.nut:198)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_STRING \"lambda_str1\"\n|-VarDecl 'let', name = 'gfn5', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = 'gfn5', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_STRING \"lambda_str2\"\n|-VarDecl 'local', name = '_call', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(all_syntax.nut:200)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'name', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ExprStatement\n|             CallExpr\n|               Callee\n|                 GetSlotExpr '['\n|                 |-Receiver\n|                 |   Id 'this'\n|                 `-Key\n|                     Id 'name'\n|-VarDecl 'let', name = 'gfn_pure', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = 'gfn5', pure = 1, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_STRING \"lambda_str3\"\n|-VarDecl 'let', name = 'gfn_nodiscard', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = 'gfn6', pure = 0, nodiscard = 1, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_STRING \"lambda_str4\"\n|-VarDecl 'let', name = 'gfn_pure_nodiscard', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = 'gfn7', pure = 1, nodiscard = 1, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_STRING \"lambda_str5\"\n|-VarDecl 'let', name = 'fa1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa1', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'x'\n|-VarDecl 'let', name = 'fa2', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa2', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | `-Parameter #2 name = 'y', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 Id 'y'\n|-VarDecl 'let', name = 'fa3', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa3', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 3\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | |-Parameter #2 name = 'y', type = 'any'\n|     | `-Parameter #3 name = 'z', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 BinExpr '*'\n|                 |-Left\n|                 |   Id 'y'\n|                 `-Right\n|                     Id 'z'\n|-VarDecl 'let', name = 'fa4', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa4', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | |-Parameter #2 name = 'vargv', type = 'any'  (vararg)\n|     | `-Vararg...\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 CallExpr\n|                   Callee\n|                     GetFieldExpr '.' fieldName = 'len'\n|                       Receiver\n|                         Id 'vargv'\n|-VarDecl 'let', name = 'fa5', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa5', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'  (has default)\n|     |     DefaultValue\n|     |       ArrayExpr\n|     |       |-Element #1\n|     |       |   LiteralExpr LK_INT 1\n|     |       `-Element #2\n|     |           LiteralExpr LK_INT 2\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             GetSlotExpr '?['\n|             |-Receiver\n|             |   Id 'x'\n|             `-Key\n|                 LiteralExpr LK_INT 1\n|-VarDecl 'let', name = 'fa6', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa6', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | `-Parameter #2 name = 'y', type = 'any'  (has default)\n|     |     DefaultValue\n|     |       LiteralExpr LK_NULL\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'y'\n|-VarDecl 'let', name = 'fa7', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa7', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | `-Parameter #2 name = 'y', type = 'any'  (has default)\n|     |     DefaultValue\n|     |       TableExpr\n|     |         Field\n|     |         |-Key\n|     |         |   LiteralExpr LK_STRING \"a\"\n|     |         `-Value\n|     |             LiteralExpr LK_INT 4\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'y'\n|-VarDecl 'let', name = 'fa8', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fa8', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | `-Parameter #2 name = 'y', type = 'any'  (has default)\n|     |     DefaultValue\n|     |       TableExpr\n|     |         Field\n|     |         |-Key\n|     |         |   LiteralExpr LK_STRING \"a\"\n|     |         `-Value\n|     |             LiteralExpr LK_INT 5\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'y'\n|-VarDecl 'let', name = 'pure_fn', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'pure_fn', pure = 1, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '*'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 Id 'x'\n|-VarDecl 'let', name = 'pure_nodiscard_fn', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'pure_nodiscard_fn', pure = 1, nodiscard = 1, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '*'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 Id 'x'\n|-VarDecl 'let', name = 'coroutine_fn', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'coroutine_fn', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-YieldStatement\n|         |   LiteralExpr LK_INT 1100\n|         `-YieldStatement\n|             LiteralExpr LK_INT 1200\n|-ExprStatement\n|   CallExpr\n|   |-Callee\n|   |   Id 'println'\n|   `-Arguments\n|       Argument #1\n|         UnExpr 'RESUME'\n|           CallExpr\n|             Callee\n|               Id 'coroutine_fn'\n|-VarDecl 'let', name = 'des1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des1', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = '@arg1', type = 'table|instance|class'\n|     |     Destructuring\n|     |       DestructuringDecl type = 'table'\n|     |       |-Initializer\n|     |       |   Id '@arg1'\n|     |       `-VarDecl 'let', name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 LiteralExpr LK_INT 1\n|-VarDecl 'let', name = 'des2', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des2', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = '@arg1', type = 'array'\n|     |     Destructuring\n|     |       DestructuringDecl type = 'array'\n|     |       |-Initializer\n|     |       |   Id '@arg1'\n|     |       `-VarDecl 'let', name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 LiteralExpr LK_INT 1\n|-VarDecl 'let', name = 'des3', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des3', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = '@arg1', type = 'array'\n|     | |   Destructuring\n|     | |     DestructuringDecl type = 'array'\n|     | |     |-Initializer\n|     | |     |   Id '@arg1'\n|     | |     `-VarDecl 'let', name = 'x', type = 'any'\n|     | `-Parameter #2 name = '@arg2', type = 'table|instance|class'\n|     |     Destructuring\n|     |       DestructuringDecl type = 'table'\n|     |       |-Initializer\n|     |       |   Id '@arg2'\n|     |       `-VarDecl 'let', name = 'y', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 Id 'y'\n|-VarDecl 'let', name = 'des4', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des4', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = '@arg1', type = 'array'\n|     | |   Destructuring\n|     | |     DestructuringDecl type = 'array'\n|     | |     |-Initializer\n|     | |     |   Id '@arg1'\n|     | |     |-VarDecl 'let', name = 'x', type = 'any'\n|     | |     |-VarDecl 'let', name = 'z', type = 'any'\n|     | |     `-VarDecl 'let', name = 'w', type = 'any'\n|     | `-Parameter #2 name = '@arg2', type = 'table|instance|class'\n|     |     Destructuring\n|     |       DestructuringDecl type = 'table'\n|     |       |-Initializer\n|     |       |   Id '@arg2'\n|     |       `-VarDecl 'let', name = 'y', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 Id 'y'\n|-VarDecl 'let', name = 'des5', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des5', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | `-Parameter #2 name = '@arg2', type = 'table|instance|class'\n|     |     Destructuring\n|     |       DestructuringDecl type = 'table'\n|     |       |-Initializer\n|     |       |   Id '@arg2'\n|     |       `-VarDecl 'let', name = 'y', type = 'any'\n|     |           Initializer\n|     |             LiteralExpr LK_NULL\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 UnExpr '('\n|                   BinExpr '??'\n|                   |-Left\n|                   |   Id 'y'\n|                   `-Right\n|                       LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'des6', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des6', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'x', type = 'any'\n|     | `-Parameter #2 name = '@arg2', type = 'table|instance|class'\n|     |     Destructuring\n|     |       DestructuringDecl type = 'table'\n|     |       |-Initializer\n|     |       |   Id '@arg2'\n|     |       |-VarDecl 'let', name = 'y', type = 'any'\n|     |       |   Initializer\n|     |       |     LiteralExpr LK_NULL\n|     |       `-VarDecl 'let', name = 'z', type = 'number'\n|     |           Initializer\n|     |             LiteralExpr LK_INT 1000\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   BinExpr '+'\n|             |   |-Left\n|             |   |   Id 'x'\n|             |   `-Right\n|             |       UnExpr '('\n|             |         BinExpr '??'\n|             |         |-Left\n|             |         |   Id 'y'\n|             |         `-Right\n|             |             LiteralExpr LK_INT 2\n|             `-Right\n|                 Id 'z'\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = '(all_syntax.nut:230)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_NULL\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = '(all_syntax.nut:230)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id '$ch0'\n|-VarDecl 'let', name = '$ch2', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = '(all_syntax.nut:230)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id '$ch1'\n|-VarDecl 'let', name = 'des7', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'des7', pure = 1, nodiscard = 1, resultType = 'any'\n|     |-Parameters count = 3\n|     | |-Parameter #1 name = '@arg1', type = 'array'\n|     | |   Destructuring\n|     | |     DestructuringDecl type = 'array'\n|     | |     |-Initializer\n|     | |     |   Id '@arg1'\n|     | |     |-VarDecl 'let', name = 'x', type = 'function'\n|     | |     |   Initializer\n|     | |     |     Id '$ch2'\n|     | |     |-VarDecl 'let', name = 't', type = 'any'\n|     | |     |-VarDecl 'let', name = 'r', type = 'string'\n|     | |     |   Initializer\n|     | |     |     LiteralExpr LK_STRING \"abc555\"\n|     | |     `-VarDecl 'let', name = 'g', type = 'any'\n|     | |         Initializer\n|     | |           LiteralExpr LK_STRING \"abc666\"\n|     | |-Parameter #2 name = '@arg2', type = 'table|instance|class'\n|     | |   Destructuring\n|     | |     DestructuringDecl type = 'table'\n|     | |     |-Initializer\n|     | |     |   Id '@arg2'\n|     | |     |-VarDecl 'let', name = 'y', type = 'any'\n|     | |     |   Initializer\n|     | |     |     LiteralExpr LK_NULL\n|     | |     `-VarDecl 'let', name = 'z', type = 'number'\n|     | |         Initializer\n|     | |           LiteralExpr LK_INT 1000\n|     | |-Parameter #3 name = 'vargv', type = 'any'  (vararg)\n|     | `-Vararg...\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-DestructuringDecl type = 'table'\n|         | |-Initializer\n|         | |   Id 't'\n|         | |-VarDecl 'let', name = 'p', type = 'any'\n|         | `-VarDecl 'let', name = 'i', type = 'any'\n|         |-ExprStatement\n|         |   CallExpr\n|         |     Callee\n|         |       Id 'println'\n|         `-ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   BinExpr '+'\n|             |   |-Left\n|             |   |   Id 'x'\n|             |   `-Right\n|             |       UnExpr '('\n|             |         BinExpr '??'\n|             |         |-Left\n|             |         |   Id 'y'\n|             |         `-Right\n|             |             LiteralExpr LK_INT 2\n|             `-Right\n|                 Id 'z'\n|-VarDecl 'let', name = 'i0', type = 'any'\n|   Initializer\n|     BinExpr '+'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i1', type = 'any'\n|   Initializer\n|     BinExpr '-'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i2', type = 'any'\n|   Initializer\n|     BinExpr '*'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i3', type = 'any'\n|   Initializer\n|     BinExpr '/'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i4', type = 'any'\n|   Initializer\n|     BinExpr '%'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i5', type = 'any'\n|   Initializer\n|     BinExpr '^'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i6', type = 'any'\n|   Initializer\n|     BinExpr '&'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i7', type = 'any'\n|   Initializer\n|     BinExpr '|'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i8', type = 'any'\n|   Initializer\n|     BinExpr '||'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i9', type = 'any'\n|   Initializer\n|     BinExpr '&&'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i10', type = 'any'\n|   Initializer\n|     BinExpr '=='\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i11', type = 'any'\n|   Initializer\n|     BinExpr '!='\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i12', type = 'any'\n|   Initializer\n|     BinExpr '<'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i13', type = 'any'\n|   Initializer\n|     BinExpr '>'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i14', type = 'any'\n|   Initializer\n|     BinExpr '<='\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i15', type = 'any'\n|   Initializer\n|     BinExpr '>='\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i16', type = 'any'\n|   Initializer\n|     BinExpr '<=>'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i17', type = 'any'\n|   Initializer\n|     UnExpr '-'\n|       UnExpr '('\n|         LiteralExpr LK_INT 123\n|-VarDecl 'let', name = 'i18', type = 'any'\n|   Initializer\n|     UnExpr '~'\n|       UnExpr '('\n|         LiteralExpr LK_INT 123\n|-VarDecl 'let', name = 'i19', type = 'any'\n|   Initializer\n|     UnExpr '!'\n|       UnExpr '('\n|         LiteralExpr LK_INT 123\n|-VarDecl 'let', name = 'i20', type = 'any'\n|   Initializer\n|     UnExpr 'TYPEOF'\n|       LiteralExpr LK_INT 123\n|-VarDecl 'let', name = 'i21', type = 'any'\n|   Initializer\n|     UnExpr 'INLINE_CONST'\n|       LiteralExpr LK_INT 123\n|-VarDecl 'let', name = 'i22', type = 'any'\n|   Initializer\n|     UnExpr 'STATIC_MEMO'\n|       LiteralExpr LK_INT 123\n|-VarDecl 'let', name = 'i23', type = 'any'\n|   Initializer\n|     BinExpr 'IN'\n|     |-Left\n|     |   LiteralExpr LK_STRING \"x\"\n|     `-Right\n|         TableExpr\n|           Field\n|           |-Key\n|           |   LiteralExpr LK_STRING \"x\"\n|           `-Value\n|               LiteralExpr LK_INT 5\n|-VarDecl 'let', name = 'i24', type = 'any'\n|   Initializer\n|     UnExpr '!'\n|       BinExpr 'IN'\n|       |-Left\n|       |   LiteralExpr LK_STRING \"x\"\n|       `-Right\n|           TableExpr\n|             Field\n|             |-Key\n|             |   LiteralExpr LK_STRING \"x\"\n|             `-Value\n|                 LiteralExpr LK_INT 6\n|-VarDecl 'let', name = 'i25', type = 'any'\n|   Initializer\n|     BinExpr '>>'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i26', type = 'any'\n|   Initializer\n|     BinExpr '<<'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i27', type = 'any'\n|   Initializer\n|     BinExpr '>>>'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'let', name = 'i28', type = 'any'\n|   Initializer\n|     BinExpr '??'\n|     |-Left\n|     |   LiteralExpr LK_INT 1\n|     `-Right\n|         LiteralExpr LK_INT 2\n|-VarDecl 'local', name = 'iv', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 123\n|-ExprStatement\n|   IncExpr IF_POSTFIX '++'\n|     Id 'iv'\n|-ExprStatement\n|   IncExpr IF_POSTFIX '--'\n|     Id 'iv'\n|-ExprStatement\n|   IncExpr IF_PREFIX '--'\n|     Id 'iv'\n|-ExprStatement\n|   IncExpr IF_PREFIX '++'\n|     Id 'iv'\n|-ExprStatement\n|   BinExpr '+='\n|   |-Left\n|   |   Id 'iv'\n|   `-Right\n|       LiteralExpr LK_INT 123\n|-ExprStatement\n|   BinExpr '-='\n|   |-Left\n|   |   Id 'iv'\n|   `-Right\n|       LiteralExpr LK_INT 123\n|-ExprStatement\n|   BinExpr '*='\n|   |-Left\n|   |   Id 'iv'\n|   `-Right\n|       LiteralExpr LK_INT 123\n|-ExprStatement\n|   BinExpr '/='\n|   |-Left\n|   |   Id 'iv'\n|   `-Right\n|       LiteralExpr LK_INT 123\n|-ExprStatement\n|   BinExpr '%='\n|   |-Left\n|   |   Id 'iv'\n|   `-Right\n|       LiteralExpr LK_INT 123\n|-IfStatement\n| |-Condition\n| |   BaseExpr\n| `-ThenBranch\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'println'\n|         `-Arguments\n|             Argument #1\n|               LiteralExpr LK_STRING \"base != null\"\n|-Block isRoot = 0, isBody = 0\n| |-EmptyStatement\n| |-EmptyStatement\n| |-EmptyStatement\n| |-EmptyStatement\n| |-EmptyStatement\n| `-EmptyStatement\n|-IfStatement\n| |-Condition\n| |   BinExpr '=='\n| |   |-Left\n| |   |   LiteralExpr LK_INT 701\n| |   `-Right\n| |       LiteralExpr LK_INT 701\n| `-ThenBranch\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'fa1'\n|         `-Arguments\n|             Argument #1\n|               LiteralExpr LK_INT 701\n|-IfStatement\n| |-Condition\n| |   BinExpr '=='\n| |   |-Left\n| |   |   LiteralExpr LK_INT 702\n| |   `-Right\n| |       LiteralExpr LK_INT 703\n| |-ThenBranch\n| |   Block isRoot = 0, isBody = 0\n| |     ExprStatement\n| |       CallExpr\n| |       |-Callee\n| |       |   Id 'fa1'\n| |       `-Arguments\n| |           Argument #1\n| |             LiteralExpr LK_INT 702\n| `-ElseBranch\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'fa2'\n|         `-Arguments\n|           |-Argument #1\n|           |   LiteralExpr LK_INT 703\n|           `-Argument #2\n|               LiteralExpr LK_INT 704\n|-IfStatement\n| |-Condition\n| |   BinExpr '=='\n| |   |-Left\n| |   |   LiteralExpr LK_INT 705\n| |   `-Right\n| |       LiteralExpr LK_INT 706\n| |-ThenBranch\n| |   Block isRoot = 0, isBody = 0\n| |     ExprStatement\n| |       CallExpr\n| |       |-Callee\n| |       |   Id 'fa1'\n| |       `-Arguments\n| |           Argument #1\n| |             LiteralExpr LK_INT 707\n| `-ElseBranch\n|     Block isRoot = 0, isBody = 0\n|       IfStatement\n|       |-Condition\n|       |   BinExpr '=='\n|       |   |-Left\n|       |   |   LiteralExpr LK_INT 708\n|       |   `-Right\n|       |       LiteralExpr LK_INT 709\n|       |-ThenBranch\n|       |   Block isRoot = 0, isBody = 0\n|       |     ExprStatement\n|       |       CallExpr\n|       |       |-Callee\n|       |       |   Id 'fa2'\n|       |       `-Arguments\n|       |         |-Argument #1\n|       |         |   LiteralExpr LK_INT 710\n|       |         `-Argument #2\n|       |             LiteralExpr LK_INT 711\n|       `-ElseBranch\n|           Block isRoot = 0, isBody = 0\n|             ExprStatement\n|               CallExpr\n|               |-Callee\n|               |   Id 'fa2'\n|               `-Arguments\n|                 |-Argument #1\n|                 |   LiteralExpr LK_INT 712\n|                 `-Argument #2\n|                     LiteralExpr LK_INT 713\n|-Block isRoot = 0, isBody = 0\n| |-VarDecl 'local', name = 'cv', type = 'any'\n| |   Initializer\n| |     Id 'iv'\n| `-IfStatement\n|   |-Condition\n|   |   Id 'cv'\n|   `-ThenBranch\n|       Block isRoot = 0, isBody = 0\n|         ExprStatement\n|           CallExpr\n|           |-Callee\n|           |   Id 'println'\n|           `-Arguments\n|               Argument #1\n|                 Id 'cv'\n|-Block isRoot = 0, isBody = 0\n| |-VarDecl 'local', name = 'cv', type = 'int|null'\n| |   Initializer\n| |     Id 'iv'\n| `-IfStatement\n|   |-Condition\n|   |   Id 'cv'\n|   |-ThenBranch\n|   |   Block isRoot = 0, isBody = 0\n|   |     ExprStatement\n|   |       CallExpr\n|   |       |-Callee\n|   |       |   Id 'println'\n|   |       `-Arguments\n|   |           Argument #1\n|   |             Id 'cv'\n|   `-ElseBranch\n|       Block isRoot = 0, isBody = 0\n|         ExprStatement\n|           CallExpr\n|           |-Callee\n|           |   Id 'println'\n|           `-Arguments\n|               Argument #1\n|                 BinExpr '-'\n|                 |-Left\n|                 |   Id 'cv'\n|                 `-Right\n|                     LiteralExpr LK_INT 1\n|-Block isRoot = 0, isBody = 0\n| |-VarDecl 'let', name = 'cv', type = 'int'\n| |   Initializer\n| |     Id 'iv'\n| `-IfStatement\n|   |-Condition\n|   |   BinExpr '>'\n|   |   |-Left\n|   |   |   Id 'cv'\n|   |   `-Right\n|   |       LiteralExpr LK_INT -1000000\n|   `-ThenBranch\n|       Block isRoot = 0, isBody = 0\n|         ExprStatement\n|           CallExpr\n|           |-Callee\n|           |   Id 'println'\n|           `-Arguments\n|               Argument #1\n|                 Id 'cv'\n|-Block isRoot = 0, isBody = 0\n| |-VarDecl 'local', name = 'cv', type = 'any'\n| |   Initializer\n| |     Id 'iv'\n| `-IfStatement\n|   |-Condition\n|   |   Id 'cv'\n|   |-ThenBranch\n|   |   Block isRoot = 0, isBody = 0\n|   |     ExprStatement\n|   |       CallExpr\n|   |       |-Callee\n|   |       |   Id 'println'\n|   |       `-Arguments\n|   |           Argument #1\n|   |             Id 'cv'\n|   `-ElseBranch\n|       Block isRoot = 0, isBody = 0\n|         Block isRoot = 0, isBody = 0\n|         |-VarDecl 'local', name = 'cv2', type = 'any'\n|         |   Initializer\n|         |     Id 'iv'\n|         `-IfStatement\n|           |-Condition\n|           |   Id 'cv2'\n|           `-ThenBranch\n|               Block isRoot = 0, isBody = 0\n|                 ExprStatement\n|                   CallExpr\n|                   |-Callee\n|                   |   Id 'println'\n|                   `-Arguments\n|                       Argument #1\n|                         LiteralExpr LK_STRING \"fail\"\n|-WhileStatement\n| |-Condition\n| |   IncExpr IF_POSTFIX '--'\n| |     Id 'iv'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'fa1'\n|         `-Arguments\n|             Argument #1\n|               LiteralExpr LK_INT 714\n|-DoWhileStatement\n| |-Body\n| |   Block isRoot = 0, isBody = 0\n| |     ExprStatement\n| |       CallExpr\n| |       |-Callee\n| |       |   Id 'fa1'\n| |       `-Arguments\n| |           Argument #1\n| |             LiteralExpr LK_INT 715\n| `-Condition\n|     BinExpr '<'\n|     |-Left\n|     |   IncExpr IF_POSTFIX '++'\n|     |     Id 'iv'\n|     `-Right\n|         LiteralExpr LK_INT 3\n|-ForeachStatement\n| |-ValueVariable\n| |   VarDecl 'let', name = 'i', type = 'any'\n| |-Container\n| |   Id 'e1'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'fa1'\n|         `-Arguments\n|             Argument #1\n|               Id 'i'\n|-ForeachStatement\n| |-IndexVariable\n| |   VarDecl 'let', name = 'k', type = 'any'\n| |-ValueVariable\n| |   VarDecl 'let', name = 'v', type = 'any'\n| |-Container\n| |   Id 't7'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'fa2'\n|         `-Arguments\n|           |-Argument #1\n|           |   Id 'k'\n|           `-Argument #2\n|               Id 'v'\n|-ForStatement\n|   Body\n|     Block isRoot = 0, isBody = 0\n|       BreakStatement\n|-ForStatement\n| |-Initializer\n| |   VarDecl 'local', name = 'iter', type = 'any'\n| |     Initializer\n| |       LiteralExpr LK_INT 0\n| |-Condition\n| |   BinExpr '<'\n| |   |-Left\n| |   |   Id 'iter'\n| |   `-Right\n| |       LiteralExpr LK_INT 4\n| |-Modifier\n| |   IncExpr IF_PREFIX '++'\n| |     Id 'iter'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ContinueStatement\n|-ForStatement\n| |-Initializer\n| |   VarDecl 'local', name = 'iter', type = 'any'\n| |     Initializer\n| |       LiteralExpr LK_INT 0\n| |-Condition\n| |   BinExpr '<'\n| |   |-Left\n| |   |   Id 'iter'\n| |   `-Right\n| |       LiteralExpr LK_INT 4\n| |-Modifier\n| |   CommaExpr\n| |   |-Expression #1\n| |   |   BinExpr '+='\n| |   |   |-Left\n| |   |   |   Id 'iter'\n| |   |   `-Right\n| |   |       LiteralExpr LK_INT 2\n| |   `-Expression #2\n| |       IncExpr IF_POSTFIX '--'\n| |         Id 'iter'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ContinueStatement\n|-TryStatement\n| |-TryBlock\n| |   ExprStatement\n| |     CallExpr\n| |     |-Callee\n| |     |   Id 'fa1'\n| |     `-Arguments\n| |         Argument #1\n| |           LiteralExpr LK_INT 716\n| `-CatchBlock exceptionId = 'e'\n|     ExprStatement\n|       CallExpr\n|       |-Callee\n|       |   Id 'fa1'\n|       `-Arguments\n|           Argument #1\n|             LiteralExpr LK_INT 717\n|-TryStatement\n| |-TryBlock\n| |   ThrowStatement\n| |     LiteralExpr LK_NULL\n| `-CatchBlock exceptionId = 'e'\n|     ExprStatement\n|       CallExpr\n|       |-Callee\n|       |   Id 'fa1'\n|       `-Arguments\n|           Argument #1\n|             LiteralExpr LK_INT 718\n|-DirectiveStmt\n|-VarDecl 'local', name = 'w', type = 'any'\n|   Initializer\n|     CallExpr\n|       Callee\n|         Id 'getlocals'\n|-VarDecl 'local', name = 'res', type = 'any'\n|   Initializer\n|     ArrayExpr\n|-ForeachStatement\n| |-IndexVariable\n| |   VarDecl 'let', name = 'k', type = 'any'\n| |-ValueVariable\n| |   VarDecl 'let', name = 'v', type = 'any'\n| |-Container\n| |   Id 'w'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   GetFieldExpr '.' fieldName = 'append'\n|         |     Receiver\n|         |       Id 'res'\n|         `-Arguments\n|             Argument #1\n|               CallExpr\n|               |-Callee\n|               |   GetFieldExpr '.' fieldName = 'subst'\n|               |     Receiver\n|               |       LiteralExpr LK_STRING \"{0} = {1}\"\n|               `-Arguments\n|                 |-Argument #1\n|                 |   Id 'k'\n|                 `-Argument #2\n|                     TerExpr\n|                     |-Condition\n|                     |   BinExpr '>='\n|                     |   |-Left\n|                     |   |   CallExpr\n|                     |   |   |-Callee\n|                     |   |   |   GetFieldExpr '.' fieldName = 'indexof'\n|                     |   |   |     Receiver\n|                     |   |   |       ArrayExpr\n|                     |   |   |       |-Element #1\n|                     |   |   |       |   LiteralExpr LK_STRING \"integer\"\n|                     |   |   |       |-Element #2\n|                     |   |   |       |   LiteralExpr LK_STRING \"bool\"\n|                     |   |   |       |-Element #3\n|                     |   |   |       |   LiteralExpr LK_STRING \"string\"\n|                     |   |   |       `-Element #4\n|                     |   |   |           LiteralExpr LK_STRING \"float\"\n|                     |   |   `-Arguments\n|                     |   |       Argument #1\n|                     |   |         CallExpr\n|                     |   |         |-Callee\n|                     |   |         |   Id 'type'\n|                     |   |         `-Arguments\n|                     |   |             Argument #1\n|                     |   |               Id 'v'\n|                     |   `-Right\n|                     |       LiteralExpr LK_INT 0\n|                     |-TrueBranch\n|                     |   Id 'v'\n|                     `-FalseBranch\n|                         CallExpr\n|                         |-Callee\n|                         |   Id 'type'\n|                         `-Arguments\n|                             Argument #1\n|                               Id 'v'\n|-ExprStatement\n|   CallExpr\n|     Callee\n|       GetFieldExpr '.' fieldName = 'sort'\n|         Receiver\n|           Id 'res'\n|-ForeachStatement\n| |-IndexVariable\n| |   VarDecl 'let', name = '_', type = 'any'\n| |-ValueVariable\n| |   VarDecl 'let', name = 'v', type = 'any'\n| |-Container\n| |   Id 'res'\n| `-Body\n|     Block isRoot = 0, isBody = 0\n|       ExprStatement\n|         CallExpr\n|         |-Callee\n|         |   Id 'println'\n|         `-Arguments\n|             Argument #1\n|               Id 'v'\n|-VarDecl 'let', name = 'A', type = 'any'\n|   Initializer\n|     ClassExpr\n|     |-Key: <anonymous>\n|     `-Members\n|         FunctionExpr name = 'x', pure = 0, nodiscard = 0, resultType = 'any'\n|         |-Parameters count = 0\n|         `-Body\n|             Block isRoot = 0, isBody = 1\n|               ReturnStatement\n|                 LiteralExpr LK_INT 0\n|-VarDecl 'let', name = 'instance_a', type = 'any'\n|   Initializer\n|     CallExpr\n|       Callee\n|         Id 'A'\n|-VarDecl 'let', name = '$ch3', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(all_syntax.nut:396)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-EmptyStatement\n|         `-ReturnStatement\n|             LiteralExpr LK_INT 1234\n|-VarDecl 'let', name = 'test', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'test', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             TableExpr\n|             |-Field\n|             | |-Key\n|             | |   LiteralExpr LK_STRING \"x\"\n|             | `-Value\n|             |     LiteralExpr LK_INT 4\n|             `-Field\n|               |-Key\n|               |   LiteralExpr LK_STRING \"fn\"\n|               `-Value\n|                   Id '$ch3'\n|-ExprStatement\n|   CallExpr\n|   |-Callee\n|   |   Id 'println'\n|   `-Arguments\n|       Argument #1\n|         CallExpr\n|         |-Callee\n|         |   Id 'doc'\n|         `-Arguments\n|             Argument #1\n|               Id 'A'\n|-ExprStatement\n|   CallExpr\n|   |-Callee\n|   |   Id 'println'\n|   `-Arguments\n|       Argument #1\n|         CallExpr\n|         |-Callee\n|         |   Id 'doc'\n|         `-Arguments\n|             Argument #1\n|               Id 'instance_a'\n|-ExprStatement\n|   CallExpr\n|   |-Callee\n|   |   Id 'println'\n|   `-Arguments\n|       Argument #1\n|         CallExpr\n|         |-Callee\n|         |   Id 'doc'\n|         `-Arguments\n|             Argument #1\n|               CallExpr\n|                 Callee\n|                   Id 'test'\n|-ExprStatement\n|   CallExpr\n|   |-Callee\n|   |   Id 'println'\n|   `-Arguments\n|       Argument #1\n|         CallExpr\n|         |-Callee\n|         |   Id 'doc'\n|         `-Arguments\n|             Argument #1\n|               GetFieldExpr '.' fieldName = 'fn'\n|                 Receiver\n|                   CallExpr\n|                     Callee\n|                       Id 'test'\n`-ExprStatement\n    CallExpr\n    |-Callee\n    |   Id 'println'\n    `-Arguments\n        Argument #1\n          LiteralExpr LK_STRING \"done\"\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/classCrossFunc.nut",
    "content": "local z = 0\nfunction foo(x, y) {\n    return function() {\n        let c = class {\n            x = 10\n            function zed() {\n                return function () {\n                    return x + 10;\n                }() + this.x\n            }\n        }\n        return c().zed()\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/classCrossFunc.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'local', name = 'z', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 0\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = '$ch0', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = '(classCrossFunc.nut:7)', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             BinExpr '+'\n          |             |-Left\n          |             |   Id 'x'\n          |             `-Right\n          |                 LiteralExpr LK_INT 10\n          `-ReturnStatement\n              FunctionExpr name = '(classCrossFunc.nut:3)', pure = 0, nodiscard = 0, resultType = 'any'\n              |-Parameters count = 0\n              `-Body\n                  Block isRoot = 0, isBody = 1\n                  |-VarDecl 'let', name = 'c', type = 'any'\n                  |   Initializer\n                  |     ClassExpr\n                  |     |-Key: <anonymous>\n                  |     `-Members\n                  |       |-LiteralExpr LK_INT 10\n                  |       `-FunctionExpr name = 'zed', pure = 0, nodiscard = 0, resultType = 'any'\n                  |         |-Parameters count = 0\n                  |         `-Body\n                  |             Block isRoot = 0, isBody = 1\n                  |               ReturnStatement\n                  |                 BinExpr '+'\n                  |                 |-Left\n                  |                 |   CallExpr\n                  |                 |     Callee\n                  |                 |       Id '$ch0'\n                  |                 `-Right\n                  |                     GetFieldExpr '.' fieldName = 'x'\n                  |                       Receiver\n                  |                         Id 'this'\n                  `-ReturnStatement\n                      CallExpr\n                        Callee\n                          GetFieldExpr '.' fieldName = 'zed'\n                            Receiver\n                              CallExpr\n                                Callee\n                                  Id 'c'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/classSimple.nut",
    "content": "\nfunction foo(x, y) {\n    let c = class {\n        x = 10\n        function zed() {\n            return function () {\n                return x + 10;\n            }() + this.x\n        }\n    }\n    return c().zed()\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/classSimple.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n  VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = '$ch0', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = '(classSimple.nut:6)', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             BinExpr '+'\n          |             |-Left\n          |             |   Id 'x'\n          |             `-Right\n          |                 LiteralExpr LK_INT 10\n          |-VarDecl 'let', name = 'c', type = 'any'\n          |   Initializer\n          |     ClassExpr\n          |     |-Key: <anonymous>\n          |     `-Members\n          |       |-LiteralExpr LK_INT 10\n          |       `-FunctionExpr name = 'zed', pure = 0, nodiscard = 0, resultType = 'any'\n          |         |-Parameters count = 0\n          |         `-Body\n          |             Block isRoot = 0, isBody = 1\n          |               ReturnStatement\n          |                 BinExpr '+'\n          |                 |-Left\n          |                 |   CallExpr\n          |                 |     Callee\n          |                 |       Id '$ch0'\n          |                 `-Right\n          |                     GetFieldExpr '.' fieldName = 'x'\n          |                       Receiver\n          |                         Id 'this'\n          `-ReturnStatement\n              CallExpr\n                Callee\n                  GetFieldExpr '.' fieldName = 'zed'\n                    Receiver\n                      CallExpr\n                        Callee\n                          Id 'c'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/constDep.nut",
    "content": "function foo() {\n  const x = \"asdf\"\n  println(x)\n\n  function bar() {\n    let a = x\n  }\n  bar()\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/constDep.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n  VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 0\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-ConstDecl name = 'x', isGlobal = 0\n          |   LiteralExpr LK_STRING \"asdf\"\n          |-ExprStatement\n          |   CallExpr\n          |   |-Callee\n          |   |   Id 'println'\n          |   `-Arguments\n          |       Argument #1\n          |         Id 'x'\n          |-VarDecl 'let', name = 'bar', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'bar', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           VarDecl 'let', name = 'a', type = 'any'\n          |             Initializer\n          |               Id 'x'\n          `-ExprStatement\n              CallExpr\n                Callee\n                  Id 'bar'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/constFunc.nut",
    "content": "// const function declarations should not be hoisted because they are\n// compile-time constants. Hoisting would replace the FunctionExpr with\n// an Id reference ($chN) which is not a compile-time constant.\n\nfunction outer() {\n  function inner() {\n    const function [pure] constFn(a, b) { return a + b }\n    const result = constFn(1, 2)\n\n    // non-const function in the same scope should still be hoisted\n    let regularFn = function(x) { return x * 2 }\n    let r = regularFn(3)\n  }\n  inner()\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/constFunc.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'regularFn', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '*'\n|             |-Left\n|             |   Id 'x'\n|             `-Right\n|                 LiteralExpr LK_INT 2\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'inner', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ConstDecl name = 'constFn', isGlobal = 0\n|         |   UnExpr 'INLINE_CONST'\n|         |     FunctionExpr name = 'constFn', pure = 1, nodiscard = 0, resultType = 'any'\n|         |     |-Parameters count = 2\n|         |     | |-Parameter #1 name = 'a', type = 'any'\n|         |     | `-Parameter #2 name = 'b', type = 'any'\n|         |     `-Body\n|         |         Block isRoot = 0, isBody = 1\n|         |           ReturnStatement\n|         |             BinExpr '+'\n|         |             |-Left\n|         |             |   Id 'a'\n|         |             `-Right\n|         |                 Id 'b'\n|         |-ConstDecl name = 'result', isGlobal = 0\n|         |   CallExpr\n|         |   |-Callee\n|         |   |   Id 'constFn'\n|         |   `-Arguments\n|         |     |-Argument #1\n|         |     |   LiteralExpr LK_INT 1\n|         |     `-Argument #2\n|         |         LiteralExpr LK_INT 2\n|         |-VarDecl 'let', name = 'regularFn', type = 'any'\n|         |   Initializer\n|         |     Id '$ch0'\n|         `-VarDecl 'let', name = 'r', type = 'any'\n|             Initializer\n|               CallExpr\n|               |-Callee\n|               |   Id 'regularFn'\n|               `-Arguments\n|                   Argument #1\n|                     LiteralExpr LK_INT 3\n`-VarDecl 'let', name = 'outer', type = 'any'\n    Initializer\n      FunctionExpr name = 'outer', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 0\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = 'inner', type = 'any'\n          |   Initializer\n          |     Id '$ch1'\n          `-ExprStatement\n              CallExpr\n                Callee\n                  Id 'inner'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/deepUnchained.nut",
    "content": "local z = 0\nfunction foo(x, y) {\n    return function(a, b) {\n        z = a + b\n        return function(c, d) {\n            z = c - d\n            return function(e, f) {\n                z = e * f\n                return function(g, h) {\n                    return g / h\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/deepUnchained.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'local', name = 'z', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(deepUnchained.nut:9)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'g', type = 'any'\n|     | `-Parameter #2 name = 'h', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '/'\n|             |-Left\n|             |   Id 'g'\n|             `-Right\n|                 Id 'h'\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(deepUnchained.nut:7)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'e', type = 'any'\n|     | `-Parameter #2 name = 'f', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ExprStatement\n|         |   BinExpr '='\n|         |   |-Left\n|         |   |   Id 'z'\n|         |   `-Right\n|         |       BinExpr '*'\n|         |       |-Left\n|         |       |   Id 'e'\n|         |       `-Right\n|         |           Id 'f'\n|         `-ReturnStatement\n|             Id '$ch0'\n|-VarDecl 'let', name = '$ch2', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(deepUnchained.nut:5)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'c', type = 'any'\n|     | `-Parameter #2 name = 'd', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ExprStatement\n|         |   BinExpr '='\n|         |   |-Left\n|         |   |   Id 'z'\n|         |   `-Right\n|         |       BinExpr '-'\n|         |       |-Left\n|         |       |   Id 'c'\n|         |       `-Right\n|         |           Id 'd'\n|         `-ReturnStatement\n|             Id '$ch1'\n|-VarDecl 'let', name = '$ch3', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(deepUnchained.nut:3)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'a', type = 'any'\n|     | `-Parameter #2 name = 'b', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ExprStatement\n|         |   BinExpr '='\n|         |   |-Left\n|         |   |   Id 'z'\n|         |   `-Right\n|         |       BinExpr '+'\n|         |       |-Left\n|         |       |   Id 'a'\n|         |       `-Right\n|         |           Id 'b'\n|         `-ReturnStatement\n|             Id '$ch2'\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n            ReturnStatement\n              Id '$ch3'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/externalSymbol.nut",
    "content": "function foo(x, y) {\n    return function(a, b) {\n        println(a + b)\n        return function(c, d) {\n            println(c - d)\n            return function(e, f) {\n                println(e * f)\n                return function(g, h) {\n                    println(g / h)\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/externalSymbol.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(externalSymbol.nut:8)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'g', type = 'any'\n|     | `-Parameter #2 name = 'h', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ExprStatement\n|             CallExpr\n|             |-Callee\n|             |   Id 'println'\n|             `-Arguments\n|                 Argument #1\n|                   BinExpr '/'\n|                   |-Left\n|                   |   Id 'g'\n|                   `-Right\n|                       Id 'h'\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(externalSymbol.nut:6)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'e', type = 'any'\n|     | `-Parameter #2 name = 'f', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ExprStatement\n|         |   CallExpr\n|         |   |-Callee\n|         |   |   Id 'println'\n|         |   `-Arguments\n|         |       Argument #1\n|         |         BinExpr '*'\n|         |         |-Left\n|         |         |   Id 'e'\n|         |         `-Right\n|         |             Id 'f'\n|         `-ReturnStatement\n|             Id '$ch0'\n|-VarDecl 'let', name = '$ch2', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(externalSymbol.nut:4)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'c', type = 'any'\n|     | `-Parameter #2 name = 'd', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ExprStatement\n|         |   CallExpr\n|         |   |-Callee\n|         |   |   Id 'println'\n|         |   `-Arguments\n|         |       Argument #1\n|         |         BinExpr '-'\n|         |         |-Left\n|         |         |   Id 'c'\n|         |         `-Right\n|         |             Id 'd'\n|         `-ReturnStatement\n|             Id '$ch1'\n|-VarDecl 'let', name = '$ch3', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(externalSymbol.nut:2)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'a', type = 'any'\n|     | `-Parameter #2 name = 'b', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-ExprStatement\n|         |   CallExpr\n|         |   |-Callee\n|         |   |   Id 'println'\n|         |   `-Arguments\n|         |       Argument #1\n|         |         BinExpr '+'\n|         |         |-Left\n|         |         |   Id 'a'\n|         |         `-Right\n|         |             Id 'b'\n|         `-ReturnStatement\n|             Id '$ch2'\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n            ReturnStatement\n              Id '$ch3'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/implicitChainedFuncs.nut",
    "content": "local z = 0\nfunction foo(x, y) {\n  return function bar(a, b) { //<< this function does not use anything from outer scope\n    return function qux(c, d) { //<< but this function does and coupled with `bar` function\n        z = x + a - c;\n    }\n  }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/implicitChainedFuncs.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'local', name = 'z', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 0\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n            ReturnStatement\n              FunctionExpr name = 'bar', pure = 0, nodiscard = 0, resultType = 'any'\n              |-Parameters count = 2\n              | |-Parameter #1 name = 'a', type = 'any'\n              | `-Parameter #2 name = 'b', type = 'any'\n              `-Body\n                  Block isRoot = 0, isBody = 1\n                    ReturnStatement\n                      FunctionExpr name = 'qux', pure = 0, nodiscard = 0, resultType = 'any'\n                      |-Parameters count = 2\n                      | |-Parameter #1 name = 'c', type = 'any'\n                      | `-Parameter #2 name = 'd', type = 'any'\n                      `-Body\n                          Block isRoot = 0, isBody = 1\n                            ExprStatement\n                              BinExpr '='\n                              |-Left\n                              |   Id 'z'\n                              `-Right\n                                  BinExpr '-'\n                                  |-Left\n                                  |   BinExpr '+'\n                                  |   |-Left\n                                  |   |   Id 'x'\n                                  |   `-Right\n                                  |       Id 'a'\n                                  `-Right\n                                      Id 'c'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/implicitChainedFuncs2.nut",
    "content": "\nlocal z = 0\nfunction foo(x, y) {\n    return function(a, b) {\n        let fff = function() {\n            return z\n        }\n        return function(c, d) {\n            z = x + a - c;\n            return function(f, g) {\n                return f - g - x\n            }\n        }\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/implicitChainedFuncs2.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'local', name = 'z', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fff', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'z'\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = '$ch0', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = '(implicitChainedFuncs2.nut:10)', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 2\n          |     | |-Parameter #1 name = 'f', type = 'any'\n          |     | `-Parameter #2 name = 'g', type = 'any'\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             BinExpr '-'\n          |             |-Left\n          |             |   BinExpr '-'\n          |             |   |-Left\n          |             |   |   Id 'f'\n          |             |   `-Right\n          |             |       Id 'g'\n          |             `-Right\n          |                 Id 'x'\n          `-ReturnStatement\n              FunctionExpr name = '(implicitChainedFuncs2.nut:4)', pure = 0, nodiscard = 0, resultType = 'any'\n              |-Parameters count = 2\n              | |-Parameter #1 name = 'a', type = 'any'\n              | `-Parameter #2 name = 'b', type = 'any'\n              `-Body\n                  Block isRoot = 0, isBody = 1\n                  |-VarDecl 'let', name = 'fff', type = 'any'\n                  |   Initializer\n                  |     Id '$ch1'\n                  `-ReturnStatement\n                      FunctionExpr name = '(implicitChainedFuncs2.nut:8)', pure = 0, nodiscard = 0, resultType = 'any'\n                      |-Parameters count = 2\n                      | |-Parameter #1 name = 'c', type = 'any'\n                      | `-Parameter #2 name = 'd', type = 'any'\n                      `-Body\n                          Block isRoot = 0, isBody = 1\n                          |-ExprStatement\n                          |   BinExpr '='\n                          |   |-Left\n                          |   |   Id 'z'\n                          |   `-Right\n                          |       BinExpr '-'\n                          |       |-Left\n                          |       |   BinExpr '+'\n                          |       |   |-Left\n                          |       |   |   Id 'x'\n                          |       |   `-Right\n                          |       |       Id 'a'\n                          |       `-Right\n                          |           Id 'c'\n                          `-ReturnStatement\n                              Id '$ch0'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/indirectLocalCapture.nut",
    "content": "// Test: closure captures variable from nested block (indirect local)\n// The inner lambda captures 'uniqueTimerKey' which is inside an 'if' block.\n// This should prevent hoisting to fieldReadOnly's body level because the\n// variable is not accessible at that block level - must stay inside the\n// outer lambda where it can see the captured variable.\n\nfunction clearTimer(_id) {\n}\n\nfunction fieldReadOnly(params = {}) {\n  let {rawComponentName=null} = params\n\n  if (true) {\n    let uniqueTimerKey = rawComponentName\n\n    return @() {\n      onDetach = @() clearTimer(uniqueTimerKey)\n    }\n  }\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/indirectLocalCapture.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = 'clearTimer', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'clearTimer', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = '_id', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n`-VarDecl 'let', name = 'fieldReadOnly', type = 'any'\n    Initializer\n      FunctionExpr name = 'fieldReadOnly', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 1\n      |   Parameter #1 name = 'params', type = 'any'  (has default)\n      |     DefaultValue\n      |       TableExpr\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-DestructuringDecl type = 'table'\n          | |-Initializer\n          | |   Id 'params'\n          | `-VarDecl 'let', name = 'rawComponentName', type = 'any'\n          |     Initializer\n          |       LiteralExpr LK_NULL\n          `-IfStatement\n            |-Condition\n            |   LiteralExpr LK_BOOL true\n            `-ThenBranch\n                Block isRoot = 0, isBody = 0\n                |-VarDecl 'let', name = 'uniqueTimerKey', type = 'any'\n                |   Initializer\n                |     Id 'rawComponentName'\n                `-ReturnStatement\n                    FunctionExpr 'lambda' name = '(indirectLocalCapture.nut:16)', pure = 0, nodiscard = 0, resultType = 'any'\n                    |-Parameters count = 0\n                    `-Body\n                        Block isRoot = 0, isBody = 1\n                        |-VarDecl 'let', name = '$ch0', type = 'any'\n                        |   Initializer\n                        |     FunctionExpr 'lambda' name = '(indirectLocalCapture.nut:17)', pure = 0, nodiscard = 0, resultType = 'any'\n                        |     |-Parameters count = 0\n                        |     `-Body\n                        |         Block isRoot = 0, isBody = 1\n                        |           ReturnStatement\n                        |             CallExpr\n                        |             |-Callee\n                        |             |   Id 'clearTimer'\n                        |             `-Arguments\n                        |                 Argument #1\n                        |                   Id 'uniqueTimerKey'\n                        `-ReturnStatement\n                            TableExpr\n                              Field\n                              |-Key\n                              |   LiteralExpr LK_STRING \"onDetach\"\n                              `-Value\n                                  Id '$ch0'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/manyFuncs.nut",
    "content": "\nlocal z = 0\nfunction foo(x, y) {\n    let ar = [function fff(a, b) {\n        let c = class {\n            x = 10\n            function zed() {\n                return 10 + this.x;\n            }\n        }\n        return c().zed()\n    }, function () { return 10 }, @(r) r * 2]\n    ar[0](3, 4);\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/manyFuncs.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'local', name = 'z', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'fff', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'a', type = 'any'\n|     | `-Parameter #2 name = 'b', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-VarDecl 'let', name = 'c', type = 'any'\n|         |   Initializer\n|         |     ClassExpr\n|         |     |-Key: <anonymous>\n|         |     `-Members\n|         |       |-LiteralExpr LK_INT 10\n|         |       `-FunctionExpr name = 'zed', pure = 0, nodiscard = 0, resultType = 'any'\n|         |         |-Parameters count = 0\n|         |         `-Body\n|         |             Block isRoot = 0, isBody = 1\n|         |               ReturnStatement\n|         |                 BinExpr '+'\n|         |                 |-Left\n|         |                 |   LiteralExpr LK_INT 10\n|         |                 `-Right\n|         |                     GetFieldExpr '.' fieldName = 'x'\n|         |                       Receiver\n|         |                         Id 'this'\n|         `-ReturnStatement\n|             CallExpr\n|               Callee\n|                 GetFieldExpr '.' fieldName = 'zed'\n|                   Receiver\n|                     CallExpr\n|                       Callee\n|                         Id 'c'\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(manyFuncs.nut:12)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_INT 10\n|-VarDecl 'let', name = '$ch2', type = 'any'\n|   Initializer\n|     FunctionExpr 'lambda' name = '(manyFuncs.nut:12)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'r', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '*'\n|             |-Left\n|             |   Id 'r'\n|             `-Right\n|                 LiteralExpr LK_INT 2\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = 'ar', type = 'any'\n          |   Initializer\n          |     ArrayExpr\n          |     |-Element #1\n          |     |   Id '$ch0'\n          |     |-Element #2\n          |     |   Id '$ch1'\n          |     `-Element #3\n          |         Id '$ch2'\n          `-ExprStatement\n              CallExpr\n              |-Callee\n              |   GetSlotExpr '['\n              |   |-Receiver\n              |   |   Id 'ar'\n              |   `-Key\n              |       LiteralExpr LK_INT 0\n              `-Arguments\n                |-Argument #1\n                |   LiteralExpr LK_INT 3\n                `-Argument #2\n                    LiteralExpr LK_INT 4\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/multiDepthCapture.nut",
    "content": "// Test: closure captures from multiple depths\n// The lambda captures both 'rootVar' (depth 0) and 'paramVar' (depth 1)\n// It should hoist to depth 1 (outer's body), NOT to depth 0 (root)\n\nlet rootVar = 1\n\nfunction outer(paramVar) {\n    function inner() {\n        // This lambda captures from BOTH depth 0 (rootVar) and depth 1 (paramVar)\n        // Must hoist to depth 1, not depth 0\n        return @() rootVar + paramVar\n    }\n    return inner()\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/multiDepthCapture.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = 'rootVar', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 1\n`-VarDecl 'let', name = 'outer', type = 'any'\n    Initializer\n      FunctionExpr name = 'outer', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 1\n      |   Parameter #1 name = 'paramVar', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = '$ch0', type = 'any'\n          |   Initializer\n          |     FunctionExpr 'lambda' name = '(multiDepthCapture.nut:11)', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             BinExpr '+'\n          |             |-Left\n          |             |   Id 'rootVar'\n          |             `-Right\n          |                 Id 'paramVar'\n          |-VarDecl 'let', name = 'inner', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             Id '$ch0'\n          `-ReturnStatement\n              CallExpr\n                Callee\n                  Id 'inner'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/nestedParamShadow.nut",
    "content": "// Test: nested function parameter shadows a captured variable.\n// inner() captures 'x' from outer, but deep(x) has param 'x'.\n// inner should NOT be hoisted (it captures from immediate parent).\n\nfunction outer(x) {\n    function inner() {\n        function deep(x) { return x }\n        return x\n    }\n    return inner()\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/nestedParamShadow.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'deep', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'x'\n`-VarDecl 'let', name = 'outer', type = 'any'\n    Initializer\n      FunctionExpr name = 'outer', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 1\n      |   Parameter #1 name = 'x', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = 'inner', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |         |-VarDecl 'let', name = 'deep', type = 'any'\n          |         |   Initializer\n          |         |     Id '$ch0'\n          |         `-ReturnStatement\n          |             Id 'x'\n          `-ReturnStatement\n              CallExpr\n                Callee\n                  Id 'inner'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/paramDefaultCapture.nut",
    "content": "// Test 1: parameter default captures sibling from immediate parent scope.\n// 'bar' captures 'foo' from immediate parent -> blocks hoisting of bar.\n// 'foo' has no captures -> hoisted to root.\n\nfunction root() {\n  function foo(...) {\n    return \"xyz\"\n  }\n\n  function bar(source=foo) {\n    return source\n  }\n\n  return bar()\n}\n\n// Test 2: parameter default captures from grandparent, body local shadows same name.\n// inner's default `a = x` captures outer's x. inner's body also declares `let x = 2`.\n// The body local must NOT shadow the outer capture during analysis.\n// inner should NOT be hoisted above outer.\n\nfunction outer() {\n  let x = 1\n  function inner(a = x) {\n    let x = 2\n    return a + x\n  }\n  return inner\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/paramDefaultCapture.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     | |-Parameter #1 name = 'vargv', type = 'any'  (vararg)\n|     | `-Vararg...\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_STRING \"xyz\"\n|-VarDecl 'let', name = 'root', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'root', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-VarDecl 'let', name = 'foo', type = 'any'\n|         |   Initializer\n|         |     Id '$ch0'\n|         |-VarDecl 'let', name = 'bar', type = 'any'\n|         |   Initializer\n|         |     FunctionExpr name = 'bar', pure = 0, nodiscard = 0, resultType = 'any'\n|         |     |-Parameters count = 1\n|         |     |   Parameter #1 name = 'source', type = 'any'  (has default)\n|         |     |     DefaultValue\n|         |     |       Id 'foo'\n|         |     `-Body\n|         |         Block isRoot = 0, isBody = 1\n|         |           ReturnStatement\n|         |             Id 'source'\n|         `-ReturnStatement\n|             CallExpr\n|               Callee\n|                 Id 'bar'\n`-VarDecl 'let', name = 'outer', type = 'any'\n    Initializer\n      FunctionExpr name = 'outer', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 0\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = 'x', type = 'any'\n          |   Initializer\n          |     LiteralExpr LK_INT 1\n          |-VarDecl 'let', name = 'inner', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 1\n          |     |   Parameter #1 name = 'a', type = 'any'  (has default)\n          |     |     DefaultValue\n          |     |       Id 'x'\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |         |-VarDecl 'let', name = 'x', type = 'any'\n          |         |   Initializer\n          |         |     LiteralExpr LK_INT 2\n          |         `-ReturnStatement\n          |             BinExpr '+'\n          |             |-Left\n          |             |   Id 'a'\n          |             `-Right\n          |                 Id 'x'\n          `-ReturnStatement\n              Id 'inner'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/recursion1.nut",
    "content": "function foo(x, y) {\n    function bar(a, b) {\n        function qux(c, d) {\n            return c(d)\n        }\n\n        return qux(bar, b)\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/recursion1.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'qux', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'c', type = 'any'\n|     | `-Parameter #2 name = 'd', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             CallExpr\n|             |-Callee\n|             |   Id 'c'\n|             `-Arguments\n|                 Argument #1\n|                   Id 'd'\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n            VarDecl 'let', name = 'bar', type = 'any'\n              Initializer\n                FunctionExpr name = 'bar', pure = 0, nodiscard = 0, resultType = 'any'\n                |-Parameters count = 2\n                | |-Parameter #1 name = 'a', type = 'any'\n                | `-Parameter #2 name = 'b', type = 'any'\n                `-Body\n                    Block isRoot = 0, isBody = 1\n                    |-VarDecl 'let', name = 'qux', type = 'any'\n                    |   Initializer\n                    |     Id '$ch0'\n                    `-ReturnStatement\n                        CallExpr\n                        |-Callee\n                        |   Id 'qux'\n                        `-Arguments\n                          |-Argument #1\n                          |   Id 'bar'\n                          `-Argument #2\n                              Id 'b'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/simple.nut",
    "content": "\nfunction foo(x, y) {\n    return function(a, b) {\n        return a + b;\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/simple.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = '(simple.nut:3)', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 2\n|     | |-Parameter #1 name = 'a', type = 'any'\n|     | `-Parameter #2 name = 'b', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   Id 'a'\n|             `-Right\n|                 Id 'b'\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n            ReturnStatement\n              Id '$ch0'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/simple2.nut",
    "content": "local z = 0\nfunction foo(x, y) {\n    let f1 = function(a) {\n        let f2 = function(x) {\n            let f3 = function(c) {\n                return a + c\n            }\n            return x + y\n        }\n    }\n}"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/simple2.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'local', name = 'z', type = 'any'\n|   Initializer\n|     LiteralExpr LK_INT 0\n`-VarDecl 'let', name = 'foo', type = 'any'\n    Initializer\n      FunctionExpr name = 'foo', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 2\n      | |-Parameter #1 name = 'x', type = 'any'\n      | `-Parameter #2 name = 'y', type = 'any'\n      `-Body\n          Block isRoot = 0, isBody = 1\n            VarDecl 'let', name = 'f1', type = 'any'\n              Initializer\n                FunctionExpr name = 'f1', pure = 0, nodiscard = 0, resultType = 'any'\n                |-Parameters count = 1\n                |   Parameter #1 name = 'a', type = 'any'\n                `-Body\n                    Block isRoot = 0, isBody = 1\n                    |-VarDecl 'let', name = '$ch0', type = 'any'\n                    |   Initializer\n                    |     FunctionExpr name = 'f3', pure = 0, nodiscard = 0, resultType = 'any'\n                    |     |-Parameters count = 1\n                    |     |   Parameter #1 name = 'c', type = 'any'\n                    |     `-Body\n                    |         Block isRoot = 0, isBody = 1\n                    |           ReturnStatement\n                    |             BinExpr '+'\n                    |             |-Left\n                    |             |   Id 'a'\n                    |             `-Right\n                    |                 Id 'c'\n                    `-VarDecl 'let', name = 'f2', type = 'any'\n                        Initializer\n                          FunctionExpr name = 'f2', pure = 0, nodiscard = 0, resultType = 'any'\n                          |-Parameters count = 1\n                          |   Parameter #1 name = 'x', type = 'any'\n                          `-Body\n                              Block isRoot = 0, isBody = 1\n                              |-VarDecl 'let', name = 'f3', type = 'any'\n                              |   Initializer\n                              |     Id '$ch0'\n                              `-ReturnStatement\n                                  BinExpr '+'\n                                  |-Left\n                                  |   Id 'x'\n                                  `-Right\n                                      Id 'y'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/tooManyLocals.nut",
    "content": "let v001=0, v002=0, v003=0, v004=0, v005=0, v006=0, v007=0, v008=0, v009=0, v010=0\nlet v011=0, v012=0, v013=0, v014=0, v015=0, v016=0, v017=0, v018=0, v019=0, v020=0\nlet v021=0, v022=0, v023=0, v024=0, v025=0, v026=0, v027=0, v028=0, v029=0, v030=0\nlet v031=0, v032=0, v033=0, v034=0, v035=0, v036=0, v037=0, v038=0, v039=0, v040=0\nlet v041=0, v042=0, v043=0, v044=0, v045=0, v046=0, v047=0, v048=0, v049=0, v050=0\nlet v051=0, v052=0, v053=0, v054=0, v055=0, v056=0, v057=0, v058=0, v059=0, v060=0\nlet v061=0, v062=0, v063=0, v064=0, v065=0, v066=0, v067=0, v068=0, v069=0, v070=0\nlet v071=0, v072=0, v073=0, v074=0, v075=0, v076=0, v077=0, v078=0, v079=0, v080=0\nlet v081=0, v082=0, v083=0, v084=0, v085=0, v086=0, v087=0, v088=0, v089=0, v090=0\nlet v091=0, v092=0, v093=0, v094=0, v095=0, v096=0, v097=0, v098=0, v099=0, v100=0\nlet v101=0, v102=0, v103=0, v104=0, v105=0, v106=0, v107=0, v108=0, v109=0, v110=0\nlet v111=0, v112=0, v113=0, v114=0, v115=0, v116=0, v117=0, v118=0, v119=0, v120=0\nlet v121=0, v122=0, v123=0, v124=0, v125=0, v126=0, v127=0, v128=0, v129=0, v130=0\nlet v131=0, v132=0, v133=0, v134=0, v135=0, v136=0, v137=0, v138=0, v139=0, v140=0\nlet v141=0, v142=0, v143=0, v144=0, v145=0, v146=0, v147=0, v148=0, v149=0, v150=0\nlet v151=0, v152=0, v153=0, v154=0, v155=0, v156=0, v157=0, v158=0, v159=0, v160=0\nlet v161=0, v162=0, v163=0, v164=0, v165=0, v166=0, v167=0, v168=0, v169=0, v170=0\nlet v171=0, v172=0, v173=0, v174=0, v175=0, v176=0, v177=0, v178=0, v179=0, v180=0\nlet v181=0, v182=0, v183=0, v184=0, v185=0, v186=0, v187=0, v188=0, v189=0, v190=0\nlet v191=0, v192=0, v193=0, v194=0, v195=0\n\nfunction outer() {\n  function inner1() { return 0 }\n  function inner2() { return 0 }\n  function inner3() { return 0 }\n  function inner4() { return 0 }\n  // the following do not fit into max amount of locals and will not be hoisted\n  function inner5() { return 0 }\n  function inner6() { return 0 }\n  function inner7() { return 0 }\n  function inner8() { return 0 }\n  function inner9() { return 0 }\n\n  return inner9()\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/tooManyLocals.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v001', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v002', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v003', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v004', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v005', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v006', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v007', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v008', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v009', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v010', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v011', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v012', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v013', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v014', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v015', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v016', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v017', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v018', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v019', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v020', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v021', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v022', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v023', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v024', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v025', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v026', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v027', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v028', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v029', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v030', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v031', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v032', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v033', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v034', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v035', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v036', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v037', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v038', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v039', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v040', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v041', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v042', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v043', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v044', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v045', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v046', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v047', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v048', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v049', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v050', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v051', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v052', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v053', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v054', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v055', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v056', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v057', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v058', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v059', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v060', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v061', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v062', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v063', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v064', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v065', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v066', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v067', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v068', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v069', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v070', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v071', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v072', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v073', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v074', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v075', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v076', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v077', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v078', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v079', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v080', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v081', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v082', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v083', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v084', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v085', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v086', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v087', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v088', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v089', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v090', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v091', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v092', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v093', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v094', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v095', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v096', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v097', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v098', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v099', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v100', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v101', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v102', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v103', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v104', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v105', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v106', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v107', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v108', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v109', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v110', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v111', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v112', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v113', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v114', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v115', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v116', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v117', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v118', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v119', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v120', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v121', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v122', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v123', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v124', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v125', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v126', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v127', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v128', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v129', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v130', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v131', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v132', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v133', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v134', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v135', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v136', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v137', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v138', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v139', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v140', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v141', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v142', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v143', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v144', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v145', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v146', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v147', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v148', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v149', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v150', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v151', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v152', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v153', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v154', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v155', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v156', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v157', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v158', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v159', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v160', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v161', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v162', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v163', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v164', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v165', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v166', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v167', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v168', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v169', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v170', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v171', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v172', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v173', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v174', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v175', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v176', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v177', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v178', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v179', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v180', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v181', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v182', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v183', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v184', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v185', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v186', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v187', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v188', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v189', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v190', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-DeclGroup\n| |-VarDecl 'let', name = 'v191', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v192', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v193', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| |-VarDecl 'let', name = 'v194', type = 'any'\n| |   Initializer\n| |     LiteralExpr LK_INT 0\n| `-VarDecl 'let', name = 'v195', type = 'any'\n|     Initializer\n|       LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'inner1', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'inner2', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch2', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'inner3', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_INT 0\n|-VarDecl 'let', name = '$ch3', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'inner4', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             LiteralExpr LK_INT 0\n`-VarDecl 'let', name = 'outer', type = 'any'\n    Initializer\n      FunctionExpr name = 'outer', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 0\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = 'inner1', type = 'any'\n          |   Initializer\n          |     Id '$ch0'\n          |-VarDecl 'let', name = 'inner2', type = 'any'\n          |   Initializer\n          |     Id '$ch1'\n          |-VarDecl 'let', name = 'inner3', type = 'any'\n          |   Initializer\n          |     Id '$ch2'\n          |-VarDecl 'let', name = 'inner4', type = 'any'\n          |   Initializer\n          |     Id '$ch3'\n          |-VarDecl 'let', name = 'inner5', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner5', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             LiteralExpr LK_INT 0\n          |-VarDecl 'let', name = 'inner6', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner6', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             LiteralExpr LK_INT 0\n          |-VarDecl 'let', name = 'inner7', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner7', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             LiteralExpr LK_INT 0\n          |-VarDecl 'let', name = 'inner8', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner8', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             LiteralExpr LK_INT 0\n          |-VarDecl 'let', name = 'inner9', type = 'any'\n          |   Initializer\n          |     FunctionExpr name = 'inner9', pure = 0, nodiscard = 0, resultType = 'any'\n          |     |-Parameters count = 0\n          |     `-Body\n          |         Block isRoot = 0, isBody = 1\n          |           ReturnStatement\n          |             LiteralExpr LK_INT 0\n          `-ReturnStatement\n              CallExpr\n                Callee\n                  Id 'inner9'\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/typedDefaultReturnType.nut",
    "content": "// Typed default parameter safety for closure hoisting:\n// Functions with typed defaults (param with both type annotation and default\n// value) are never hoisted. The type check at closure creation can throw,\n// and hoisting would move that throw to a different scope.\n\nfunction outer() {\n  function inner() {\n    // NOT hoisted: has typed default (type + default value)\n    let typedDefault = function(x: int = 42) { return x }\n\n    // Hoisted: has default but no type annotation\n    let untypedDefault = function(x = 42) { return x }\n\n    // Hoisted: has type annotation but no default\n    let typedNoDefault = function(x: int) { return x }\n\n    // Hoisted: no type, no default\n    let plain = function(x) { return x }\n\n    return typedDefault() + untypedDefault() + typedNoDefault(1) + plain(1)\n  }\n  return inner()\n}\n"
  },
  {
    "path": "testData/ast/optimizations/closureHoisting/typedDefaultReturnType.opt.txt",
    "content": "Block isRoot = 1, isBody = 0\n|-VarDecl 'let', name = '$ch0', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'untypedDefault', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'  (has default)\n|     |     DefaultValue\n|     |       LiteralExpr LK_INT 42\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'x'\n|-VarDecl 'let', name = '$ch1', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'typedNoDefault', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'int'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'x'\n|-VarDecl 'let', name = '$ch2', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'plain', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 1\n|     |   Parameter #1 name = 'x', type = 'any'\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|           ReturnStatement\n|             Id 'x'\n|-VarDecl 'let', name = '$ch3', type = 'any'\n|   Initializer\n|     FunctionExpr name = 'inner', pure = 0, nodiscard = 0, resultType = 'any'\n|     |-Parameters count = 0\n|     `-Body\n|         Block isRoot = 0, isBody = 1\n|         |-VarDecl 'let', name = 'typedDefault', type = 'any'\n|         |   Initializer\n|         |     FunctionExpr name = 'typedDefault', pure = 0, nodiscard = 0, resultType = 'any'\n|         |     |-Parameters count = 1\n|         |     |   Parameter #1 name = 'x', type = 'int'  (has default)\n|         |     |     DefaultValue\n|         |     |       LiteralExpr LK_INT 42\n|         |     `-Body\n|         |         Block isRoot = 0, isBody = 1\n|         |           ReturnStatement\n|         |             Id 'x'\n|         |-VarDecl 'let', name = 'untypedDefault', type = 'any'\n|         |   Initializer\n|         |     Id '$ch0'\n|         |-VarDecl 'let', name = 'typedNoDefault', type = 'any'\n|         |   Initializer\n|         |     Id '$ch1'\n|         |-VarDecl 'let', name = 'plain', type = 'any'\n|         |   Initializer\n|         |     Id '$ch2'\n|         `-ReturnStatement\n|             BinExpr '+'\n|             |-Left\n|             |   BinExpr '+'\n|             |   |-Left\n|             |   |   BinExpr '+'\n|             |   |   |-Left\n|             |   |   |   CallExpr\n|             |   |   |     Callee\n|             |   |   |       Id 'typedDefault'\n|             |   |   `-Right\n|             |   |       CallExpr\n|             |   |         Callee\n|             |   |           Id 'untypedDefault'\n|             |   `-Right\n|             |       CallExpr\n|             |       |-Callee\n|             |       |   Id 'typedNoDefault'\n|             |       `-Arguments\n|             |           Argument #1\n|             |             LiteralExpr LK_INT 1\n|             `-Right\n|                 CallExpr\n|                 |-Callee\n|                 |   Id 'plain'\n|                 `-Arguments\n|                     Argument #1\n|                       LiteralExpr LK_INT 1\n`-VarDecl 'let', name = 'outer', type = 'any'\n    Initializer\n      FunctionExpr name = 'outer', pure = 0, nodiscard = 0, resultType = 'any'\n      |-Parameters count = 0\n      `-Body\n          Block isRoot = 0, isBody = 1\n          |-VarDecl 'let', name = 'inner', type = 'any'\n          |   Initializer\n          |     Id '$ch3'\n          `-ReturnStatement\n              CallExpr\n                Callee\n                  Id 'inner'\n"
  },
  {
    "path": "testData/diagnostics/1000_local_variables.diag.txt",
    "content": "ERROR: internal compiler error: too many locals\ntestData/diagnostics/1000_local_variables.nut:-1:-1\n"
  },
  {
    "path": "testData/diagnostics/1000_local_variables.nut",
    "content": "local a000, a001, a002, a003, a004, a005, a006, a007, a008, a009\nlocal a010, a011, a012, a013, a014, a015, a016, a017, a018, a019\nlocal a020, a021, a022, a023, a024, a025, a026, a027, a028, a029\nlocal a030, a031, a032, a033, a034, a035, a036, a037, a038, a039\nlocal a040, a041, a042, a043, a044, a045, a046, a047, a048, a049\nlocal a050, a051, a052, a053, a054, a055, a056, a057, a058, a059\nlocal a060, a061, a062, a063, a064, a065, a066, a067, a068, a069\nlocal a070, a071, a072, a073, a074, a075, a076, a077, a078, a079\nlocal a080, a081, a082, a083, a084, a085, a086, a087, a088, a089\nlocal a090, a091, a092, a093, a094, a095, a096, a097, a098, a099\nlocal a100, a101, a102, a103, a104, a105, a106, a107, a108, a109\nlocal a110, a111, a112, a113, a114, a115, a116, a117, a118, a119\nlocal a120, a121, a122, a123, a124, a125, a126, a127, a128, a129\nlocal a130, a131, a132, a133, a134, a135, a136, a137, a138, a139\nlocal a140, a141, a142, a143, a144, a145, a146, a147, a148, a149\nlocal a150, a151, a152, a153, a154, a155, a156, a157, a158, a159\nlocal a160, a161, a162, a163, a164, a165, a166, a167, a168, a169\nlocal a170, a171, a172, a173, a174, a175, a176, a177, a178, a179\nlocal a180, a181, a182, a183, a184, a185, a186, a187, a188, a189\nlocal a190, a191, a192, a193, a194, a195, a196, a197, a198, a199\nlocal a200, a201, a202, a203, a204, a205, a206, a207, a208, a209\nlocal a210, a211, a212, a213, a214, a215, a216, a217, a218, a219\nlocal a220, a221, a222, a223, a224, a225, a226, a227, a228, a229\nlocal a230, a231, a232, a233, a234, a235, a236, a237, a238, a239\nlocal a240, a241, a242, a243, a244, a245, a246, a247, a248, a249\nlocal a250, a251, a252, a253, a254, a255, a256, a257, a258, a259\nlocal a260, a261, a262, a263, a264, a265, a266, a267, a268, a269\nlocal a270, a271, a272, a273, a274, a275, a276, a277, a278, a279\nlocal a280, a281, a282, a283, a284, a285, a286, a287, a288, a289\nlocal a290, a291, a292, a293, a294, a295, a296, a297, a298, a299\nlocal a300, a301, a302, a303, a304, a305, a306, a307, a308, a309\nlocal a310, a311, a312, a313, a314, a315, a316, a317, a318, a319\nlocal a320, a321, a322, a323, a324, a325, a326, a327, a328, a329\nlocal a330, a331, a332, a333, a334, a335, a336, a337, a338, a339\nlocal a340, a341, a342, a343, a344, a345, a346, a347, a348, a349\nlocal a350, a351, a352, a353, a354, a355, a356, a357, a358, a359\nlocal a360, a361, a362, a363, a364, a365, a366, a367, a368, a369\nlocal a370, a371, a372, a373, a374, a375, a376, a377, a378, a379\nlocal a380, a381, a382, a383, a384, a385, a386, a387, a388, a389\nlocal a390, a391, a392, a393, a394, a395, a396, a397, a398, a399\nlocal a400, a401, a402, a403, a404, a405, a406, a407, a408, a409\nlocal a410, a411, a412, a413, a414, a415, a416, a417, a418, a419\nlocal a420, a421, a422, a423, a424, a425, a426, a427, a428, a429\nlocal a430, a431, a432, a433, a434, a435, a436, a437, a438, a439\nlocal a440, a441, a442, a443, a444, a445, a446, a447, a448, a449\nlocal a450, a451, a452, a453, a454, a455, a456, a457, a458, a459\nlocal a460, a461, a462, a463, a464, a465, a466, a467, a468, a469\nlocal a470, a471, a472, a473, a474, a475, a476, a477, a478, a479\nlocal a480, a481, a482, a483, a484, a485, a486, a487, a488, a489\nlocal a490, a491, a492, a493, a494, a495, a496, a497, a498, a499\nlocal a500, a501, a502, a503, a504, a505, a506, a507, a508, a509\nlocal a510, a511, a512, a513, a514, a515, a516, a517, a518, a519\nlocal a520, a521, a522, a523, a524, a525, a526, a527, a528, a529\nlocal a530, a531, a532, a533, a534, a535, a536, a537, a538, a539\nlocal a540, a541, a542, a543, a544, a545, a546, a547, a548, a549\nlocal a550, a551, a552, a553, a554, a555, a556, a557, a558, a559\nlocal a560, a561, a562, a563, a564, a565, a566, a567, a568, a569\nlocal a570, a571, a572, a573, a574, a575, a576, a577, a578, a579\nlocal a580, a581, a582, a583, a584, a585, a586, a587, a588, a589\nlocal a590, a591, a592, a593, a594, a595, a596, a597, a598, a599\nlocal a600, a601, a602, a603, a604, a605, a606, a607, a608, a609\nlocal a610, a611, a612, a613, a614, a615, a616, a617, a618, a619\nlocal a620, a621, a622, a623, a624, a625, a626, a627, a628, a629\nlocal a630, a631, a632, a633, a634, a635, a636, a637, a638, a639\nlocal a640, a641, a642, a643, a644, a645, a646, a647, a648, a649\nlocal a650, a651, a652, a653, a654, a655, a656, a657, a658, a659\nlocal a660, a661, a662, a663, a664, a665, a666, a667, a668, a669\nlocal a670, a671, a672, a673, a674, a675, a676, a677, a678, a679\nlocal a680, a681, a682, a683, a684, a685, a686, a687, a688, a689\nlocal a690, a691, a692, a693, a694, a695, a696, a697, a698, a699\nlocal a700, a701, a702, a703, a704, a705, a706, a707, a708, a709\nlocal a710, a711, a712, a713, a714, a715, a716, a717, a718, a719\nlocal a720, a721, a722, a723, a724, a725, a726, a727, a728, a729\nlocal a730, a731, a732, a733, a734, a735, a736, a737, a738, a739\nlocal a740, a741, a742, a743, a744, a745, a746, a747, a748, a749\nlocal a750, a751, a752, a753, a754, a755, a756, a757, a758, a759\nlocal a760, a761, a762, a763, a764, a765, a766, a767, a768, a769\nlocal a770, a771, a772, a773, a774, a775, a776, a777, a778, a779\nlocal a780, a781, a782, a783, a784, a785, a786, a787, a788, a789\nlocal a790, a791, a792, a793, a794, a795, a796, a797, a798, a799\nlocal a800, a801, a802, a803, a804, a805, a806, a807, a808, a809\nlocal a810, a811, a812, a813, a814, a815, a816, a817, a818, a819\nlocal a820, a821, a822, a823, a824, a825, a826, a827, a828, a829\nlocal a830, a831, a832, a833, a834, a835, a836, a837, a838, a839\nlocal a840, a841, a842, a843, a844, a845, a846, a847, a848, a849\nlocal a850, a851, a852, a853, a854, a855, a856, a857, a858, a859\nlocal a860, a861, a862, a863, a864, a865, a866, a867, a868, a869\nlocal a870, a871, a872, a873, a874, a875, a876, a877, a878, a879\nlocal a880, a881, a882, a883, a884, a885, a886, a887, a888, a889\nlocal a890, a891, a892, a893, a894, a895, a896, a897, a898, a899\nlocal a900, a901, a902, a903, a904, a905, a906, a907, a908, a909\nlocal a910, a911, a912, a913, a914, a915, a916, a917, a918, a919\nlocal a920, a921, a922, a923, a924, a925, a926, a927, a928, a929\nlocal a930, a931, a932, a933, a934, a935, a936, a937, a938, a939\nlocal a940, a941, a942, a943, a944, a945, a946, a947, a948, a949\nlocal a950, a951, a952, a953, a954, a955, a956, a957, a958, a959\nlocal a960, a961, a962, a963, a964, a965, a966, a967, a968, a969\nlocal a970, a971, a972, a973, a974, a975, a976, a977, a978, a979\nlocal a980, a981, a982, a983, a984, a985, a986, a987, a988, a989\nlocal a990, a991, a992, a993, a994, a995, a996, a997, a998, a999\n\n\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_access_member.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_access_member.nut:4:202\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n                                                                                                                                                                                                          ^\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_access_member.nut",
    "content": "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x\n\n"
  },
  {
    "path": "testData/diagnostics/50k_curly_brackets.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_curly_brackets.nut:2:122\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n                                                                                                                          ^\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_curly_brackets.nut",
    "content": "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50k_function_calls.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_function_calls.nut:1:70\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n                                                                      ^\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_function_calls.nut",
    "content": "p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\np(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(p(\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50k_lambdas.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_lambdas.nut:1:93\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n                                                                                             ^\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_lambdas.nut",
    "content": "@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()@()\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50k_nested_tables.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_nested_tables.nut:1:101\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n                                                                                                     ^\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_nested_tables.nut",
    "content": "x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\nx={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={x={\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50k_not.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_not.nut:2:115\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                                                                                                                   ^\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_not.nut",
    "content": "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50k_paren_brackets.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_paren_brackets.nut:1:35\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n                                   ^\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_paren_brackets.nut",
    "content": "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50k_square_brackets.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50k_square_brackets.nut:1:35\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n                                   ^\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n\n"
  },
  {
    "path": "testData/diagnostics/50k_square_brackets.nut",
    "content": "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n\n\u001a"
  },
  {
    "path": "testData/diagnostics/50r_binop.diag.txt",
    "content": "ERROR: AST too big. Consider simplifying it\ntestData/diagnostics/50r_binop.nut:4:200\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n                                                                                                                                                                                                        ^\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\n\n"
  },
  {
    "path": "testData/diagnostics/50r_binop.nut",
    "content": "x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\n\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+\nx+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x\n\n"
  },
  {
    "path": "testData/diagnostics/assign_to_expr.diag.txt",
    "content": "ERROR: can't assign to expression\ntestData/diagnostics/assign_to_expr.nut:2:0\n\nlocal x\nx-- = 1\n^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/assign_to_expr.nut",
    "content": "local x\nx-- = 1\n"
  },
  {
    "path": "testData/diagnostics/assign_to_expr2.diag.txt",
    "content": "ERROR: can't assign to expression\ntestData/diagnostics/assign_to_expr2.nut:1:13\n\nlocal x; @() !x = 1\n             ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/assign_to_expr2.nut",
    "content": "local x; @() !x = 1"
  },
  {
    "path": "testData/diagnostics/assign_to_optional_7.diag.txt",
    "content": "ERROR: can't assign to expression\ntestData/diagnostics/assign_to_optional_7.nut:2:0\n\nlocal v = {v = {v = 0}}\nv.v ?? v = 3\n^-------\n\n\n"
  },
  {
    "path": "testData/diagnostics/assign_to_optional_7.nut",
    "content": "local v = {v = {v = 0}}\nv.v ?? v = 3"
  },
  {
    "path": "testData/diagnostics/base_as_array_assign.diag.txt",
    "content": "ERROR: can't assign to expression\ntestData/diagnostics/base_as_array_assign.nut:1:0\n\nbase[\"x\"] = 1\n^--------\n\n\n"
  },
  {
    "path": "testData/diagnostics/base_as_array_assign.nut",
    "content": "base[\"x\"] = 1"
  },
  {
    "path": "testData/diagnostics/base_as_array_pp.diag.txt",
    "content": "ERROR: argument of inc/dec operation is not assignable\ntestData/diagnostics/base_as_array_pp.nut:1:0\n\nbase[0]++\n^------\n\n\n"
  },
  {
    "path": "testData/diagnostics/base_as_array_pp.nut",
    "content": "base[0]++"
  },
  {
    "path": "testData/diagnostics/base_pp.diag.txt",
    "content": "ERROR: argument of inc/dec operation is not assignable\ntestData/diagnostics/base_pp.nut:1:0\n\nbase++\n^---\n\n\n"
  },
  {
    "path": "testData/diagnostics/base_pp.nut",
    "content": "base++"
  },
  {
    "path": "testData/diagnostics/base_x_pp.diag.txt",
    "content": "ERROR: argument of inc/dec operation is not assignable\ntestData/diagnostics/base_x_pp.nut:1:0\n\nbase.x++\n^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/base_x_pp.nut",
    "content": "base.x++"
  },
  {
    "path": "testData/diagnostics/binding_assign.diag.txt",
    "content": "ERROR: can't assign to binding 'a' (probably declaring using 'local' was intended, but 'let' was used)\ntestData/diagnostics/binding_assign.nut:2:0\n\nlet a = 2\na = 3\n^\n\n\n"
  },
  {
    "path": "testData/diagnostics/binding_assign.nut",
    "content": "let a = 2\na = 3"
  },
  {
    "path": "testData/diagnostics/clone_op_allowed.diag.txt",
    "content": "ERROR: expected 'IDENTIFIER'\ntestData/diagnostics/clone_op_allowed.nut.txt:10:12\n\nlet ct0 = clone t\nlet ct1 = t.clone()\n            ^----\n\n\n"
  },
  {
    "path": "testData/diagnostics/clone_op_allowed.nut.txt",
    "content": "\n#allow-clone-operator\n\nlet t = {\n    a = 10, b = 20\n}\n\n\nlet ct0 = clone t\nlet ct1 = t.clone()\n"
  },
  {
    "path": "testData/diagnostics/clone_op_forbiden.diag.txt",
    "content": "ERROR: end of statement expected (; or lf)\ntestData/diagnostics/clone_op_forbiden.nut.txt:10:16\n\nlet ct1 = t.clone()\nlet ct0 = clone t\n                ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/clone_op_forbiden.nut.txt",
    "content": "\n#forbid-clone-operator\n\nlet t = {\n    a = 10, b = 20\n}\n\n\nlet ct1 = t.clone()\nlet ct0 = clone t\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/empty_literal.diag.txt",
    "content": "ERROR: empty constant\ntestData/diagnostics/compilation_errors/lex_errors/empty_literal.nut:2:8\n\n// EXPECT_ERROR: \"empty constant\"\nlet x = ''\n        ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/empty_literal.nut",
    "content": "// EXPECT_ERROR: \"empty constant\"\nlet x = ''\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/fp_exp_expected.diag.txt",
    "content": "ERROR: exponent expected\ntestData/diagnostics/compilation_errors/lex_errors/fp_exp_expected.nut:2:8\n\n// EXPECT_ERROR: \"exponent expected\"\nlet x = 1.0e\n        ^---\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/fp_exp_expected.nut",
    "content": "// EXPECT_ERROR: \"exponent expected\"\nlet x = 1.0e\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/hex_digits_expected.diag.txt",
    "content": "ERROR: expected hex digits after '0x'\ntestData/diagnostics/compilation_errors/lex_errors/hex_digits_expected.nut:2:8\n\n// EXPECT_ERROR: \"expected hex digits after '0x'\"\nlet x = 0xGG\n        ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/hex_digits_expected.nut",
    "content": "// EXPECT_ERROR: \"expected hex digits after '0x'\"\nlet x = 0xGG\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/hex_numbers_expected.diag.txt",
    "content": "ERROR: hexadecimal number expected\ntestData/diagnostics/compilation_errors/lex_errors/hex_numbers_expected.nut:2:8\n\n// EXPECT_ERROR: \"hexadecimal number expected\"\nlet x = \"\\xZZ\"\n        ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/hex_numbers_expected.nut",
    "content": "// EXPECT_ERROR: \"hexadecimal number expected\"\nlet x = \"\\xZZ\"\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/hex_too_many_digits.diag.txt",
    "content": "ERROR: too many digits for a hex number\ntestData/diagnostics/compilation_errors/lex_errors/hex_too_many_digits.nut:2:8\n\n// EXPECT_ERROR: \"too many digits for a hex number\"\nlet x = 0x100000000000000000\n        ^-------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/hex_too_many_digits.nut",
    "content": "// EXPECT_ERROR: \"too many digits for a hex number\"\nlet x = 0x100000000000000000\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/invalid_token.diag.txt",
    "content": "ERROR: invalid token '..'\ntestData/diagnostics/compilation_errors/lex_errors/invalid_token.nut:2:0\n\n// EXPECT_ERROR: \"invalid token\"\n..\n^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/invalid_token.nut",
    "content": "// EXPECT_ERROR: \"invalid token\"\n..\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/literal_overflow.diag.txt",
    "content": "ERROR: integer constant overflow\ntestData/diagnostics/compilation_errors/lex_errors/literal_overflow.nut:2:8\n\n// EXPECT_ERROR: \"constant overflow\"\nlet x = 99999999999999999999999999999999999999999999\n        ^-------------------------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/literal_overflow.nut",
    "content": "// EXPECT_ERROR: \"constant overflow\"\nlet x = 99999999999999999999999999999999999999999999\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/literal_underflow.diag.txt",
    "content": "ERROR: float constant underflow\ntestData/diagnostics/compilation_errors/lex_errors/literal_underflow.nut:2:8\n\n// EXPECT_ERROR: \"constant underflow\"\nlet x = 1e-999999\n        ^--------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/literal_underflow.nut",
    "content": "// EXPECT_ERROR: \"constant underflow\"\nlet x = 1e-999999\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/malformed_number.diag.txt",
    "content": "ERROR: malformed number\ntestData/diagnostics/compilation_errors/lex_errors/malformed_number.nut:2:8\n\n// EXPECT_ERROR: \"malformed number\"\nlet x = 1.2.3\n        ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/malformed_number.nut",
    "content": "// EXPECT_ERROR: \"malformed number\"\nlet x = 1.2.3\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/newline_in_const.diag.txt",
    "content": "ERROR: newline in a constant\ntestData/diagnostics/compilation_errors/lex_errors/newline_in_const.nut:2:8\n\n// EXPECT_ERROR: \"newline in a constant\"\nlet x = \"hello\n        ^------\n\"\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/newline_in_const.nut",
    "content": "// EXPECT_ERROR: \"newline in a constant\"\nlet x = \"hello\n\""
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/octal_not_supported.diag.txt",
    "content": "ERROR: leading 0 is not allowed, octal numbers are not supported\ntestData/diagnostics/compilation_errors/lex_errors/octal_not_supported.nut:2:8\n\n// EXPECT_ERROR: \"octal numbers are not supported\"\nlet x = 0755\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/octal_not_supported.nut",
    "content": "// EXPECT_ERROR: \"octal numbers are not supported\"\nlet x = 0755\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/trailing_block_comment.diag.txt",
    "content": "ERROR: missing \"*/\" in comment\ntestData/diagnostics/compilation_errors/lex_errors/trailing_block_comment.nut:2:0\n\n// EXPECT_ERROR: \"in comment\"\n/* this comment is never closed\n^--------------------------------------------\nlet x = 42\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/trailing_block_comment.nut",
    "content": "// EXPECT_ERROR: \"in comment\"\n/* this comment is never closed\nlet x = 42\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/unexpected_char.diag.txt",
    "content": "ERROR: unexpected character '(control)'\ntestData/diagnostics/compilation_errors/lex_errors/unexpected_char.nut:2:8\n\n// EXPECT_ERROR: \"unexpected character\"\nlet x = \u0001\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/unexpected_char.nut",
    "content": "// EXPECT_ERROR: \"unexpected character\"\r\nlet x = \u0001\r\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/unfinished_string.diag.txt",
    "content": "ERROR: unfinished string\ntestData/diagnostics/compilation_errors/lex_errors/unfinished_string.nut:2:8\n\n// EXPECT_ERROR: \"unfinished string\"\nlet x = \"hello\n        ^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/unfinished_string.nut",
    "content": "// EXPECT_ERROR: \"unfinished string\"\nlet x = \"hello"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/unrecognised_escape.diag.txt",
    "content": "ERROR: unrecognised escape char\ntestData/diagnostics/compilation_errors/lex_errors/unrecognised_escape.nut:2:8\n\n// EXPECT_ERROR: \"unrecognised escape char\"\nlet x = \"\\q\"\n        ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/lex_errors/unrecognised_escape.nut",
    "content": "// EXPECT_ERROR: \"unrecognised escape char\"\nlet x = \"\\q\"\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/assign_to_binding.diag.txt",
    "content": "ERROR: can't assign to binding 'x' (probably declaring using 'local' was intended, but 'let' was used)\ntestData/diagnostics/compilation_errors/sema_errors/assign_to_binding.nut:3:0\n\nlet x = 10\nx = 20\n^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/assign_to_binding.nut",
    "content": "// EXPECT_ERROR: \"can't assign to binding\"\nlet x = 10\nx = 20\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/assign_to_expr.diag.txt",
    "content": "ERROR: can't assign to expression\ntestData/diagnostics/compilation_errors/sema_errors/assign_to_expr.nut:2:0\n\n// EXPECT_ERROR: \"can't assign to expression\"\n(1 + 2) = 5\n^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/assign_to_expr.nut",
    "content": "// EXPECT_ERROR: \"can't assign to expression\"\n(1 + 2) = 5\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/cannot_delete.diag.txt",
    "content": "ERROR: can't delete an (outer) local\ntestData/diagnostics/compilation_errors/sema_errors/cannot_delete.nut:4:0\n\nlocal x = 5\ndelete x\n^-------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/cannot_delete.nut",
    "content": "// EXPECT_ERROR: \"can't delete\"\n#allow-delete-operator\nlocal x = 5\ndelete x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/conflicts_with.diag.txt",
    "content": "ERROR: Local variable name 'foo' conflicts with existing local variable\ntestData/diagnostics/compilation_errors/sema_errors/conflicts_with.nut:3:0\n\nfunction foo() { return 1 }\nlocal foo = 2\n^------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/conflicts_with.nut",
    "content": "// EXPECT_ERROR: \"conflicts with\"\nfunction foo() { return 1 }\nlocal foo = 2\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/constant_field_not_found.diag.txt",
    "content": "ERROR: Field 'c' not found in constant object\ntestData/diagnostics/compilation_errors/sema_errors/constant_field_not_found.nut:3:10\n\nconst TBL = {a = 1, b = 2}\nconst X = TBL.c\n          ^----\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/constant_field_not_found.nut",
    "content": "// EXPECT_ERROR: \"not found in constant object\"\nconst TBL = {a = 1, b = 2}\nconst X = TBL.c\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/constant_slot_not_found.diag.txt",
    "content": "ERROR: string slot c not found in constant object\ntestData/diagnostics/compilation_errors/sema_errors/constant_slot_not_found.nut:3:14\n\nconst TBL = {a = 1, b = 2}\nconst X = TBL[\"c\"]\n              ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/constant_slot_not_found.nut",
    "content": "// EXPECT_ERROR: \"not found in constant object\"\nconst TBL = {a = 1, b = 2}\nconst X = TBL[\"c\"]\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/duplicate_func_attr.diag.txt",
    "content": "ERROR: duplicate attribute 'pure'\ntestData/diagnostics/compilation_errors/sema_errors/duplicate_func_attr.nut:2:16\n\n// EXPECT_ERROR: \"duplicate attribute\"\nlet f = @[pure, pure](x) x + 1\n                ^---\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/duplicate_func_attr.nut",
    "content": "// EXPECT_ERROR: \"duplicate attribute\"\nlet f = @[pure, pure](x) x + 1\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/duplicate_key.diag.txt",
    "content": "ERROR: duplicate key 'a'\ntestData/diagnostics/compilation_errors/sema_errors/duplicate_key.nut:4:4\n\n    a = 1,\n    a = 2\n    ^\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/duplicate_key.nut",
    "content": "// EXPECT_ERROR: \"duplicate key\"\nlet t = {\n    a = 1,\n    a = 2\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/id_is_not_const.diag.txt",
    "content": "ERROR: Identifier 'y' is not a compile-time constant\ntestData/diagnostics/compilation_errors/sema_errors/id_is_not_const.nut:3:12\n\nlocal y = 5\nconst BAD = y\n            ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/id_is_not_const.nut",
    "content": "// EXPECT_ERROR: \"is not a compile-time constant\"\nlocal y = 5\nconst BAD = y\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/inc_dec_not_assignable.diag.txt",
    "content": "ERROR: argument of inc/dec operation is not assignable\ntestData/diagnostics/compilation_errors/sema_errors/inc_dec_not_assignable.nut:2:0\n\n// EXPECT_ERROR: \"not assignable\"\n(1 + 2)++\n^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/inc_dec_not_assignable.nut",
    "content": "// EXPECT_ERROR: \"not assignable\"\n(1 + 2)++\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/initialization_required.diag.txt",
    "content": "ERROR: Initialization required\ntestData/diagnostics/compilation_errors/sema_errors/initialization_required.nut:2:11\n\n// EXPECT_ERROR: \"Initialization required\"\nif (local x; x < 10; x++) {}\n           ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/initialization_required.nut",
    "content": "// EXPECT_ERROR: \"Initialization required\"\nif (local x; x < 10; x++) {}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/invalid_enum.diag.txt",
    "content": "ERROR: Field 'YELLOW' not found in constant object\ntestData/diagnostics/compilation_errors/sema_errors/invalid_enum.nut:3:8\n\nenum Color { RED, GREEN, BLUE }\nlet x = Color.YELLOW\n        ^-----------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/invalid_enum.nut",
    "content": "// EXPECT_ERROR: \"not found in constant\"\nenum Color { RED, GREEN, BLUE }\nlet x = Color.YELLOW\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/local_slot_create.diag.txt",
    "content": "ERROR: can't 'create' a local slot\ntestData/diagnostics/compilation_errors/sema_errors/local_slot_create.nut:3:0\n\nlocal x = 5\nx <- 10\n^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/local_slot_create.nut",
    "content": "// EXPECT_ERROR: \"can't 'create' a local slot\"\nlocal x = 5\nx <- 10\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/loop_controller_not_in_loop_break.diag.txt",
    "content": "ERROR: 'break' has to be in a loop block\ntestData/diagnostics/compilation_errors/sema_errors/loop_controller_not_in_loop_break.nut:3:4\n\nfunction foo() {\n    break\n    ^----\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/loop_controller_not_in_loop_break.nut",
    "content": "// EXPECT_ERROR: \"has to be in a loop block\"\nfunction foo() {\n    break\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/loop_controller_not_in_loop_continue.diag.txt",
    "content": "ERROR: 'continue' has to be in a loop block\ntestData/diagnostics/compilation_errors/sema_errors/loop_controller_not_in_loop_continue.nut:3:4\n\nfunction foo() {\n    continue\n    ^-------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/loop_controller_not_in_loop_continue.nut",
    "content": "// EXPECT_ERROR: \"has to be in a loop block\"\nfunction foo() {\n    continue\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/not_allowed_in_const.diag.txt",
    "content": "ERROR: increment expression is not allowed in constant\ntestData/diagnostics/compilation_errors/sema_errors/not_allowed_in_const.nut:3:10\n\nlocal i = 0\nconst X = i++\n          ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/not_allowed_in_const.nut",
    "content": "// EXPECT_ERROR: \"is not allowed in constant\"\nlocal i = 0\nconst X = i++\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/only_single_variable_declaration.diag.txt",
    "content": "ERROR: Only single variable declaration is allowed here\ntestData/diagnostics/compilation_errors/sema_errors/only_single_variable_declaration.nut:2:15\n\n// EXPECT_ERROR: \"Only single variable declaration is allowed here\"\nif (local a = 1, b = 2) {}\n               ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/only_single_variable_declaration.nut",
    "content": "// EXPECT_ERROR: \"Only single variable declaration is allowed here\"\nif (local a = 1, b = 2) {}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/same_foreach_kv_names.diag.txt",
    "content": "ERROR: foreach() key and value names are the same: 'x'\ntestData/diagnostics/compilation_errors/sema_errors/same_foreach_kv_names.nut:3:12\n\nlet arr = [1, 2, 3]\nforeach (x, x in arr) {\n            ^\n    print(x)\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/same_foreach_kv_names.nut",
    "content": "// EXPECT_ERROR: \"foreach() key and value names are the same\"\nlet arr = [1, 2, 3]\nforeach (x, x in arr) {\n    print(x)\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/space_sep_field_name.diag.txt",
    "content": "ERROR: Separate access operator '.' with its following name is forbidden\ntestData/diagnostics/compilation_errors/sema_errors/space_sep_field_name.nut:3:11\n\nlet t = {a = 1}\nlet x = t. a\n           ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/space_sep_field_name.nut",
    "content": "// EXPECT_ERROR: \"Separate access operator\"\nlet t = {a = 1}\nlet x = t. a\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/too_many_locals.diag.txt",
    "content": "ERROR: internal compiler error: too many locals\ntestData/diagnostics/compilation_errors/sema_errors/too_many_locals.nut:-1:-1\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/too_many_locals.nut",
    "content": "// EXPECT_ERROR: \"too many\"\nfunction too_many() {\nlocal a000=0;local a001=0;local a002=0;local a003=0;local a004=0;local a005=0;local a006=0;local a007=0;local a008=0;local a009=0\nlocal a010=0;local a011=0;local a012=0;local a013=0;local a014=0;local a015=0;local a016=0;local a017=0;local a018=0;local a019=0\nlocal a020=0;local a021=0;local a022=0;local a023=0;local a024=0;local a025=0;local a026=0;local a027=0;local a028=0;local a029=0\nlocal a030=0;local a031=0;local a032=0;local a033=0;local a034=0;local a035=0;local a036=0;local a037=0;local a038=0;local a039=0\nlocal a040=0;local a041=0;local a042=0;local a043=0;local a044=0;local a045=0;local a046=0;local a047=0;local a048=0;local a049=0\nlocal a050=0;local a051=0;local a052=0;local a053=0;local a054=0;local a055=0;local a056=0;local a057=0;local a058=0;local a059=0\nlocal a060=0;local a061=0;local a062=0;local a063=0;local a064=0;local a065=0;local a066=0;local a067=0;local a068=0;local a069=0\nlocal a070=0;local a071=0;local a072=0;local a073=0;local a074=0;local a075=0;local a076=0;local a077=0;local a078=0;local a079=0\nlocal a080=0;local a081=0;local a082=0;local a083=0;local a084=0;local a085=0;local a086=0;local a087=0;local a088=0;local a089=0\nlocal a090=0;local a091=0;local a092=0;local a093=0;local a094=0;local a095=0;local a096=0;local a097=0;local a098=0;local a099=0\nlocal a100=0;local a101=0;local a102=0;local a103=0;local a104=0;local a105=0;local a106=0;local a107=0;local a108=0;local a109=0\nlocal a110=0;local a111=0;local a112=0;local a113=0;local a114=0;local a115=0;local a116=0;local a117=0;local a118=0;local a119=0\nlocal a120=0;local a121=0;local a122=0;local a123=0;local a124=0;local a125=0;local a126=0;local a127=0;local a128=0;local a129=0\nlocal a130=0;local a131=0;local a132=0;local a133=0;local a134=0;local a135=0;local a136=0;local a137=0;local a138=0;local a139=0\nlocal a140=0;local a141=0;local a142=0;local a143=0;local a144=0;local a145=0;local a146=0;local a147=0;local a148=0;local a149=0\nlocal a150=0;local a151=0;local a152=0;local a153=0;local a154=0;local a155=0;local a156=0;local a157=0;local a158=0;local a159=0\nlocal a160=0;local a161=0;local a162=0;local a163=0;local a164=0;local a165=0;local a166=0;local a167=0;local a168=0;local a169=0\nlocal a170=0;local a171=0;local a172=0;local a173=0;local a174=0;local a175=0;local a176=0;local a177=0;local a178=0;local a179=0\nlocal a180=0;local a181=0;local a182=0;local a183=0;local a184=0;local a185=0;local a186=0;local a187=0;local a188=0;local a189=0\nlocal a190=0;local a191=0;local a192=0;local a193=0;local a194=0;local a195=0;local a196=0;local a197=0;local a198=0;local a199=0\nlocal a200=0;local a201=0;local a202=0;local a203=0;local a204=0;local a205=0;local a206=0;local a207=0;local a208=0;local a209=0\nlocal a210=0;local a211=0;local a212=0;local a213=0;local a214=0;local a215=0;local a216=0;local a217=0;local a218=0;local a219=0\nlocal a220=0;local a221=0;local a222=0;local a223=0;local a224=0;local a225=0;local a226=0;local a227=0;local a228=0;local a229=0\nlocal a230=0;local a231=0;local a232=0;local a233=0;local a234=0;local a235=0;local a236=0;local a237=0;local a238=0;local a239=0\nlocal a240=0;local a241=0;local a242=0;local a243=0;local a244=0;local a245=0;local a246=0;local a247=0;local a248=0;local a249=0\nlocal a250=0;local a251=0;local a252=0;local a253=0;local a254=0;local a255=0;local a256=0;local a257=0;local a258=0;local a259=0\nreturn 0\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/type_differs.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/sema_errors/type_differs.nut:2:0\n\n// EXPECT_ERROR: \"differs from the declared type\"\nlocal x: int = \"not a number\"\n^----------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/type_differs.nut",
    "content": "// EXPECT_ERROR: \"differs from the declared type\"\nlocal x: int = \"not a number\"\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/uninitialized_binding.diag.txt",
    "content": "ERROR: Binding 'x' must be initialized\ntestData/diagnostics/compilation_errors/sema_errors/uninitialized_binding.nut:2:4\n\n// EXPECT_ERROR: \"must be initialized\"\nlet x\n    ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/uninitialized_binding.nut",
    "content": "// EXPECT_ERROR: \"must be initialized\"\nlet x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/unknown_symbol.diag.txt",
    "content": "ERROR: Unknown variable [undefined_var]\ntestData/diagnostics/compilation_errors/sema_errors/unknown_symbol.nut:2:8\n\n// EXPECT_ERROR: \"Unknown variable\"\nlet x = undefined_var\n        ^------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/sema_errors/unknown_symbol.nut",
    "content": "// EXPECT_ERROR: \"Unknown variable\"\nlet x = undefined_var\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/assign_inside_forbidden.diag.txt",
    "content": "ERROR: '=' inside 'if' is forbidden\ntestData/diagnostics/compilation_errors/syntax_errors/assign_inside_forbidden.nut:3:10\n\nlocal x = 5\nif (x = 10) {\n          ^\n    print(\"oops\")\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/assign_inside_forbidden.nut",
    "content": "// EXPECT_ERROR: \"is forbidden\"\nlocal x = 5\nif (x = 10) {\n    print(\"oops\")\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/broken_slot_declaration.diag.txt",
    "content": "ERROR: cannot break deref/or comma needed after [exp]=exp slot declaration\ntestData/diagnostics/compilation_errors/syntax_errors/broken_slot_declaration.nut:4:0\n\nt\n[0] = 1\n^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/broken_slot_declaration.nut",
    "content": "// EXPECT_ERROR: \"cannot break deref\"\nlocal t = {}\nt\n[0] = 1\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/compiler_internals_forbidden.diag.txt",
    "content": "ERROR: Access to compiler internals is forbidden\ntestData/diagnostics/compilation_errors/syntax_errors/compiler_internals_forbidden.nut:2:8\n\n// EXPECT_ERROR: \"Access to compiler internals is forbidden\"\nlet x = $${return 42}\n        ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/compiler_internals_forbidden.nut",
    "content": "// EXPECT_ERROR: \"Access to compiler internals is forbidden\"\nlet x = $${return 42}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/delete_op_forbidden.diag.txt",
    "content": "ERROR: Usage of 'delete' operator is forbidden. Use 'o.rawdelete(\"key\")' instead\ntestData/diagnostics/compilation_errors/syntax_errors/delete_op_forbidden.nut:4:0\n\nlet t = {a = 1}\ndelete t.a\n^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/delete_op_forbidden.nut",
    "content": "// EXPECT_ERROR: \"Usage of 'delete' operator is forbidden\"\n#forbid-delete-operator\nlet t = {a = 1}\ndelete t.a\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/end_of_stmt_expected.diag.txt",
    "content": "ERROR: end of statement expected (; or lf)\ntestData/diagnostics/compilation_errors/syntax_errors/end_of_stmt_expected.nut:2:10\n\n// EXPECT_ERROR: \"end of statement expected\"\nlet x = 5 let y = 6\n          ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/end_of_stmt_expected.nut",
    "content": "// EXPECT_ERROR: \"end of statement expected\"\nlet x = 5 let y = 6\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_bracket.diag.txt",
    "content": "ERROR: expected ']'\ntestData/diagnostics/compilation_errors/syntax_errors/expected_bracket.nut:2:31\n\n// EXPECT_ERROR: \"expected ']'\"\nlet a = [1, 2, 3]; let x = a[0\n                               ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_bracket.nut",
    "content": "// EXPECT_ERROR: \"expected ']'\"\nlet a = [1, 2, 3]; let x = a[0\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_colnum.diag.txt",
    "content": "ERROR: expected column number after #pos:<line>:\ntestData/diagnostics/compilation_errors/syntax_errors/expected_colnum.nut:2:0\n\n// EXPECT_ERROR: \"expected column number after #pos:\"\n#pos:1:abc\n^\nlet x = 1\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_colnum.nut",
    "content": "// EXPECT_ERROR: \"expected column number after #pos:\"\n#pos:1:abc\nlet x = 1\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_expression.diag.txt",
    "content": "ERROR: expected 'expression'\ntestData/diagnostics/compilation_errors/syntax_errors/expected_expression.nut:2:8\n\n// EXPECT_ERROR: \"expected 'expression'\"\nlet x =\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_expression.nut",
    "content": "// EXPECT_ERROR: \"expected 'expression'\"\nlet x =\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_identifier.diag.txt",
    "content": "ERROR: expected 'IDENTIFIER'\ntestData/diagnostics/compilation_errors/syntax_errors/expected_identifier.nut:2:9\n\n// EXPECT_ERROR: \"expected 'IDENTIFIER'\"\nfunction 123() {\n         ^--\n    return 42\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_identifier.nut",
    "content": "// EXPECT_ERROR: \"expected 'IDENTIFIER'\"\nfunction 123() {\n    return 42\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_linenum.diag.txt",
    "content": "ERROR: expected line number after #pos:\ntestData/diagnostics/compilation_errors/syntax_errors/expected_linenum.nut:2:0\n\n// EXPECT_ERROR: \"expected line number after #pos:\"\n#pos:abc\n^-------\nlet x = 1\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_linenum.nut",
    "content": "// EXPECT_ERROR: \"expected line number after #pos:\"\n#pos:abc\nlet x = 1\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_token_brace.diag.txt",
    "content": "ERROR: expected '}'\ntestData/diagnostics/compilation_errors/syntax_errors/expected_token_brace.nut:2:29\n\n// EXPECT_ERROR: \"expected '}'\"\nlocal {a, b = {x = 1, y = 2}\n                             ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_token_brace.nut",
    "content": "// EXPECT_ERROR: \"expected '}'\"\nlocal {a, b = {x = 1, y = 2}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_token_paren.diag.txt",
    "content": "ERROR: expected ')'\ntestData/diagnostics/compilation_errors/syntax_errors/expected_token_paren.nut:2:9\n\n// EXPECT_ERROR: \"expected ')'\"\nif (true {\n         ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_token_paren.nut",
    "content": "// EXPECT_ERROR: \"expected ')'\"\nif (true {\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_while.diag.txt",
    "content": "ERROR: expected 'while'\ntestData/diagnostics/compilation_errors/syntax_errors/expected_while.nut:4:2\n\n    local x = 42\n}\n  ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/expected_while.nut",
    "content": "// EXPECT_ERROR: \"expected 'while'\"\ndo {\n    local x = 42\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/global_consts_only.diag.txt",
    "content": "ERROR: global can be applied to const and enum only\ntestData/diagnostics/compilation_errors/syntax_errors/global_consts_only.nut:2:7\n\n// EXPECT_ERROR: \"global can be applied to const and enum only\"\nglobal local x = 5\n       ^----\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/global_consts_only.nut",
    "content": "// EXPECT_ERROR: \"global can be applied to const and enum only\"\nglobal local x = 5\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/invalid_type_name.diag.txt",
    "content": "ERROR: Invalid type name 'UnknownType'\ntestData/diagnostics/compilation_errors/syntax_errors/invalid_type_name.nut:2:16\n\n// EXPECT_ERROR: \"Invalid type name\"\nfunction foo(x: UnknownType) {\n                ^----------\n    return x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/invalid_type_name.nut",
    "content": "// EXPECT_ERROR: \"Invalid type name\"\nfunction foo(x: UnknownType) {\n    return x\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/invalid_type_name_suggestion.diag.txt",
    "content": "ERROR: Invalid type name 'Int', did you mean 'int'?\ntestData/diagnostics/compilation_errors/syntax_errors/invalid_type_name_suggestion.nut:2:9\n\n// EXPECT_ERROR: \"did you mean\"\nlocal x: Int = 5\n         ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/invalid_type_name_suggestion.nut",
    "content": "// EXPECT_ERROR: \"did you mean\"\nlocal x: Int = 5\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/multiple_docstrings.diag.txt",
    "content": "ERROR: multiple docstrings in a single block\ntestData/diagnostics/compilation_errors/syntax_errors/multiple_docstrings.nut:3:0\n\n@@\"first docstring\"\n@@\"second docstring\"\n^-------------------\nfunction foo() {\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/multiple_docstrings.nut",
    "content": "// EXPECT_ERROR: \"multiple docstrings\"\n@@\"first docstring\"\n@@\"second docstring\"\nfunction foo() {\n    return 42\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/root_table_forbidden.diag.txt",
    "content": "ERROR: Access to root table is forbidden\ntestData/diagnostics/compilation_errors/syntax_errors/root_table_forbidden.nut:3:8\n\n#forbid-root-table\nlet x = ::some_global\n        ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/root_table_forbidden.nut",
    "content": "// EXPECT_ERROR: \"Access to root table is forbidden\"\n#forbid-root-table\nlet x = ::some_global\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/scalar_expected.diag.txt",
    "content": "ERROR: scalar expected : integer, float, or string\ntestData/diagnostics/compilation_errors/syntax_errors/scalar_expected.nut:3:8\n\nenum BadEnum {\n    A = [1, 2, 3]\n        ^\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/scalar_expected.nut",
    "content": "// EXPECT_ERROR: \"scalar expected\"\nenum BadEnum {\n    A = [1, 2, 3]\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/unsupported_directive.diag.txt",
    "content": "ERROR: unsupported directive 'this-directive-does-not-exist'\ntestData/diagnostics/compilation_errors/syntax_errors/unsupported_directive.nut:2:0\n\n// EXPECT_ERROR: \"unsupported directive\"\n#this-directive-does-not-exist\n^-----------------------------\nlet x = 42\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/unsupported_directive.nut",
    "content": "// EXPECT_ERROR: \"unsupported directive\"\n#this-directive-does-not-exist\nlet x = 42\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/vararg_with_default.diag.txt",
    "content": "ERROR: function with default parameters cannot have variable number of parameters\ntestData/diagnostics/compilation_errors/syntax_errors/vararg_with_default.nut:2:20\n\n// EXPECT_ERROR: \"function with default parameters cannot have variable number of parameters\"\nfunction foo(a = 1, ...) {\n                    ^--\n    return a\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/syntax_errors/vararg_with_default.nut",
    "content": "// EXPECT_ERROR: \"function with default parameters cannot have variable number of parameters\"\nfunction foo(a = 1, ...) {\n    return a\n}\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_arithmetic_mismatch.diag.txt",
    "content": "ERROR: expression of type 'int' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_arithmetic_mismatch.nut:4:0\n\nlocal b: int = 20\nlocal c: string = a + b\n^----------------------\nreturn c\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_arithmetic_mismatch.nut",
    "content": "// EXPECTED: compile-time error - int arithmetic result assigned to string\nlocal a: int = 10\nlocal b: int = 20\nlocal c: string = a + b\nreturn c\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_array_literal.diag.txt",
    "content": "ERROR: expression of type 'array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_array_literal.nut:2:0\n\n// EXPECTED: compile-time error - array literal assigned to table variable\nlocal x: table = [1, 2, 3]\n^-------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_array_literal.nut",
    "content": "// EXPECTED: compile-time error - array literal assigned to table variable\nlocal x: table = [1, 2, 3]\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_array_return.diag.txt",
    "content": "ERROR: expression of type 'array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_array_return.nut:3:4\n\nfunction make_array(): table {\n    return [1, 2, 3]\n    ^---------------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_array_return.nut",
    "content": "// EXPECTED: compile-time error - function returns array, declared as returning table\nfunction make_array(): table {\n    return [1, 2, 3]\n}\nreturn make_array\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_array_to_int.diag.txt",
    "content": "ERROR: expression of type 'array' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_array_to_int.nut:2:0\n\n// EXPECTED: compile-time error - array assigned to int\nlocal x: int = [1, 2, 3]\n^-----------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_array_to_int.nut",
    "content": "// EXPECTED: compile-time error - array assigned to int\nlocal x: int = [1, 2, 3]\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_assignment_chain.diag.txt",
    "content": "ERROR: expression of type 'int' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_assignment_chain.nut:4:0\n\nlet z = 120 * y\nlet s: string = z\n^----------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_assignment_chain.nut",
    "content": "let x: int = 234\nlet y = x + 4\nlet z = 120 * y\nlet s: string = z\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_call_result_type.diag.txt",
    "content": "ERROR: expression of type 'int' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_call_result_type.nut:5:0\n\n}\nlocal y: string = sqri(5)\n^------------------------\nreturn y\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_call_result_type.nut",
    "content": "// EXPECTED: compile-time error - function returns int, assigned to string variable\nfunction sqri(x: int): int {\n    return x * x\n}\nlocal y: string = sqri(5)\nreturn y\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_call_union_return.diag.txt",
    "content": "ERROR: expression of type 'int|string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_call_union_return.nut:5:0\n\n}\nlocal x: int = fn(1)\n^-------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_call_union_return.nut",
    "content": "// EXPECTED: compile-time error - fn returns string|int, but var only accepts int\nfunction fn(val): string|int {\n    return val ? 42 : \"hello\"\n}\nlocal x: int = fn(1)\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_class_literal.diag.txt",
    "content": "ERROR: expression of type 'class' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_class_literal.nut:2:0\n\n// EXPECTED: compile-time error - class literal assigned to string variable\nlocal x: string = class {\n^\n    a = 1\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_class_literal.nut",
    "content": "// EXPECTED: compile-time error - class literal assigned to string variable\nlocal x: string = class {\n    a = 1\n    b = 2\n}\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_comparison_to_int.diag.txt",
    "content": "ERROR: expression of type 'bool' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_comparison_to_int.nut:4:0\n\nlocal b: int = 20\nlocal c: int = a > b\n^-------------------\nreturn c\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_comparison_to_int.nut",
    "content": "// EXPECTED: compile-time error - comparison produces bool, assigned to int\nlocal a: int = 10\nlocal b: int = 20\nlocal c: int = a > b\nreturn c\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_assign_mismatch.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_assign_mismatch.nut:4:0\n\nlocal x: int = 42\nx = \"hello\"\n^\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_assign_mismatch.nut",
    "content": "// EXPECTED: compile-time error\n// Variable with type annotation reassigned with wrong type expression\nlocal x: int = 42\nx = \"hello\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_bitwise.diag.txt",
    "content": "ERROR: expression of type 'int' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_bitwise.nut:8:0\n\nlocal d: int = 0x55\nlocal result: string = (a & b) | (c ^ d) << 2\n^--------------------------------------------\nreturn result\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_bitwise.nut",
    "content": "// EXPECTED: compile-time error\n// Bitwise operations always produce int\n// (a & b) | (c ^ d) << 2 => int => not subset of string\nlocal a: int = 0xFF\nlocal b: int = 0x0F\nlocal c: int = 0xAA\nlocal d: int = 0x55\nlocal result: string = (a & b) | (c ^ d) << 2\nreturn result\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_call_chain.diag.txt",
    "content": "ERROR: expression of type 'float' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_call_chain.nut:8:0\n\n}\nlocal result: string = double_it(to_float(42))\n^---------------------------------------------\nreturn result\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_call_chain.nut",
    "content": "// EXPECTED: compile-time error - chained function calls, final result is float, assigned to string\nfunction to_float(x: int): float {\n    return x.tofloat()\n}\nfunction double_it(x: float): float {\n    return x * 2.0\n}\nlocal result: string = double_it(to_float(42))\nreturn result\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_deep_nesting.diag.txt",
    "content": "ERROR: expression of type 'bool' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_deep_nesting.nut:8:0\n\nlocal c: int = 3\nlocal deep_result: string = ((((a + b) * c) > 5) ? \"big\" : \"small\") != \"big\"\n^---------------------------------------------------------------------------\nreturn deep_result\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_deep_nesting.nut",
    "content": "// EXPECTED: compile-time error\n// Deeply nested expression with many operators\n// ((((1 + 2) * 3) > 5) ? \"big\" : \"small\") != \"big\" => bool\n// bool is not subset of string\nlocal a: int = 1\nlocal b: int = 2\nlocal c: int = 3\nlocal deep_result: string = ((((a + b) * c) > 5) ? \"big\" : \"small\") != \"big\"\nreturn deep_result\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_logical.diag.txt",
    "content": "ERROR: expression of type 'int|string' cannot be assigned to type 'bool'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_logical.nut:4:0\n\n// 42 || \"hello\" => int|string => not subset of bool\nlocal x: bool = 42 || \"hello\"\n^----------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_logical.nut",
    "content": "// EXPECTED: compile-time error\n// Logical operators: || returns one of the operands (not necessarily bool)\n// 42 || \"hello\" => int|string => not subset of bool\nlocal x: bool = 42 || \"hello\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_mega.diag.txt",
    "content": "ERROR: expression of type 'number|string' cannot be assigned to type 'function|null'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_mega.nut:53:0\n\n// declared type: function|null => mismatch!\nlocal v_fail: function|null = get_flag() ? sqrf(4.3) : fn(3)\n^-----------------------------------------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_mega.nut",
    "content": "// EXPECTED: compile-time error on line with v_fail\n// This test exercises many expression types in combination\n//\n// Type inference rules exercised:\n//   - Literals: int, float, string, bool, null\n//   - Arithmetic: int+int=int, float*float=float, int+float=int|float\n//   - Comparison: always bool\n//   - Typeof: always string\n//   - Bitwise: always int\n//   - Negation: ~int = int\n//   - Logical not: !x = bool\n//   - Ternary: union of branches\n//   - Null-coalesce: (lhs minus null) | rhs\n//   - Logical or/and: union of operands\n//   - String concat: string + any = string\n//   - Function call: return type of callee\n//   - Table/array/class literals: table/array/class\n//   - Lambda: function\n\nconst function [pure] sqri(x: int): int { return x * x }\nconst function [pure] sqrf(x: float): float { return x * x }\nfunction fn(val): string|int { return val ? sqri(val) : \"err\" }\nfunction get_flag(): bool { return true }\nfunction maybe_int(): int|null { return 42 }\nfunction make_table(): table { return { a = 1 } }\nfunction make_array(): array { return [1, 2] }\n\n// --- All of these should be OK ---\nlocal ok_int: int = sqri(5)                                           // int\nlocal ok_float: float = sqrf(3.14)                                    // float\nlocal ok_union: string|int = fn(42)                                   // string|int\nlocal ok_bool: bool = get_flag()                                      // bool\nlocal ok_nullc: int = maybe_int() ?? 0                                // int\nlocal ok_ternary: int|float = get_flag() ? 42 : 3.14                  // int|float\nlocal ok_arith: int = (1 + 2) * 3 - 4 % 5                             // int\nlocal ok_bitwise: int = (0xFF & 0x0F) | (0xAA ^ 0x55) << 2            // int\nlocal ok_comp: bool = 42 > 10                                         // bool\nlocal ok_typeof: string = typeof []                                   // string\nlocal ok_not: bool = !get_flag()                                      // bool\nlocal ok_table: table = { x = 1, y = \"hello\" }                        // table\nlocal ok_array: array = [1, \"two\", 3.0]                               // array\nlocal ok_class: class = class { val = 0 }                             // class\nlocal ok_lambda: function = @(x) x * 2                                // function\nlocal ok_concat: string = \"value: \" + 42                              // string (concat)\nlocal ok_deep: string = get_flag() ? typeof 42 : \"fallback\"           // string|string = string\nlocal ok_chain: int|string = get_flag() ? sqri(10) : fn(5)            // int | string|int = int|string\nlocal ok_wide: int|float|string|null = get_flag() ? (maybe_int() ?? sqri(1)) : fn(2)\n\n// --- This should FAIL ---\n// sqrf(4.3) returns float, fn(3) returns string|int\n// ternary: float | string|int = float|string|int\n// declared type: function|null => mismatch!\nlocal v_fail: function|null = get_flag() ? sqrf(4.3) : fn(3)\n\nreturn [ok_int, ok_float, ok_union, ok_bool]\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_mixed_arithmetic.diag.txt",
    "content": "ERROR: expression of type 'int|string' cannot be assigned to type 'bool'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_mixed_arithmetic.nut:7:0\n\nlocal n: int = 10\nlocal x: bool = get_flag() ? ((1 + 2) * 3 + n) : typeof \"x\"\n^----------------------------------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_mixed_arithmetic.nut",
    "content": "// EXPECTED: compile-time error\n// Complex arithmetic expression with mixed types ending up assigned to wrong type\n// (1 + 2) * 3 => int, typeof \"x\" => string\n// result of ternary: int|string => not subset of bool\nfunction get_flag(): bool { return true }\nlocal n: int = 10\nlocal x: bool = get_flag() ? ((1 + 2) * 3 + n) : typeof \"x\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_multifunction.diag.txt",
    "content": "ERROR: expression of type 'string|array' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_multifunction.nut:12:4\n\nfunction pick(flag: bool): int {\n    return flag ? make_pair(1, 2) : get_name()\n    ^-----------------------------------------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_multifunction.nut",
    "content": "// EXPECTED: compile-time error\n// Multiple functions with known return types composed together\n// make_pair returns array, get_name returns string\n// ternary: array|string => not subset of int\nfunction make_pair(a: int, b: int): array {\n    return [a, b]\n}\nfunction get_name(): string {\n    return \"hello\"\n}\nfunction pick(flag: bool): int {\n    return flag ? make_pair(1, 2) : get_name()\n}\nreturn pick\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_nested_ternary.diag.txt",
    "content": "ERROR: expression of type 'number|string' cannot be assigned to type 'number'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_nested_ternary.nut:8:0\n\nlocal flag2 = false\nlocal x: int|float = flag1 ? (flag2 ? 42 : 3.14) : \"oops\"\n^--------------------------------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_nested_ternary.nut",
    "content": "// EXPECTED: compile-time error - nested ternaries produce int|float|string, var only accepts int|float\n//   flag1 ? (flag2 ? 42 : 3.14) : \"oops\"\n//   true-branch:  flag2 ? 42 : 3.14  => int|float\n//   false-branch: \"oops\"             => string\n//   combined: int|float|string       => NOT subset of int|float\nlocal flag1 = true\nlocal flag2 = false\nlocal x: int|float = flag1 ? (flag2 ? 42 : 3.14) : \"oops\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_nullcoalesce.diag.txt",
    "content": "ERROR: expression of type 'int|string' cannot be assigned to type 'float'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_nullcoalesce.nut:6:0\n\nfunction maybe_int(): int|null { return 42 }\nlocal x: float = maybe_int() ?? \"default\"\n^----------------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_nullcoalesce.nut",
    "content": "// EXPECTED: compile-time error\n// null-coalescing: lhs is int|null, rhs is string\n// result type: int (non-null part of lhs) | string (rhs) = int|string\n// assigned to float => mismatch\nfunction maybe_int(): int|null { return 42 }\nlocal x: float = maybe_int() ?? \"default\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_pure_chain.diag.txt",
    "content": "ERROR: expression of type 'float' cannot be assigned to type 'function|null'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_pure_chain.nut:15:0\n\nlocal v: function|null = sqrf(4.3) + 3\n^-------------------------------------\nreturn v\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_pure_chain.nut",
    "content": "// EXPECTED: compile-time error\n// Chain of pure function calls with type mismatch at the end\n// sqri returns int, sqrf returns float, fn returns string|int\n// sqrf(1.5) + 3 => float (float arithmetic) => not subset of function|null\nconst function [pure] sqri(x: int): int {\n    return x * x\n}\nconst function [pure] sqrf(x: float): float {\n    return x * x\n}\nfunction fn(val): string|int {\n    return val ? sqri(val) : \"error\"\n}\n\nlocal v: function|null = sqrf(4.3) + 3\nreturn v\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_return_expr.diag.txt",
    "content": "ERROR: expression of type 'int|string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_return_expr.nut:5:4\n\nfunction compute(flag: bool, x: int, y: int): int {\n    return flag ? x * y + 1 : \"error\"\n    ^--------------------------------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_return_expr.nut",
    "content": "// EXPECTED: compile-time error\n// Complex return expression: function declared to return int,\n// but the expression is a ternary with string branch\nfunction compute(flag: bool, x: int, y: int): int {\n    return flag ? x * y + 1 : \"error\"\n}\nreturn compute\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_table_ternary.diag.txt",
    "content": "ERROR: expression of type 'table|array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_complex_table_ternary.nut:5:4\n\nfunction get_data(flag: bool): table {\n    return flag ? { x = 1 } : [1, 2, 3]\n    ^----------------------------------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_complex_table_ternary.nut",
    "content": "// EXPECTED: compile-time error\n// Ternary produces table|array, assigned to table\n// The array branch violates the constraint\nfunction get_data(flag: bool): table {\n    return flag ? { x = 1 } : [1, 2, 3]\n}\nreturn get_data\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array.diag.txt",
    "content": "ERROR: expression of type 'array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_const_array.nut:3:0\n\nconst ARR2 = [4, 3]\nlet x: table = true ? ARR1 : ARR2\n^--------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array.nut",
    "content": "const ARR1 = [1, null]\nconst ARR2 = [4, 3]\nlet x: table = true ? ARR1 : ARR2\nreturn x"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array2.diag.txt",
    "content": "ERROR: expression of type 'array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_const_array2.nut:4:12\n\nfunction fn(x: table = true ? ARR1 : ARR2): null {}\n            ^----------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array2.nut",
    "content": "const ARR1 = [1, null]\nconst ARR2 = [4, 3]\n\nfunction fn(x: table = true ? ARR1 : ARR2): null {}\n\nreturn fn({})"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array3.diag.txt",
    "content": "ERROR: expression of type 'table|array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_const_array3.nut:4:12\n\nfunction fn(x: table = true ? {} : ARR2): null {}\n            ^--------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array3.nut",
    "content": "const ARR1 = [1, null]\nconst ARR2 = [4, 3]\n\nfunction fn(x: table = true ? {} : ARR2): null {}\n\nreturn fn({})"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array4.diag.txt",
    "content": "ERROR: expression of type 'table|array' cannot be assigned to type 'table'\ntestData/diagnostics/compilation_errors/type_inference/test_const_array4.nut:4:12\n\nfunction fn(x: table = true ? ARR1 : {}): null {}\n            ^--------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_array4.nut",
    "content": "const ARR1 = [1, null]\nconst ARR2 = [4, 3]\n\nfunction fn(x: table = true ? ARR1 : {}): null {}\n\nreturn fn({})"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_function.diag.txt",
    "content": "ERROR: expression of type 'function' cannot be assigned to type 'array'\ntestData/diagnostics/compilation_errors/type_inference/test_const_function.nut:3:0\n\nconst function fn2() {}\nlet x: array = true ? fn1 : fn2\n^------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_function.nut",
    "content": "const function fn1() {}\nconst function fn2() {}\nlet x: array = true ? fn1 : fn2\nreturn x"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_inline.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_const_inline.nut:3:0\n\nconst MY_STR = \"hello\"\nlocal x: int = MY_STR\n^--------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_inline.nut",
    "content": "// EXPECTED: compile-time error - const string assigned to int variable\nconst MY_STR = \"hello\"\nlocal x: int = MY_STR\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_table.diag.txt",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'array'\ntestData/diagnostics/compilation_errors/type_inference/test_const_table.nut:3:0\n\nconst TAB2 = {x = 4}\nlet x: array = true ? TAB1 : TAB2\n^--------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_const_table.nut",
    "content": "const TAB1 = {}\nconst TAB2 = {x = 4}\nlet x: array = true ? TAB1 : TAB2\nreturn x"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_destructure_array_default_mismatch.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_destructure_array_default_mismatch.nut:4:5\n\n// This CAN be checked at compile time because the default value is known.\nlet [x: int = \"hello\"] = [42]\n     ^---------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_destructure_array_default_mismatch.nut",
    "content": "// EXPECTED: compile-time error - default value \"hello\" doesn't match declared type int\n// The default value is a string literal, and the declared type is int.\n// This CAN be checked at compile time because the default value is known.\nlet [x: int = \"hello\"] = [42]\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_destructure_complex.diag.txt",
    "content": "ERROR: expression of type 'float' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_destructure_complex.nut:6:40\n\n}\nlet [x: int = 0, y: string = \"default\", z: string = 3.14] = get_data()\n                                        ^---------------\nreturn [x, y, z]\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_destructure_complex.nut",
    "content": "// EXPECTED: compile-time error - default value type doesn't match declared type\n// In array destructuring, the default for z is a float but declared as string\nfunction get_data(): array {\n    return [1, \"hello\"]\n}\nlet [x: int = 0, y: string = \"default\", z: string = 3.14] = get_data()\nreturn [x, y, z]\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_destructure_table_mismatch.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [type 'string' differs from the declared type 'int']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/compilation_errors/type_inference/test_destructure_table_mismatch.nut:5\n\nLOCALS\n[x] \"hello\"\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_destructure_table_mismatch.nut",
    "content": "// EXPECTED: runtime error - destructured value \"hello\" doesn't match declared type int\n// (Compile-time inference for destructuring is harder since the source is a table\n//  expression where individual field types need to be tracked. Initially this may\n//  remain a runtime check. Documenting desired eventual behavior.)\nlet {x: int} = {x = \"hello\"}\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_field_access_unknown.diag.txt",
    "content": ""
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_field_access_unknown.nut",
    "content": "// EXPECTED: no compile-time error (should fall back to runtime check)\n// Field access on tables/objects has unknown type at compile time\nlocal t = { value = 42 }\nlocal x: int = t.value   // type of t.value is unknown, runtime check\nreturn null\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_freeze_type_mismatch.diag.txt",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_freeze_type_mismatch.nut:2:0\n\n// EXPECTED: compile-time error - freeze({}) returns table, assigned to int variable\nlocal x: int = freeze({a = 1})\n^-----------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_freeze_type_mismatch.nut",
    "content": "// EXPECTED: compile-time error - freeze({}) returns table, assigned to int variable\nlocal x: int = freeze({a = 1})\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_function_literal.diag.txt",
    "content": "ERROR: expression of type 'function' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_function_literal.nut:2:0\n\n// EXPECTED: compile-time error - lambda assigned to int variable\nlocal x: int = @() 42\n^--------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_function_literal.nut",
    "content": "// EXPECTED: compile-time error - lambda assigned to int variable\nlocal x: int = @() 42\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_instance_from_class.diag.txt",
    "content": "ERROR: expression of type 'instance' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_instance_from_class.nut:6:0\n\n}\nlocal obj: string = MyClass()\n^----------------------------\nreturn obj\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_instance_from_class.nut",
    "content": "// EXPECTED: compile-time error - class() produces instance, assigned to string\nlocal MyClass = class {\n    x = 0\n    constructor() {}\n}\nlocal obj: string = MyClass()\nreturn obj\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_literal_float_to_int.diag.txt",
    "content": "ERROR: expression of type 'float' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_literal_float_to_int.nut:2:0\n\n// EXPECTED: compile-time error - float literal assigned to int variable\nlocal x: int = 3.14\n^------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_literal_float_to_int.nut",
    "content": "// EXPECTED: compile-time error - float literal assigned to int variable\nlocal x: int = 3.14\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_literal_int_to_string.diag.txt",
    "content": "ERROR: expression of type 'int' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_literal_int_to_string.nut:2:0\n\n// EXPECTED: compile-time error - integer literal assigned to string variable\nlocal x: string = 42\n^-------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_literal_int_to_string.nut",
    "content": "// EXPECTED: compile-time error - integer literal assigned to string variable\nlocal x: string = 42\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_literal_string_to_int.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_literal_string_to_int.nut:2:0\n\n// EXPECTED: compile-time error - string literal assigned to int variable\nlocal x: int = \"hello\"\n^---------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_literal_string_to_int.nut",
    "content": "// EXPECTED: compile-time error - string literal assigned to int variable\nlocal x: int = \"hello\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_return_float_to_int.diag.txt",
    "content": "ERROR: expression of type 'float' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_return_float_to_int.nut:3:4\n\nfunction fn(): int {\n    return 3.14\n    ^----------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_return_float_to_int.nut",
    "content": "// EXPECTED: compile-time error - return float from int function\nfunction fn(): int {\n    return 3.14\n}\nreturn fn\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_return_literal_mismatch.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_return_literal_mismatch.nut:3:4\n\nfunction fn(): int {\n    return \"hello\"\n    ^-------------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_return_literal_mismatch.nut",
    "content": "// EXPECTED: compile-time error - return string from int function\nfunction fn(): int {\n    return \"hello\"\n}\nreturn fn\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_slot_access_unknown.diag.txt",
    "content": ""
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_slot_access_unknown.nut",
    "content": "// EXPECTED: no compile-time error (should fall back to runtime check)\n// Slot access (dynamic key) has unknown type at compile time\nlocal t = { value = 42 }\nlocal key = \"value\"\nlocal x: int = t[key]   // type of t[key] is unknown, runtime check\nreturn null\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_string_concat_to_int.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_string_concat_to_int.nut:4:0\n\nlocal n: int = 42\nlocal result: int = s + n\n^------------------------\nreturn result\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_string_concat_to_int.nut",
    "content": "// EXPECTED: compile-time error - string concat produces string, not int\nlocal s: string = \"hello\"\nlocal n: int = 42\nlocal result: int = s + n\nreturn result\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_table_literal.diag.txt",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'array'\ntestData/diagnostics/compilation_errors/type_inference/test_table_literal.nut:2:0\n\n// EXPECTED: compile-time error - table literal assigned to array variable\nlocal x: array = { a = 1, b = 2 }\n^--------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_table_literal.nut",
    "content": "// EXPECTED: compile-time error - table literal assigned to array variable\nlocal x: array = { a = 1, b = 2 }\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_table_return.diag.txt",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'array'\ntestData/diagnostics/compilation_errors/type_inference/test_table_return.nut:3:4\n\nfunction make_table(): array {\n    return { a = 1, b = 2 }\n    ^----------------------\n}\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_table_return.nut",
    "content": "// EXPECTED: compile-time error - function returns table, declared as returning array\nfunction make_table(): array {\n    return { a = 1, b = 2 }\n}\nreturn make_table\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_table_to_string.diag.txt",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'string'\ntestData/diagnostics/compilation_errors/type_inference/test_table_to_string.nut:2:0\n\n// EXPECTED: compile-time error - table assigned to string\nlocal x: string = { a = 1 }\n^--------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_table_to_string.nut",
    "content": "// EXPECTED: compile-time error - table assigned to string\nlocal x: string = { a = 1 }\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_ternary_mismatch.diag.txt",
    "content": "ERROR: expression of type 'int|string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_ternary_mismatch.nut:3:0\n\nlocal flag = true\nlocal x: int = flag ? 42 : \"hello\"\n^---------------------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_ternary_mismatch.nut",
    "content": "// EXPECTED: compile-time error - ternary produces int|string, var only accepts int\nlocal flag = true\nlocal x: int = flag ? 42 : \"hello\"\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_typeof_to_int.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/compilation_errors/type_inference/test_typeof_to_int.nut:2:0\n\n// EXPECTED: compile-time error - typeof produces string, not int\nlocal x: int = typeof 42\n^-----------------------\nreturn x\n\n\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_typeof_to_int.nut",
    "content": "// EXPECTED: compile-time error - typeof produces string, not int\nlocal x: int = typeof 42\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_unknown_passthrough.diag.txt",
    "content": ""
  },
  {
    "path": "testData/diagnostics/compilation_errors/type_inference/test_unknown_passthrough.nut",
    "content": "// EXPECTED: no compile-time error (should fall back to runtime check)\n// When the expression type is unknown (~0u), the compiler cannot check\n// and must emit _OP_CHECK_TYPE for runtime. This test verifies no false positive.\nfunction unknown_fn(x) {  // no return type annotation\n    return x\n}\nlocal x: int = unknown_fn(42)   // unknown return type, runtime check only\nreturn null\n"
  },
  {
    "path": "testData/diagnostics/const_scope_1.diag.txt",
    "content": "ERROR: Unknown variable [x]\ntestData/diagnostics/const_scope_1.nut:4:6\n\nprint(x)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/const_scope_1.nut",
    "content": "if (true)\n  const x = 5\n\nprint(x)\n"
  },
  {
    "path": "testData/diagnostics/const_scope_2.diag.txt",
    "content": "ERROR: Unknown variable [x]\ntestData/diagnostics/const_scope_2.nut:5:6\n\nprint(x)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/const_scope_2.nut",
    "content": "local function f() {\n  const x = 6\n}\n\nprint(x)\n"
  },
  {
    "path": "testData/diagnostics/const_scope_3.diag.txt",
    "content": "ERROR: Unknown variable [x]\ntestData/diagnostics/const_scope_3.nut:4:8\n\nelse\n  print(x)\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/const_scope_3.nut",
    "content": "if (true)\n  const x = 6\nelse\n  print(x)\n"
  },
  {
    "path": "testData/diagnostics/continue_in_codeblock.diag.txt",
    "content": "ERROR: 'continue' has to be in a loop block\ntestData/diagnostics/continue_in_codeblock.nut:3:2\n\nlet x = $${\n  continue\n  ^-------\n  return 1\n\n\n"
  },
  {
    "path": "testData/diagnostics/continue_in_codeblock.nut",
    "content": "#allow-compiler-internals\nlet x = $${\n  continue\n  return 1\n}\n"
  },
  {
    "path": "testData/diagnostics/delete_base.diag.txt",
    "content": "ERROR: can't delete 'base'\ntestData/diagnostics/delete_base.nut:2:0\n\n#allow-delete-operator\ndelete base\n^----------\n\n\n"
  },
  {
    "path": "testData/diagnostics/delete_base.nut",
    "content": "#allow-delete-operator\ndelete base\n\n// ^ Legacy, to be removed\n"
  },
  {
    "path": "testData/diagnostics/delete_forbid_pragma.diag.txt",
    "content": "ERROR: Usage of 'delete' operator is forbidden. Use 'o.rawdelete(\"key\")' instead\ntestData/diagnostics/delete_forbid_pragma.nut.txt:10:0\n\ndelete t.a // FP 1\n^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/delete_forbid_pragma.nut.txt",
    "content": "\n\nlet t = {\n    a = 10,\n    b = 20,\n    c = 30,\n    d = 40\n}\n\ndelete t.a // FP 1\n\n#forbid-delete-operator\n\nt.rawdelete(\"b\")\n\n#allow-delete-operator\n\ndelete t.c // FP 2\n\n#forbid-delete-operator\n\ndelete t.d // EXPECTED"
  },
  {
    "path": "testData/diagnostics/destrucuring_var_decl_in_if.diag.txt",
    "content": "ERROR: Only single variable declaration is allowed here\ntestData/diagnostics/destrucuring_var_decl_in_if.nut:1:10\n\nif (local [x] = [1, 2, 3]; x > 4)\n          ^\n    println(\"fail\")\n\n\n"
  },
  {
    "path": "testData/diagnostics/destrucuring_var_decl_in_if.nut",
    "content": "if (local [x] = [1, 2, 3]; x > 4)\n    println(\"fail\")"
  },
  {
    "path": "testData/diagnostics/float_overflow.diag.txt",
    "content": "ERROR: float constant overflow\ntestData/diagnostics/float_overflow.nut:1:8\n\nprintln(1000000000000000000000000000000000000000.0)\n        ^-----------------------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/float_overflow.nut",
    "content": "println(1000000000000000000000000000000000000000.0)"
  },
  {
    "path": "testData/diagnostics/float_underflow.diag.txt",
    "content": "ERROR: float constant underflow\ntestData/diagnostics/float_underflow.nut:1:8\n\nprintln(0.00000000000000000000000000000000000000000000000000000000000000001)\n        ^------------------------------------------------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/float_underflow.nut",
    "content": "println(0.00000000000000000000000000000000000000000000000000000000000000001)\n"
  },
  {
    "path": "testData/diagnostics/foreach_destr_typed_default.diag.txt",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'int'\ntestData/diagnostics/foreach_destr_typed_default.nut:1:10\n\nforeach ({x: int = \"bad\"} in [{x = 1}]) {\n          ^-------------\n  println(x)\n\n\n"
  },
  {
    "path": "testData/diagnostics/foreach_destr_typed_default.nut",
    "content": "foreach ({x: int = \"bad\"} in [{x = 1}]) {\n  println(x)\n}\n"
  },
  {
    "path": "testData/diagnostics/hex_overflow.diag.txt",
    "content": "ERROR: too many digits for a hex number\ntestData/diagnostics/hex_overflow.nut:1:8\n\nprintln(0x1_0000_0000_0000_0000)\n        ^----------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/hex_overflow.nut",
    "content": "println(0x1_0000_0000_0000_0000)"
  },
  {
    "path": "testData/diagnostics/if_var_decl_init.diag.txt",
    "content": "ERROR: Initialization required\ntestData/diagnostics/if_var_decl_init.nut:1:11\n\nif (local x)\n           ^\n    println(\"fail\")\n\n\n"
  },
  {
    "path": "testData/diagnostics/if_var_decl_init.nut",
    "content": "if (local x)\n    println(\"fail\")"
  },
  {
    "path": "testData/diagnostics/import_01.diag.txt",
    "content": ""
  },
  {
    "path": "testData/diagnostics/import_01.nut",
    "content": "import \"a\"\n"
  },
  {
    "path": "testData/diagnostics/import_02.diag.txt",
    "content": ""
  },
  {
    "path": "testData/diagnostics/import_02.nut",
    "content": "/*\n  wretwert\n  rtwrt\n*/\n// wtwrtwrt wrtwr t\\\n/* adsfadf/* //  */ import /**/ \"a\" /**/ as x\n/*\n  wretwert\n  rtwrt\n*/\n"
  },
  {
    "path": "testData/diagnostics/import_03.diag.txt",
    "content": "ERROR: missing \"*/\" in comment\ntestData/diagnostics/import_03.nut:1:0\n\n/*\n^--------------------\nimport \"a\" as x\n\n\n"
  },
  {
    "path": "testData/diagnostics/import_03.nut",
    "content": "/*\nimport \"a\" as x\n"
  },
  {
    "path": "testData/diagnostics/import_04.diag.txt",
    "content": "ERROR: expected 'identifier'\ntestData/diagnostics/import_04.nut:2:1\n\nimport \"a\" as\n\n ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/import_04.nut",
    "content": "import \"a\" as\n\n"
  },
  {
    "path": "testData/diagnostics/import_05.diag.txt",
    "content": "ERROR: unrecognised escape char\ntestData/diagnostics/import_05.nut:1:5\n\nfrom \"../a\\..\\b\\folder/file.nut\" import *\n     ^-----\n\n\n"
  },
  {
    "path": "testData/diagnostics/import_05.nut",
    "content": "from \"../a\\..\\b\\folder/file.nut\" import *\n"
  },
  {
    "path": "testData/diagnostics/import_06.diag.txt",
    "content": ""
  },
  {
    "path": "testData/diagnostics/import_06.nut",
    "content": "#strict\n\n// import b\nimport \"math\" // as math2\n import \"dagor2.math\" as m\nfrom \"generic/std.nut\" import TMatrix as Matrix, /* Xyz as Qwe */\n  Point2 as point\n/* comment\ncomment\n// */\nfrom \"module2\" import *\n\n\nlocal a = require_optional(\"x.nut\")\nreturn a?.x\n"
  },
  {
    "path": "testData/diagnostics/import_07.diag.txt",
    "content": "ERROR: newline in a constant\ntestData/diagnostics/import_07.nut:1:7\n\nimport \"a\n       ^--\n\" as a\n\n\n"
  },
  {
    "path": "testData/diagnostics/import_07.nut",
    "content": "import \"a\n\" as a\n"
  },
  {
    "path": "testData/diagnostics/import_error.diag.txt",
    "content": "ERROR: expected 'identifier or *'\ntestData/diagnostics/import_error.nut:2:20\n\n// missing import list\nfrom \"file1\" import\n                    ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/import_error.nut",
    "content": "// missing import list\nfrom \"file1\" import\n"
  },
  {
    "path": "testData/diagnostics/init_with_wrong_type.diag.txt",
    "content": "ERROR: Assigned null type differs from the declared type\ntestData/diagnostics/init_with_wrong_type.nut:1:0\n\nlocal y: table\n^------\nreturn y\n\n\n"
  },
  {
    "path": "testData/diagnostics/init_with_wrong_type.nut",
    "content": "local y: table\nreturn y\n"
  },
  {
    "path": "testData/diagnostics/integer_overflow.diag.txt",
    "content": "ERROR: integer constant overflow\ntestData/diagnostics/integer_overflow.nut:1:8\n\nprintln(1000000000000000000000000000000000000000)\n        ^---------------------------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/integer_overflow.nut",
    "content": "println(1000000000000000000000000000000000000000)"
  },
  {
    "path": "testData/diagnostics/integer_overflow_2.diag.txt",
    "content": "ERROR: integer constant overflow\ntestData/diagnostics/integer_overflow_2.nut:1:8\n\nprintln(20496385583567863808)\n        ^-------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/integer_overflow_2.nut",
    "content": "println(20496385583567863808)"
  },
  {
    "path": "testData/diagnostics/integer_overflow_int_max.diag.txt",
    "content": "ERROR: integer constant overflow\ntestData/diagnostics/integer_overflow_int_max.nut:1:8\n\nprintln(9223372036854775808)\n        ^------------------\n\n\n"
  },
  {
    "path": "testData/diagnostics/integer_overflow_int_max.nut",
    "content": "println(9223372036854775808)"
  },
  {
    "path": "testData/diagnostics/interp_str_hanging_missed_ccurvy.diag.txt",
    "content": "ERROR: unfinished string\ntestData/diagnostics/interp_str_hanging_missed_ccurvy.nut:3:16\n\nprintln($\"{foo()\")\n                ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/interp_str_hanging_missed_ccurvy.nut",
    "content": "function foo() { return \"X\" }\n\nprintln($\"{foo()\")"
  },
  {
    "path": "testData/diagnostics/interp_str_not_string.diag.txt",
    "content": "ERROR: expected 'expression'\ntestData/diagnostics/interp_str_not_string.nut:3:8\n\nprintln($'{{{{{{{{')\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/interp_str_not_string.nut",
    "content": "\n\nprintln($'{{{{{{{{')"
  },
  {
    "path": "testData/diagnostics/interp_str_not_string_2.diag.txt",
    "content": "ERROR: expected 'expression'\ntestData/diagnostics/interp_str_not_string_2.nut:5:8\n\nprintln($foo())\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/interp_str_not_string_2.nut",
    "content": "\n\nfunction foo() {}\n\nprintln($foo())"
  },
  {
    "path": "testData/diagnostics/interp_str_wrong_template.diag.txt",
    "content": "ERROR: expected 'IDENTIFIER'\ntestData/diagnostics/interp_str_wrong_template.nut:3:12\n\nprintln($\"{{{{{{{{\")\n            ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/interp_str_wrong_template.nut",
    "content": "\n\nprintln($\"{{{{{{{{\")"
  },
  {
    "path": "testData/diagnostics/invalid_float_1.diag.txt",
    "content": "ERROR: malformed number\ntestData/diagnostics/invalid_float_1.nut:1:8\n\nprintln(1e4e-4)\n        ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_float_1.nut",
    "content": "println(1e4e-4)\n"
  },
  {
    "path": "testData/diagnostics/invalid_float_2.diag.txt",
    "content": "ERROR: malformed number\ntestData/diagnostics/invalid_float_2.nut:1:8\n\nprintln(1e4......)\n        ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_float_2.nut",
    "content": "println(1e4......)"
  },
  {
    "path": "testData/diagnostics/invalid_float_3.diag.txt",
    "content": "ERROR: malformed number\ntestData/diagnostics/invalid_float_3.nut:1:8\n\nprintln(1.2.3.4)\n        ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_float_3.nut",
    "content": "println(1.2.3.4)"
  },
  {
    "path": "testData/diagnostics/invalid_string_interp_1.diag.txt",
    "content": "ERROR: unfinished string\ntestData/diagnostics/invalid_string_interp_1.nut:1:11\n\nprintln($\"{\")\n           ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_string_interp_1.nut",
    "content": "println($\"{\")"
  },
  {
    "path": "testData/diagnostics/invalid_type_hint_1.diag.txt",
    "content": "ERROR: expected 'TYPE_NAME'\ntestData/diagnostics/invalid_type_hint_1.nut:1:6\n\nlet a:2 = 3\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_type_hint_1.nut",
    "content": "let a:2 = 3"
  },
  {
    "path": "testData/diagnostics/invalid_type_hint_2.diag.txt",
    "content": "ERROR: expected 'TYPE_NAME'\ntestData/diagnostics/invalid_type_hint_2.nut:1:16\n\nfunction fn(...:) {}\n                ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_type_hint_2.nut",
    "content": "function fn(...:) {}"
  },
  {
    "path": "testData/diagnostics/invalid_type_hint_3.diag.txt",
    "content": "ERROR: Invalid type name 'Integer', did you mean 'int'?\ntestData/diagnostics/invalid_type_hint_3.nut:1:13\n\nlet a = @(x: Integer): Integer x * x\n             ^------\n\n\n"
  },
  {
    "path": "testData/diagnostics/invalid_type_hint_3.nut",
    "content": "let a = @(x: Integer): Integer x * x"
  },
  {
    "path": "testData/diagnostics/leading_zero_1.diag.txt",
    "content": "ERROR: leading 0 is not allowed, octal numbers are not supported\ntestData/diagnostics/leading_zero_1.nut:1:6\n\nprint(00)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/leading_zero_1.nut",
    "content": "print(00)"
  },
  {
    "path": "testData/diagnostics/leading_zero_2.diag.txt",
    "content": "ERROR: leading 0 is not allowed, octal numbers are not supported\ntestData/diagnostics/leading_zero_2.nut:1:6\n\nprint(01)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/leading_zero_2.nut",
    "content": "print(01)"
  },
  {
    "path": "testData/diagnostics/leading_zero_3.diag.txt",
    "content": "ERROR: leading 0 is not allowed, octal numbers are not supported\ntestData/diagnostics/leading_zero_3.nut:1:6\n\nprint(00.1)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/leading_zero_3.nut",
    "content": "print(00.1)"
  },
  {
    "path": "testData/diagnostics/letAssign.diag.txt",
    "content": "ERROR: can't assign to binding 'y' (probably declaring using 'local' was intended, but 'let' was used)\ntestData/diagnostics/letAssign.nut:4:0\n\nlet y = 30\ny = 40\n^\n\n\n"
  },
  {
    "path": "testData/diagnostics/letAssign.nut",
    "content": "local x = 10\nx = 20\nlet y = 30\ny = 40"
  },
  {
    "path": "testData/diagnostics/many_args_in_function_call.diag.txt",
    "content": "ERROR: internal compiler error: too many locals\ntestData/diagnostics/many_args_in_function_call.nut:-1:-1\n"
  },
  {
    "path": "testData/diagnostics/many_args_in_function_call.nut",
    "content": "local function f(...) {}\nf(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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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,\n  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\n  )"
  },
  {
    "path": "testData/diagnostics/need_space_after_float.diag.txt",
    "content": "ERROR: malformed number\ntestData/diagnostics/need_space_after_float.nut:2:9\n\nlocal f = 333\nprintln([5.0f][1])\n         ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/need_space_after_float.nut",
    "content": "local f = 333\nprintln([5.0f][1])\n"
  },
  {
    "path": "testData/diagnostics/need_space_after_hex.diag.txt",
    "content": "ERROR: expected hex digits after '0x'\ntestData/diagnostics/need_space_after_hex.nut:2:9\n\nlet x = 123\nprintln([0xx][1])\n         ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/need_space_after_hex.nut",
    "content": "let x = 123\nprintln([0xx][1])\n"
  },
  {
    "path": "testData/diagnostics/need_space_after_int.diag.txt",
    "content": "ERROR: malformed number\ntestData/diagnostics/need_space_after_int.nut:2:9\n\nlocal f = 333\nprintln([5f][1])\n         ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/need_space_after_int.nut",
    "content": "local f = 333\nprintln([5f][1])\n"
  },
  {
    "path": "testData/diagnostics/return_type_check_1.diag.txt",
    "content": "ERROR: Return type differs from the declared type\ntestData/diagnostics/return_type_check_1.nut:4:8\n\n    if (x < 0)\n        return\n        ^-----\n    return 4\n\n\n"
  },
  {
    "path": "testData/diagnostics/return_type_check_1.nut",
    "content": "\nfunction fn(x: int): int {\n    if (x < 0)\n        return\n    return 4\n}\n\nreturn fn\n"
  },
  {
    "path": "testData/diagnostics/single_var_decl_in_if.diag.txt",
    "content": "ERROR: Only single variable declaration is allowed here\ntestData/diagnostics/single_var_decl_in_if.nut:1:13\n\nif (let x = 4, y = 6)\n             ^\n    println(\"fail\")\n\n\n"
  },
  {
    "path": "testData/diagnostics/single_var_decl_in_if.nut",
    "content": "if (let x = 4, y = 6)\n    println(\"fail\")"
  },
  {
    "path": "testData/diagnostics/space_sep_name.diag.txt",
    "content": "ERROR: Separate access operator '.' with its following name is forbidden\ntestData/diagnostics/space_sep_name.nut.txt:10:0\n\na1.\nappend(8).  // NOT OK\n^-----\nextend(6)   // NOT OK\n\n\n"
  },
  {
    "path": "testData/diagnostics/space_sep_name.nut.txt",
    "content": "\n\n\nlet a1 = [1, 2, 3]\n\na1.append(6) // OK\n.extend(7)   // OK\n\na1.\nappend(8).  // NOT OK\nextend(6)   // NOT OK\n"
  },
  {
    "path": "testData/diagnostics/space_sep_name_space.diag.txt",
    "content": "ERROR: Separate access operator '?.$' with its following name is forbidden\ntestData/diagnostics/space_sep_name_space.nut.txt:8:10\n\nt1?.$     foo // NOT OK\n          ^--\n\n\n"
  },
  {
    "path": "testData/diagnostics/space_sep_name_space.nut.txt",
    "content": "let t1 = {}\n\n\nt1              ?.foo // OK\n.bar    // OK\n\n\nt1?.$     foo // NOT OK"
  },
  {
    "path": "testData/diagnostics/too_large_static_memo_expr.diag.txt",
    "content": "ERROR: static expression is too big\ntestData/diagnostics/too_large_static_memo_expr.nut.txt:3:14\n\nlet x = static(\n              ^\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n\n\n"
  },
  {
    "path": "testData/diagnostics/too_large_static_memo_expr.nut.txt",
    "content": "function a() { return 1 }\n\nlet x = static(\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  (a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+(a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a()+a())+\n  1\n)\n\nreturn x\n"
  },
  {
    "path": "testData/diagnostics/too_many_locals2.diag.txt",
    "content": "ERROR: internal compiler error: too many locals\ntestData/diagnostics/too_many_locals2.nut:-1:-1\n"
  },
  {
    "path": "testData/diagnostics/too_many_locals2.nut",
    "content": "//#disable-optimizer\n#allow-switch-statement\nlet _sv = @(_e) (type(_e) == \"integer\" || type(_e) == \"float\" || type(_e) == \"null\" || type(_e) == \"bool\" || type(_e) == \"string\") ? \"\" + _e : type(_e)\ntry {\n// Code Bricks assembly - seed 126\n  const function [pure] v0_fn(x) { return x + 0 }\n  const v0_a = -65536\n  const v0 = v0_fn(v0_a)  // [const_chain]\n  local v1 = v0\n  v1 *= 32769  // [modify_mul_const]\n  let v2_C = class {\n    _n = 0\n    constructor(n) { this._n = n & 7 }\n    function _nexti(idx) {\n      local next = idx == null ? 0 : idx + 1\n      return next < this._n ? next : null\n    }\n    function _get(idx) { return idx * -257 }\n  }\n  let v2_obj = v2_C(v0)\n  local v2 = 0\n  foreach (_i, v in v2_obj) v2 += v  // [meta_nexti]\n  global enum S126_E1 { A = \"\\u0000\", B = \"world\" }\n  let v3 = $\"{S126_E1.A}{S126_E1.B}\"  // [enum_string]\n  let v4_outer = {inner = {value = 42}}\n  let v4 = v4_outer?.inner?.value ?? 4294967295  // [nullsafe_nested_table]\n  let v5 = (function() {\n    let g = (function() {\n      for (local i = 0; i < 1; i++) yield i\n    })()\n    local s = 0\n    while (g.getstatus() == \"suspended\") {\n      s += resume g\n    }\n    return s\n  })()  // [coroutine_sum]\n  let v6_C = class {\n    _v = 0\n    constructor(xv) { this._v = xv }\n  }\n  let v6_obj = v6_C(v1)\n  let v6 = v6_obj instanceof v6_C  // [instanceof_check]\n  let v7 = ~v4  // [int_bitnot]\n  local v8_root = {child = {data = {count = 32767, value = v5}}}\n  local v8_data = v8_root.child.data\n  v8_data.count += '9'\n  v8_data.value *= 1000\n  let v8 = v8_root.child.data.count + v8_root.child.data.value  // [modify_via_local_ref]\n  let v9_fn = function(x, acc = []) {\n    acc.append(x)\n    return acc.len()\n  }\n  let v9_a = v9_fn(v7)\n  let v9_b = v9_fn(v7 + 1)\n  let v9 = v9_a + v9_b  // [default_param_mutable_shared]\n  let v10_fn = function(x, pipe = {pre = @(v) v & 0xFF,\n                                   run = @(v) v + 129,\n                                   post = @(v) v * -255}) {\n    return pipe.post(pipe.run(pipe.pre(x)))\n  }\n  let v10 = v10_fn(v1)  // [default_param_pipeline]\n  let v11_C = class {\n    _v = 0\n    constructor(xv) { this._v = xv }\n  }\n  let v11_obj = v11_C(v10)\n  let v11 = v11_obj instanceof v11_C  // [instanceof_check]\n  let v12 = v0 < v8 ? v0 : v8  // [int_min_two]\n  let v13 = v2 + v10  // [int_add]\n  local v14 = 0\n  local v14_v = v0 & 0xFF\n  while (v14_v != 0) {\n    v14 += v14_v & 1\n    v14_v = v14_v >>> 1\n  }  // [int_bit_count]\n  let v15 = v3.len()  // [string_len]\n  let v16 = v10\n  assert(v16 == v16)  // [assert_tautology]\n  let v17_fn = function(p0, p1, p2) {\n    local u0 = 9223372036854775807\n    try { u0 = p1.tointeger() } catch (_e) {}  // [string_tointeger]\n    local u1_state = 0\n    let u1_inc = function() { u1_state++; return u1_state }\n    u1_inc()\n    u1_inc()\n    let u1 = u1_inc()  // [closure_counter]\n    let u2 = p1.indexof(v3) ?? 129  // [string_indexof]\n    local u3 = typeof p2\n    switch (u3) {\n      case \"integer\": u3 = \"int\"; break\n      case \"float\": u3 = \"flt\"; break\n      case \"string\": u3 = \"str\"; break\n      default: u3 = \"other\"\n    }  // [typeof_switch]\n    let u4_fn = function(x, ctx = {\n        cls = class { v = 0; constructor(n) { this.v = n } },\n        wrap = @(inst) inst.v + -9223372036854775807\n      }) {\n      return ctx.wrap(ctx.cls(x))\n    }\n    let u4 = u4_fn(v14)  // [default_param_table_class]\n    let u5_fns = [@(x) x + -130, @(x) x * 127, @(x) x - -257]\n    local u5 = u1\n    foreach (f in u5_fns) u5 = f(u5)  // [array_of_closures_accumulate]\n    let u6 = typeof u4 == \"integer\"  // [typeof_int_check]\n    let u7 = (@(a, b) a + b)(u3, p1)  // [lambda_str_concat]\n    return u7\n  }\n  let v17 = v17_fn(v5, v3, v13)  // [nested_func depth=1]\n  let v18_fn = function(n) {\n    local i = 0\n    while (i < 8) {\n      if (i * n > -127) return i\n      i++\n    }\n    return i\n  }\n  let v18 = v18_fn(v7)  // [while_early_return]\n  let v19 = v0.tostring()  // [int_to_string]\n  let v20 = v3.indexof(v17) ?? -65537  // [string_indexof]\n  let v21 = v6 ? v13 : v5  // [ternary_int]\n  let v22_outer = function(x) {\n    let inner = @(n) n * -65535\n    return inner(x) + 4294967297\n  }\n  let v22 = v22_outer(v0)  // [nested_function]\n  let v23_fn = function(p0, p1, p2) {\n    let u0 = __LINE__  // [magic_line]\n    let u1 = -v0  // [int_neg]\n    local u2 = 1\n    local u2_i = 0\n    while (u2_i < 1) {\n      u2 = u2 * ((v0 % 4) + 1)\n      u2_i++\n    }  // [while_mul]\n    local u3 = false\n    try { u3 = u1 == v7 } catch (_e) {}  // [any_cmp_eq]\n    local u4 = v13\n    ++u4  // [prefix_inc]\n    let u5 = v3.rstrip()  // [string_rstrip]\n    return u5\n  }\n  let v23 = v23_fn(v12, v19, v6)  // [nested_func depth=1]\n  local v24_iseven = null\n  local v24_isodd = null\n  v24_iseven = @(n) (n & 7) == 0 ? true : v24_isodd(n - 1)\n  v24_isodd = @(n) (n & 7) == 0 ? false : v24_iseven(n - 1)\n  let v24 = v24_iseven(v5 & 7) ? -3 : 255  // [mutual_recursion]\n  let v25 = v19.len()  // [string_len]\n  let v26_fn = function(...) {\n    return vargv.len() > 0 ? vargv[0] : 256\n  }\n  let v26 = v26_fn(v8)  // [vargv_first]\n  local v27 = 0\n  switch (v24 & 3) {\n    case 0:\n    case 1: v27 = -2147483648; break\n    case 2: v27 = -3; break\n    default: v27 = '\\t'\n  }  // [switch_fallthrough]\n  local v28 = -4294967295\n  if (v26 > v13) {\n    v28 = 65536\n  } else if (v26 == v13) {\n    v28 = 0\n  } else {\n    v28 = -32768\n  }  // [if_chain]\n  let v29 = !v11  // [bool_not]\n  let v30_fn = @(a: int, b: int) a * b\n  let v30 = v30_fn(v18, v21)  // [typed_lambda]\n  local v31 = v0\n  v31++  // [postfix_inc]\n  local v32 = -127\n  switch (v25 % 3) {\n    case 0: v32 = -255; break\n    case 1: v32 = 0xFF; break\n    default: v32 = -32769; break\n  }  // [switch_default]\n  local v33 = v9\n  v33 += v28\n  v33 -= v22\n  v33 *= -4294967298  // [modify_chain]\n  let v34_fn = function({dx, dy = -9223372036854775807}, [da, db]) {\n    return dx + dy + da + db\n  }\n  let v34 = v34_fn({dx = v24}, [v15, v18])  // [destruct_param_mixed]\n  local v35_sum = 0\n  let v35_add = function(x) { v35_sum = v35_sum + x }\n  v35_add(v24)\n  v35_add(v7)\n  v35_add(v24 + v7)\n  let v35 = v35_sum  // [closure_accumulator]\n  let [v36_a, v36_b] = [v5, v5 + 1]\n  let [v36_c] = [v36_a + v36_b]\n  let v36 = v36_c  // [destruct_nested]\n  let v37_fn = function({da, db}) { return da + db }\n  let v37 = v37_fn({da = v30, db = v27})  // [destruct_param_table]\n  let v38_fn = function(x,\n      cls = class { function calc(v) { return v + 4294967295 } }) {\n    return cls().calc(x)\n  }\n  let v38_a = v38_fn(v4)\n  let v38_other = class { function calc(v) { return v * 0x100 } }\n  let v38_b = v38_fn(v4, v38_other)\n  let v38 = v38_a + v38_b  // [default_param_class]\n  let v39_fn = function(p0, p1) {\n    local u0 = -32770\n    switch (v17) {\n      case \"a\": u0 = 42; break\n      case \"b\": u0 = -2147483647; break\n      case \"c\": u0 = 1; break\n      default: u0 = -257\n    }  // [switch_string]\n    let u1_fn = function(n) {\n      local x = n & 7\n      if (x <= 0) return 0\n      return x + callee()(x - 1)\n    }\n    let u1 = u1_fn(v7)  // [func_recursive_sum]\n    local u2 = v0\n    u2 += 0xDEADBEEF  // [modify_add_const]\n    let u3_fn = function() {\n      let w0_t = {a = {b = {c = v36}}}\n      let w0 = w0_t?.a?.b?.c ?? -1  // [table_deep]\n      let w1_fns = [@(x) x + 256, @(x) x * 65536, @(x) x - -257]\n      local w1 = v1\n      foreach (f in w1_fns) w1 = f(w1)  // [array_of_closures_accumulate]\n      let w2_idx = v17.indexof(v23)\n      let w2 = w2_idx != null ? w2_idx : 0x80000000  // [string_find_method]\n      local w3 = 0\n      for (local w3_i = 0; w3_i < 2; w3_i++) {\n        w3 += v30\n        if (w3 >= (v13 & 0x7FFFFFFF)) break\n      }  // [for_break_early]\n      return w3\n    }\n    let u3 = u3_fn()  // [nested_func depth=2]\n    let u4_fn = function() {\n      let w0 = {a = null, b = null}  // [null_table_value]\n      let w1_make = @(bv) @(x) x + bv\n      let w1_add = w1_make(v12)\n      let w1 = w1_add(32768)  // [func_returns_func]\n      let w2_fn = function(x: int): string|null { return x > -32770 ? \"[]{}()\" : null }\n      let w2 = w2_fn(v13) != null  // [typed_return_null]\n      function [pure] w3_fn(x) { return x * 65535 }\n      let w3 = w3_fn(v12)  // [named_func_pure]\n      const function [pure] w4_fn(a, b) { return a + b * 65536 }\n      const w4 = w4_fn(-4294967298, 3)  // [const_pure_call_multi]\n      return w4\n    }\n    let u4 = u4_fn()  // [nested_func depth=2]\n    let u5_fn = function() {\n      local w0 = \"\"\n      if (v11) {\n        w0 = v19\n      } else {\n        w0 = v23\n      }  // [if_else_str]\n      let w1_t = {x = v25}\n      w1_t.x *= -9223372036854775807\n      let w1 = w1_t.x  // [table_field_muleq]\n      local w2 = v30\n      w2++\n      w2++\n      w2--  // [inc_dec_chain]\n      return w2\n    }\n    let u5 = u5_fn()  // [nested_func depth=2]\n    let u6_C = class {\n      v = 0\n      constructor(x) { this.v = x }\n      function get() { return this.v }\n    }\n    local u6_holder = {obj = u6_C(v31), tag = \"\\uffff\"}\n    let u6 = u6_holder?.obj?.get() ?? 2147483647  // [table_with_instance_field]\n    return u6\n  }\n  let v39 = v39_fn(v18, v16)  // [nested_func depth=1]\n  local v40 = -4\n  switch (v3) {\n    case \"a\": v40 = 1000; break\n    case \"b\": v40 = -127; break\n    case \"c\": v40 = 256; break\n    default: v40 = ' '\n  }  // [switch_string]\n  local v41 = v9 & 7\n  do {\n    v41--\n  } while (v41 > 0)  // [do_while_dec]\n  global enum S126_E2 { V1 = 3, V2 = -32769 }\n  let v42_t = {a = S126_E2.V1, b = S126_E2.V2}\n  let v42 = v42_t.a + v42_t.b  // [enum_in_table]\n  let v43_fn = function(x: int|null): int { return x != null ? x : 0x80000000 }\n  let v43 = v43_fn(v8)  // [typed_nullable_param]\n  local v44 = v25 & 7\n  do {\n    v44--\n  } while (v44 > 0)  // [do_while_dec]\n  let v45_fn = function(p0, p1) {\n    let u0_fn = function(n) {\n      local i = 0\n      while (i < -1) {\n        if (i * n > 3) return i\n        i++\n      }\n      return i\n    }\n    let u0 = u0_fn(v34)  // [while_early_return]\n    let u1_fn = function(x: int): int { return x * 1000 }\n    let u1 = u1_fn(v40)  // [typed_function_return]\n    let u2_C = class {\n      _a = 0\n      _b = 0\n      constructor(xa, xb) { this._a = xa; this._b = xb }\n      function sum() { return this._a + this._b }\n      function diff() { return this._a - this._b }\n    }\n    let u2_obj = u2_C(v15, v2)\n    let u2 = u2_obj.sum() + u2_obj.diff()  // [class_method_call]\n    let u3_fn = function(x: int|null): int { return x != null ? x : -2 }\n    let u3 = u3_fn(v22)  // [typed_nullable_param]\n    let u4_fn = function(a, b,\n        combine = {op = @(x, y) x + y, identity = -3}) {\n      return combine.op(a, b) + combine.identity\n    }\n    let u4_add = u4_fn(v4, v26)\n    let u4_mul = u4_fn(v4, v26,\n      {op = @(x, y) x * y, identity = -4294967295})\n    let u4 = u4_add + u4_mul  // [default_param_fn_field_call]\n    let u5 = (function() {\n      let gen = (function() {\n        yield 0\n        yield -32769\n        yield 32769\n      })()\n      let arr = []\n      while (gen.getstatus() == \"suspended\") {\n        arr.append(resume gen)\n      }\n      return arr\n    })()  // [coroutine_collect_all]\n    return u4\n  }\n  let v45 = v45_fn(v39, v25)  // [nested_func depth=1]\n  let v46 = {}  // [empty_table]\n  let v47_t = {arr = [0, null, {key = v39}]}\n  let v47 = v47_t?.arr?[2]?.key ?? 42  // [nested_table_array_nullsafe_read]\n  let v48_fn = function(x, s, cfg = {\n      fmt = @(n, t) $\"{n}:{t}\",\n      limits = {lo = -2147483648, hi = -65535}\n    }) {\n    local clamped = x < cfg.limits.lo ? cfg.limits.lo\n                  : x > cfg.limits.hi ? cfg.limits.hi : x\n    return cfg.fmt(clamped, s)\n  }\n  let v48 = v48_fn(v9, v17)  // [default_param_config_nested]\n  local v49 = 32769\n  if (let v49_v = v46?.x; v49_v != null) {\n    v49 = v49_v\n  }  // [if_let_nullcheck]\n  local v50 = 0\n  foreach (c in v48) {\n    if (c >= '0' && c <= '9') v50++\n  }  // [string_scan_digits]\n  local v51 = 2147483648\n  if (v29) {\n    v51 = v2 + 128\n  } else {\n    v51 = v12 - 4294967297\n  }  // [if_else_int]\n  local v52 = \"\"\n  foreach (c in v17) {\n    if (c != ' ') v52 += c.tochar()\n  }  // [string_build_filtered]\n  const function [pure] v53_fn(x) { return x + 0xDEADBEEF }\n  const v53_a = 0x1\n  const v53 = v53_fn(v53_a)  // [const_chain]\n  const v54 = -32769 + -255  // [const_expr]\n  let v55 = typeof null == \"null\"  // [typeof_null_check]\n  const function [pure] v56_fn(x) { return x * -1 }\n  const v56 = v56_fn(4294967296)  // [const_pure_call]\n  let v57_fn = function(p0, p1) {\n    let u0 = []\n    local u0_i = 0\n    while (u0_i < 3) {\n      u0.append(u0_i * u0_i)\n      u0_i++\n    }  // [while_array_fill]\n    let u1_fn = function(x, ctx = {\n        cls = class { v = 0; constructor(n) { this.v = n } },\n        wrap = @(inst) inst.v + -4294967295\n      }) {\n      return ctx.wrap(ctx.cls(x))\n    }\n    let u1 = u1_fn(v9)  // [default_param_table_class]\n    let u2_fn = function() {\n      local w0 = 0\n      for (local w0_i = 7; w0_i > 0; w0_i--) {\n        w0 += v56\n      }  // [for_countdown]\n      local w1 = \"\"\n      local w1_i = 0\n      while (w1_i < 1) {\n        w1 = w1 + v3\n        w1_i++\n      }  // [while_string_build]\n      local w2 = 0\n      u0.each(@(_v) w2++)  // [array_each_lambda]\n      return w2\n    }\n    let u2 = u2_fn()  // [nested_func depth=2]\n    let u3 = v9.tofloat()  // [int_to_float]\n    let u4 = u0.findvalue(@(v) v != null) ?? 2147483648  // [array_findvalue]\n    let u5 = array(v38 & 7, 128)  // [array_function_init]\n    return u4\n  }\n  let v57 = v57_fn(v50, v7)  // [nested_func depth=1]\n  local v58_state = 0\n  let v58_inc = function() { v58_state++; return v58_state }\n  v58_inc()\n  v58_inc()\n  let v58 = v58_inc()  // [closure_counter]\n  enum S126_E3 { LOW = 0, MID = 50, HIGH = 100 }\n  local v59 = \"\"\n  if (v51 < S126_E3.MID) v59 = \"low\"\n  else if (v51 < S126_E3.HIGH) v59 = \"mid\"\n  else v59 = \"high\"  // [enum_compare_chain]\n  let v60 = [v35, v17, true, null]  // [array_mixed_types]\n  let v61 = v60.len()  // [array_len]\n  local v62_state = {scores = [v51, -4294967296, 2], tag = \"test\"}\n  v62_state.scores[0] += -65536\n  v62_state.scores[2] = v62_state.scores[0] + v62_state.scores[1]\n  let v62 = v62_state.scores.reduce(@(a, v) a + v, 0)  // [table_slot_array_modify]\n  let v63_fn = @[pure, nodiscard] (a, b) a + b\n  let v63 = v63_fn(v2, v36)  // [func_pure_nodiscard]\n  let v64 = $\"{v19}{v59}\"  // [string_concat]\n  let v65 = v29 ? v58 : v40  // [ternary_int]\n  enum S126_E4 { LOW = 0, MID = 1, HIGH = 2 }\n  let v66 = (v30 & 3) == S126_E4.MID  // [enum_compare]\n  let v67_fn = function(p0, p1, p2) {\n    if (v60.len() > 0) v60[0] = v32\n    let u0 = v60?[0] ?? 4294967296  // [array_set_elem]\n    let u1 = v60.hasvalue(v57)  // [array_hasvalue]\n    let u2_fn = function() {\n      let w0 = v48.len() > 4 ? v48.slice(1, 3) : v48  // [string_slice_both]\n      let w1 = freeze(clone v46)  // [freeze_table]\n      let w2 = v29 ? v34 : v57  // [ternary_int]\n      return w2\n    }\n    let u2 = u2_fn()  // [nested_func depth=2]\n    let u3 = array(v62 & 7, -65536)  // [array_function_init]\n    return u2\n  }\n  let v67 = v67_fn(v4, v45, v53)  // [nested_func depth=1]\n  let v68 = v46.len() > 0 ? v46.reduce(@(a, _v) a) : -2147483649  // [table_reduce]\n  let v69 = typeof v60 == \"array\"  // [typeof_array_check]\n  function [pure, nodiscard] v70_fn(x) { return x - 0x1 }\n  let v70 = v70_fn(v26)  // [named_func_pure_nodiscard]\n  local v71 = 0\n  foreach (_k, _v in v46) {\n    v71++\n  }  // [foreach_table_keys]\n  let v72 = v46.values()  // [table_values]\n  local v73 = 0\n  for (local v73_i = 0; v73_i < 1; v73_i++) {\n    if (v73_i % 2 == 0) continue\n    v73 = v73 + v2\n  }  // [for_continue]\n  let v74 = (@(x) -x)(v50)  // [lambda_negate]\n  let v75_fn = function() {\n    let u0 = [v1, v73]  // [array_of_ints]\n    let u1_fn = function(...) {\n      local s = 0\n      foreach (v in vargv) s += v\n      return s\n    }\n    let u1 = u1_fn(v44, v74, -4294967297)  // [vargv_sum]\n    let u2_fn = function(q0) {\n      local w0 = 0\n      foreach (c in v3) {\n        if (c >= 'A' && c <= 'Z') w0++\n      }  // [string_scan_upper]\n      let w1 = (true ? (v55 ? v23 : v23) : v59)  // [string_literal]\n      let w2 = []\n      local w2_i = 0\n      while (w2_i < 0) {\n        w2.append(w2_i * w2_i)\n        w2_i++\n      }  // [while_array_fill]\n      let w3 = v63.tofloat()  // [int_to_float]\n      local w4 = 0\n      foreach (_c in v59) w4++  // [foreach_string_chars]\n      let w5 = v46?.x ?? 256  // [nullsafe_field]\n      return w5\n    }\n    let u2 = u2_fn(v56)  // [nested_func depth=2]\n    let u3_t = {x = v35, y = 0xDEADBEEF}\n    let u3_v = u3_t.rawget(\"x\") ?? -65536\n    u3_t.rawdelete(\"x\")\n    let u3 = u3_v  // [table_rawdelete]\n    local u4 = \"\"\n    if (let u4_v = v64; u4_v.len() > 0) {\n      u4 = u4_v.toupper()\n    }  // [if_let_string]\n    const u5 = 1e-40  // [const_float]\n    return u5\n  }\n  let v75 = v75_fn()  // [nested_func depth=1]\n  let v76 = v32 < v30 ? v32 : v30  // [int_min_two]\n  local v77: string = v59  // [typed_string_var]\n  let v78_fn = function(p0, p1, p2) {\n    let u0 = v45 > 0 ? 1 : (v45 < 0 ? -1 : 0)  // [int_sign]\n    let u1_t = freeze({x = v24, y = -4})\n    let u1 = u1_t.x + u1_t.y  // [freeze_nested]\n    local u2_val = v34\n    let u2_set = function(x) { u2_val = x }\n    let u2_get = function() { return u2_val }\n    u2_set(v34 + -255)\n    let u2 = u2_get()  // [closure_getter_setter]\n    let u3 = v41\n    assert(u3 == u3)  // [assert_tautology]\n    let u4 = v75.tointeger()  // [float_to_int]\n    return u4\n  }\n  let v78 = v78_fn(v42, v10, v6)  // [nested_func depth=1]\n  let v79 = v46.len()  // [table_len]\n  let v80 = clone v72\n  for (local v80_i = 0; v80_i < v80.len(); v80_i++)\n    v80[v80_i] = v49  // [array_modify_elems]\n  local v81 = -257\n  if (let v81_v = v46?.x; v81_v != null) {\n    v81 = v81_v\n  }  // [if_let_nullcheck]\n  let v82_fn = function(a, b,\n      combine = {op = @(x, y) x + y, identity = 257}) {\n    return combine.op(a, b) + combine.identity\n  }\n  let v82_add = v82_fn(v26, v63)\n  let v82_mul = v82_fn(v26, v63,\n    {op = @(x, y) x * y, identity = -4294967297})\n  let v82 = v82_add + v82_mul  // [default_param_fn_field_call]\n  local v83_cfg = {a = {val = v25 + 32769}, b = {val = v25 - 0x8000}}\n  let v83 = v66 ? (v83_cfg?.a?.val ?? 0x100) : (v83_cfg?.b?.val ?? 0x8000)  // [conditional_deep_path]\n  let v84_fn = function(p0) {\n    local u0 = -256\n    u0 = v40\n    u0 = u0 + 2147483649\n    u0 = u0 * 3  // [expr_stmt_assign_chain]\n    let u1 = v4 || v71  // [logical_or_val]\n    let u2 = v43 != 0 ? v58 % v43 : 0x7FFF  // [int_mod_safe]\n    return u2\n  }\n  let v84 = v84_fn(v57)  // [nested_func depth=1]\n  let v85_t = clone v46\n  v85_t.tmp <- -2147483648\n  let v85 = v85_t.tmp  // [table_delete_read]\n  let v86 = typeof null == \"null\"  // [typeof_null_check]\n  let v87_v = v39 & 0xFFFF\n  let v87 = v87_v > 0 && (v87_v & (v87_v - 1)) == 0  // [int_pow2_check]\n  let v88_fn = function([da, db = -4]) { return da * db }\n  let v88 = v88_fn([v45])  // [destruct_param_array_default]\n  let v89_arr = v46?.keys\n  let v89 = v89_arr != null ? v46.keys().len() : -4294967298  // [nullsafe_method_on_result]\n  let v90 = [v86, v66, true, false]  // [array_of_bools]\n  let v91 = v3 == v48  // [str_cmp_eq]\n  let v92_fn = function(p0, p1) {\n    let u0 = v46.keys()  // [table_keys]\n    local u1 = 3\n    try {\n      let g = (function() { yield v34; yield v34 + 1 })()\n      u1 = resume g\n    } catch (_e) {\n      u1 = -2147483648\n    }  // [coroutine_try_catch]\n    local u2 = v9\n    u2 *= v25  // [modify_mul_int]\n    let u3 = []  // [empty_array]\n    return u2\n  }\n  let v92 = v92_fn(v5, v35)  // [nested_func depth=1]\n  let v93 = v90.len() >= 2\n    ? v90[0] + v90[1]\n    : v90.len() == 1 ? v90[0] : -65535  // [array_two_elems]\n  let v94_fn = function(x: int|float): int { return x.tointeger() }\n  let v94 = v94_fn(v38)  // [typed_union_param]\n  let v95 = (function(x) { return x * x })(v39)  // [immediate_invoke]\n  local v96 = v18\n  v96 %= v13  // [modify_mod_int_unsafe]\n  let v97 = [65535, 129, 4294967295]\n  v97.insert(1, v38)\n  v97.remove(0)  // [array_insert_remove]\n  local v98 = v77\n  v98 += v17  // [modify_string_concat]\n  let v99_a = [v26, v26 + 1]\n  v99_a.append(v26 * 2)\n  let v99 = v99_a.pop()  // [array_push_pop]\n  local v100 = \"\"\n  local v100_i = 0\n  while (v100_i < 1) {\n    v100 = v100 + v52\n    v100_i++\n  }  // [while_string_build]\n  let v101 = v87 ? v100 : v17  // [ternary_str]\n  let v102_fn = function(p0, p1, p2) {\n    let u0 = [v18, v34]  // [array_of_ints]\n    let u1 = v19 < p0  // [string_cmp_lt]\n    let u2_t = clone v46\n    u2_t.clear()\n    let u2 = u2_t.len()  // [table_clear]\n    let u3_fn = function(a, b = \"test\") { return a + b }\n    let u3 = u3_fn(p0)  // [default_param_string]\n    let u4 = v46.map(@(v) v)  // [table_map]\n    const u5 = \"\\n\"  // [const_string]\n    return u5\n  }\n  let v102 = v102_fn(v52, v57, v42)  // [nested_func depth=1]\n  local v103 = 0\n  foreach (c in v48) {\n    if (c >= 'A' && c <= 'Z') v103++\n  }  // [string_scan_upper]\n  let v104_fn = function(p0) {\n    let u0_Base = class {\n      function compute(x) { return x + -129 }\n    }\n    let u0_Der = class(u0_Base) {\n      function compute(x) { return base.compute(x) * 32767 }\n    }\n    let u0 = u0_Der().compute(v16)  // [class_method_override]\n    let u1 = -v75  // [float_neg]\n    let u2_fn = function(q0, q1) {\n      local w0 = \"\"\n      foreach (c in v98) {\n        if (c != ' ') w0 += c.tochar()\n      }  // [string_build_filtered]\n      let w1_f = @(x) x * -4294967296\n      let w1_g = @(x) x + 'A'\n      let w1 = w1_f(w1_g(v68))  // [func_compose]\n      let w2_fn = function(a, b = \"0\") { return a + b }\n      let w2 = w2_fn(v101)  // [default_param_string]\n      let w3_C = class {\n        xv = 0\n        constructor(x) { this.xv = x }\n        function _sub(o) { return this.getclass()(this.xv - o.xv) }\n      }\n      let w3_r = w3_C(v51) - w3_C(v70)\n      let w3 = w3_r.xv  // [meta_sub]\n      let w4_fn = function(r0, r1, r2) {\n        let z0 = v6 && v66  // [bool_and]\n        let z1_Base = class { xv = 0 }\n        let z1_Der = class(z1_Base) { yv = 0 }\n        let z1 = z1_Der.getbase() == z1_Base  // [class_getbase]\n        let z2 = [-2147483648, -4294967297, 0x7FFF]\n        z2.insert(1, v8)\n        z2.remove(0)  // [array_insert_remove]\n        local z3: float = u1  // [typed_float_var]\n        return z3\n      }\n      let w4 = w4_fn(v79, v42, u1)  // [nested_func depth=3]\n      return w4\n    }\n    let u2 = u2_fn(v42, v15)  // [nested_func depth=2]\n    let u3_fn = function(q0, q1) {\n      const w0_BASE = 256\n      const w0_SCALE = -65536\n      let w0 = v24 * w0_SCALE + w0_BASE  // [const_in_expr]\n      let w1 = v80.map(@(v) v)  // [array_map_lambda]\n      let w2 = v80.filter(@(v) v != null)  // [array_filter_lambda]\n      print($\"array.len={w2.len()}\\n\")  // [print_array]\n      local w3_t = {arr = [9223372036854775807, null, {key = v88}]}\n      local w3_inner = w3_t?.arr?[2]\n      if (w3_inner != null) w3_inner.key += 257\n      let w3 = w3_t?.arr?[2]?.key ?? 1  // [nested_table_array_modify]\n      let w4_fn = function() {\n        let z0 = typeof u2 == \"float\"  // [typeof_float_check]\n        let z1 = v17.lstrip()  // [string_lstrip]\n        function [pure] z2_fn(x) { return x * 9223372036854775807 }\n        let z2 = z2_fn(v84)  // [named_func_pure]\n        return z2\n      }\n      let w4 = w4_fn()  // [nested_func depth=3]\n      return w4\n    }\n    let u3 = u3_fn(v89, v37)  // [nested_func depth=2]\n    return u3\n  }\n  let v104 = v104_fn(v34)  // [nested_func depth=1]\n  let v105 = v101.replace(\"\\u0000\", \"\\\"\")  // [string_replace]\n  let v106_inner = function(...) {\n    local s = 0\n    foreach (v in vargv) s += v\n    return s\n  }\n  let v106_outer = function(a, ...) { return a + v106_inner(vargv.len(), a) }\n  let v106 = v106_outer(v15, v32)  // [vargv_forward]\n  let v107_C = class {\n    _val = 0\n    constructor(xv) { this._val = xv }\n    function getVal() { return this._val }\n  }\n  let v107_obj = v107_C(v20)\n  let v107 = v107_obj.getVal()  // [class_basic]\n  let v108_fn = function({da, db = -130}) { return da + db }\n  let v108 = v108_fn({da = v93})  // [destruct_param_table_default]\n  let v109_fn = function(a, b = 3, c = '\\'') { return a + b + c }\n  let v109 = v109_fn(v67)  // [default_param_multi]\n  let v110_fn = function(a, b = 2) { return a + b }\n  let v110 = v110_fn(v44, v45)  // [default_param_call_with]\n  let v111 = (@(a, b) a + b)(v10, v45)  // [immediate_lambda]\n  let v112 = freeze(clone v80)  // [freeze_array]\n  let v113 = v64.escape()  // [string_escape]\n  print($\"int={v110}\\n\")  // [print_int]\n  const v114 = 3  // [const_int]\n  let v115 = type(v106)  // [type_function]\n  let [v116_a, v116_b] = [v18, v15]\n  let [v116_x, v116_y] = [v116_b, v116_a]\n  let v116 = v116_x + v116_y  // [destruct_swap]\n  let v117 = v69 || v66  // [bool_or]\n  let v118_fn = function(p0) {\n    let u0 = v48.startswith(v98)  // [string_startswith]\n    let u1_q = [v111, v2]\n    u1_q.append(0xFFFF)\n    let u1_val = u1_q[0]\n    u1_q.remove(0)\n    let u1 = u1_val  // [array_as_queue]\n    let u2 = $\"val={v75}\"  // [string_interp_float]\n    return u2\n  }\n  let v118 = v118_fn(v37)  // [nested_func depth=1]\n  let v119 = {x = v57, s = v23}  // [table_create]\n  let v120 = {[v115] = v31, [\"y\"] = -2147483648}  // [table_computed_key]\n  let v121_C = class {\n    xv = 0\n    constructor(x) { this.xv = x }\n  }\n  let v121_arr = [v121_C(v70), v121_C(v70 + 1), v121_C(v70 + 2)]\n  let v121 = v121_arr[0].xv + v121_arr[1].xv + v121_arr[2].xv  // [class_array_of]\n  let v122 = v90.hasvalue(v37)  // [array_hasvalue]\n  let v123_fn = function() {\n    local u0 = 0\n    foreach (c in v118) {\n      if (c >= 'A' && c <= 'Z') u0++\n    }  // [string_scan_upper]\n    let u1 = ~v7  // [int_bitnot]\n    let u2_fn = function(q0, q1, q2) {\n      let w0 = {}  // [empty_table]\n      let w1_fn = function(n) {\n        local i = 0\n        while (i < 7) {\n          if (i * n > 0x1) return i\n          i++\n        }\n        return i\n      }\n      let w1 = w1_fn(v107)  // [while_early_return]\n      local w2 = v54 & 7\n      do {\n        w2--\n      } while (w2 > 0)  // [do_while_dec]\n      let w3_t = {[v48] = v4}\n      let w3 = w3_t?[v48] ?? -2147483649  // [table_computed_key_read]\n      let w4_fn = function() {\n        local z0_val = v94\n        let z0_set = function(x) { z0_val = x }\n        let z0_get = function() { return z0_val }\n        z0_set(v94 + 32767)\n        let z0 = z0_get()  // [closure_getter_setter]\n        local z1 = v109\n        z1 -= v45  // [modify_sub_int]\n        let z2 = null  // [null_var]\n        let z3 = [v104, v103]  // [array_of_ints]\n        return z2\n      }\n      let w4 = w4_fn()  // [nested_func depth=3]\n      return w4\n    }\n    let u2 = u2_fn(v49, v29, v25)  // [nested_func depth=2]\n    print($\"float={v75}\\n\")  // [print_float]\n    local u3 = 0\n    local u3_v = v65 & 0xFF\n    while (u3_v != 0) {\n      u3 += u3_v & 1\n      u3_v = u3_v >>> 1\n    }  // [int_bit_count]\n    return u3\n  }\n  let v123 = v123_fn()  // [nested_func depth=1]\n  let v124_t = {arr = [4294967296, null, {key = v10}]}\n  let v124 = v124_t?.arr?[2]?.key ?? -2147483647  // [nested_table_array_nullsafe_read]\n  let v125 = (false ? (((-255) <= 65537) ? true : true) : v87)  // [bool_literal]\n  local v126 = \"\"\n  foreach (c in v115) {\n    if (c != ' ') v126 += c.tochar()\n  }  // [string_build_filtered]\n  let v127_fn = function(p0, p1) {\n    let u0_fn = @[nodiscard] (x) x + 4294967297\n    let u0 = u0_fn(v82)  // [func_nodiscard]\n    let u1 = v3.tolower()  // [string_tolower]\n    let u2_C = class {\n      xv = 0\n      extra = 0\n      constructor(x) { this.xv = x }\n      function _cloned(_other) { this.extra = -4294967295 }\n    }\n    let u2_orig = u2_C(v47)\n    let u2_cpy = clone u2_orig\n    let u2 = u2_cpy.xv + u2_cpy.extra  // [meta_cloned]\n    let u3_fn = function(q0) {\n      local w0 = v76\n      --w0  // [prefix_dec]\n      local w1 = typeof v114\n      switch (w1) {\n        case \"integer\": w1 = \"int\"; break\n        case \"float\": w1 = \"flt\"; break\n        case \"string\": w1 = \"str\"; break\n        default: w1 = \"other\"\n      }  // [typeof_switch]\n      let w2_C = class {\n        v = 0\n        constructor(x) { this.v = x }\n        function get() { return this.v }\n      }\n      local w2_holder = {obj = w2_C(v45), tag = \"\\t\\n\\r\"}\n      let w2 = w2_holder?.obj?.get() ?? 0xFFFF  // [table_with_instance_field]\n      let w3 = (1e-37).tointeger()  // [int_literal]\n      let w4 = v90.len() >= 2\n        ? v90[0] + v90[1]\n        : v90.len() == 1 ? v90[0] : 32767  // [array_two_elems]\n      return w4\n    }\n    let u3 = u3_fn(v79)  // [nested_func depth=2]\n    let u4_fn = function() {\n      let w0 = []\n      v119.each(@(v, _k) w0.append(v))  // [table_each_collect]\n      let w1_fn = @[nodiscard] (x) x + 32769\n      let w1 = w1_fn(v116)  // [func_nodiscard]\n      let w2_fn = function(n) {\n        local i = 0\n        while (i < 3) {\n          if (i * n > -32767) return i\n          i++\n        }\n        return i\n      }\n      let w2 = w2_fn(v54)  // [while_early_return]\n      let w3_fn = @[pure, nodiscard] (a, b) a + b\n      let w3 = w3_fn(v16, v28)  // [func_pure_nodiscard]\n      let w4_fn = function(r0, r1) {\n        let z0 = array(v111 & 7, -9223372036854775807)  // [array_function_init]\n        let z1_a = [v79, v79 + 1]\n        z1_a.append(v79 * 2)\n        let z1 = z1_a.pop()  // [array_push_pop]\n        local z2_db = {users = {alice = {score = 65535, level = 32769},\n                                 bob   = {score = 4294967295, level = -257}}}\n        z2_db.users.alice.score += v94\n        z2_db.users.bob.score   -= v94\n        let z2 = (z2_db?.users?.alice?.score ?? 128)\n                  + (z2_db?.users?.bob?.score ?? -65535)  // [deep_nested_db_modify]\n        let z3 = []\n        local z3_i = 0\n        while (z3_i < -1) {\n          z3.append(z3_i * z3_i)\n          z3_i++\n        }  // [while_array_fill]\n        return z2\n      }\n      let w4 = w4_fn(v32, v96)  // [nested_func depth=3]\n      let w5 = v119?.x ?? -129  // [null_coalesce]\n      return w5\n    }\n    let u4 = u4_fn()  // [nested_func depth=2]\n    let u5 = v120.values()  // [table_values]\n    return u4\n  }\n  let v127 = v127_fn(v28, v108)  // [nested_func depth=1]\n  local v128_mat = [[2147483647, -32768, 1000],\n                   [-127, 0xFFFF, -256]]\n  v128_mat[0][1] += v24\n  v128_mat[1][0] -= v24\n  let v128 = (v128_mat?[0]?[1] ?? 0) + (v128_mat?[1]?[0] ?? -127)  // [matrix_modify_read]\n  let v129_C = class {\n    xv = 0\n    constructor(x) { this.xv = x }\n    function _mul(o) { return this.getclass()(this.xv * o.xv) }\n  }\n  let v129_r = v129_C(v88) * v129_C(v67)\n  let v129 = v129_r.xv  // [meta_mul]\n  let v130 = v14 >>> -1  // [int_ushr]\n  let v131 = v72.len() > 0 ? v72.reduce(@(a, _b) a) : 2  // [array_reduce_lambda]\n  let v132 = clone v60\n  if (v132.len() >= 2) v132.swap(0, v132.len() - 1)  // [array_swap]\n  let v133 = v97.hasvalue(v30)  // [array_hasvalue]\n  let v134 = v64.tolower()  // [string_tolower]\n  let v135_fn = function(p0, p1, p2) {\n    let u0 = v93 != v81  // [int_cmp_ne]\n    let u1 = ((\"\\\"\" + v19)).toupper()  // [string_literal]\n    const function [pure] u2_fn(a, b) { return a + b * -2147483647 }\n    const u2 = u2_fn(32767, 32767)  // [const_pure_call_multi]\n    let u3_fn = function(q0) {\n      let w0 = ((v125 || q0) ? v126 : (\"he said \\\"hi\\\"\").toupper())  // [string_literal]\n      enum S126_E5 { A, B, C }\n      let w1 = S126_E5.A + S126_E5.B + S126_E5.C  // [enum_basic]\n      let w2 = clone v120\n      w2.__update(v119)  // [table_update]\n      local w3_a = v107\n      local w3_b = v5\n      w3_a = w3_a ^ w3_b\n      w3_b = w3_a ^ w3_b\n      w3_a = w3_a ^ w3_b\n      let w3 = w3_a  // [int_swap_via_xor]\n      let w4_fn = function(r0, r1, r2) {\n        local z0_maybe = v25 > -32770 ? v25 : null\n        let z0 = z0_maybe ?? 4294967295  // [null_assign_fallback]\n        let z1 = (w2.findindex(@(_v) true) ?? \"\\u0000\").tostring()  // [table_findindex]\n        let z2 = u2.tofloat() + v75  // [int_float_arith]\n        let z3_C = class {\n          xv = 0\n          constructor(x) { this.xv = x }\n          function _add(o) { return this.getclass()(this.xv + o.xv) }\n        }\n        let z3_r = z3_C(v73) + z3_C(v93)\n        let z3 = z3_r.xv  // [meta_add]\n        return z3\n      }\n      let w4 = w4_fn(v53, v96, v36)  // [nested_func depth=3]\n      return w4\n    }\n    let u3 = u3_fn(v125)  // [nested_func depth=2]\n    let u4 = ((v67 >>> 1)).tostring()  // [string_literal]\n    let u5 = \"{0}+{1}\".subst(v59, \"[]{}()\")  // [string_subst]\n    local u6_store = {pages = [{lines = [4294967295, 0xFFFFFFFF]}, {lines = [65535, 2147483647]}]}\n    u6_store.pages[0].lines[1] += u2\n    let u6 = u6_store?.pages?[0]?.lines?[1] ?? -32768  // [nested_db_array_field]\n    return u6\n  }\n  let v135 = v135_fn(v62, v91, v16)  // [nested_func depth=1]\n  local v136 = 0\n  foreach (v in v90) {\n    if (typeof v == \"integer\") v136 = v136 + v\n  }  // [foreach_array_sum]\n  let v137 = -v75  // [float_neg]\n  const v138 = -1e+37  // [const_float]\n  let v139 = v119.__merge(v120)  // [table_merge]\n  local v140 = \"\"\n  foreach (c in v105) {\n    if (c != ' ') v140 += c.tochar()\n  }  // [string_build_filtered]\n  let v141_fn = function(x) {\n    local cached = static({v = -2147483647 * 4294967296})\n    return x + cached.v\n  }\n  let v141 = v141_fn(v114)  // [static_complex]\n  let v142 = v97.totable()  // [array_totable]\n  let v143_fn = function(x, s, cfg = {\n      fmt = @(n, t) $\"{n}:{t}\",\n      limits = {lo = -1, hi = -32770}\n    }) {\n    local clamped = x < cfg.limits.lo ? cfg.limits.lo\n                  : x > cfg.limits.hi ? cfg.limits.hi : x\n    return cfg.fmt(clamped, s)\n  }\n  let v143 = v143_fn(v85, v118)  // [default_param_config_nested]\n  let v144_fn = function(p0) {\n    let u0 = v97.totable()  // [array_totable]\n    local u1 = -9223372036854775807\n    switch (v77) {\n      case \"a\": u1 = -4; break\n      case \"b\": u1 = 257; break\n      case \"c\": u1 = -2147483648; break\n      default: u1 = 0\n    }  // [switch_string]\n    let u2 = (function() {\n      let gen = (function() {\n        yield -257\n        yield -257\n        yield -4\n      })()\n      let arr = []\n      while (gen.getstatus() == \"suspended\") {\n        arr.append(resume gen)\n      }\n      return arr\n    })()  // [coroutine_collect_all]\n    return u1\n  }\n  let v144 = v144_fn(v17)  // [nested_func depth=1]\n  let v145 = $\"{v19}{v59}\"  // [string_concat]\n  let v146 = v120.keys()  // [table_keys]\n  let v147 = v119.rawget(\"x\") ?? -32770  // [rawget_table]\n  local v148 = v138\n  v148 *= v75  // [modify_mul_float]\n  let v149_stack = []\n  v149_stack.append(v58)\n  v149_stack.append(v54)\n  let v149 = v149_stack.pop()  // [table_as_stack]\n  let v150_t = {arr = [0x8000, null, {key = v76}]}\n  let v150 = v150_t?.arr?[2]?.key ?? 65535  // [nested_table_array_nullsafe_read]\n  let v151 = v72.hasindex(0)  // [array_hasindex]\n  let v152 = v46.topairs()  // [table_topairs]\n  let v153 = v117 && v11  // [bool_and]\n  let v154_fn = @(a: int, b: int) a * b\n  let v154 = v154_fn(v2, v67)  // [typed_lambda]\n  let v155 = v97.totable()  // [array_totable]\n  let v156 = v5 >= v99  // [int_cmp_ge]\n  let v157_fn = function(x) {\n    local cached = static({v = -4294967296 * 2147483648})\n    return x + cached.v\n  }\n  let v157 = v157_fn(v9)  // [static_complex]\n  enum S126_E6 { LOW = 0, MID = 1, HIGH = 2 }\n  let v158 = (v79 & 3) == S126_E6.MID  // [enum_compare]\n  let v159 = {}  // [empty_table]\n  let v160 = freeze(clone v72)  // [freeze_array]\n  let v161 = v155.map(@(v) v)  // [table_map]\n  let v162 = v115.toupper()  // [string_toupper]\n  let v163_fn = function(a, b = \"true\") { return a + b }\n  let v163 = v163_fn(v145)  // [default_param_string]\n  local v164 = -127\n  if (let v164_v = v31; v164_v > 0xFFFF) {\n    v164 = v164_v * -255\n  }  // [if_let_positive]\n  let v165_fn = function() {\n    let u0 = v161.filter(@(v) v != null)  // [table_filter]\n    let u1 = u0.len() > 0  // [table_getdelegate]\n    let u2_fn = function(q0, q1, q2) {\n      local w0 = 0\n      for (local w0_i = 0; w0_i < 1; w0_i++) {\n        for (local w0_j = 0; w0_j < -4; w0_j++) {\n          w0 += w0_i * w0_j\n        }\n      }  // [nested_loops]\n      const function [pure] w1_fn(a, b) { return a + b * 2147483648 }\n      const w1 = w1_fn(-4294967298, 42)  // [const_pure_call_multi]\n      let w2 = v34\n      assert(w2 == w2)  // [assert_tautology]\n      local w3 = v128\n      w3 /= v38  // [modify_div_int_unsafe]\n      let w4_t = {a = {b = {c = v45}}}\n      let w4 = w4_t?.a?.b?.c ?? 0x8000  // [table_deep]\n      return w4\n    }\n    let u2 = u2_fn(v117, v78, v89)  // [nested_func depth=2]\n    return u2\n  }\n  let v165 = v165_fn()  // [nested_func depth=1]\n  let v166 = v28 > 0 ? 1 : (v28 < 0 ? -1 : 0)  // [int_sign]\n  let v167 = typeof v119 == \"table\"  // [typeof_table_check]\n  let v168_fn = function(p0, p1, p2) {\n    local u0 = 0\n    local u0_i = 0\n    while (u0_i < 100) {\n      if (u0_i >= 5) break\n      u0 = u0 + v37\n      u0_i++\n    }  // [while_break]\n    let u1_prev = v161?.x ?? 2147483649\n    v161.x <- v53\n    let u1 = u1_prev + v161.x  // [table_modify_field]\n    let u2 = v106 == v83  // [int_cmp_eq]\n    return u2\n  }\n  let v168 = v168_fn(v42, v87, v106)  // [nested_func depth=1]\n  let v169 = freeze(clone v112)  // [freeze_array]\n  let v170 = v142.map(@(v) v)  // [table_map]\n  let v171 = v170.len() > 0 ? v170.reduce(@(a, _v) a) : 129  // [table_reduce]\n  let v172_A = class { v = 0; constructor(x) { this.v = x }; function get() { return this.v } }\n  let v172_B = class(v172_A) { bonus = 0; constructor(x) { base.constructor(x); this.bonus = -4294967297 } }\n  let v172_C = class(v172_B) { extra = 0; constructor(x) { base.constructor(x); this.extra = -3 } }\n  let v172_obj = v172_C(v121)\n  let v172 = v172_obj.get() + v172_obj.bonus + v172_obj.extra  // [class_three_level]\n  local v173 = 0\n  v46.each(@(_v, _k) v173++)  // [table_each]\n  let v174 = []\n  for (local v174_i = 0; v174_i < -4; v174_i++) {\n    v174.append(v174_i)\n  }  // [for_build_array]\n  let v175 = v21 - v9  // [int_sub]\n  let v176 = v90.len() >= 2 ? v90.slice(1) : clone v90  // [array_slice_mid]\n  let v177 = [v77, v23, @\"raw_string\"]  // [array_of_strings]\n  let v178_fn = function(p0, p1) {\n    let u0 = v0 != 0 ? v135 / v0 : 42  // [int_div_safe]\n    let u1 = $\"flag={v133}\"  // [string_interp_bool]\n    local u2_items = [{k = \"world\", v = -2},\n                       {k = \"\", v = 2147483648},\n                       {k = \"1e10\", v = v14}]\n    foreach (item in u2_items)\n      if (item.v > -258) item.v *= -128\n    local u2 = 0\n    foreach (item in u2_items) u2 += item.v  // [foreach_array_tables_modify]\n    return u2\n  }\n  let v178 = v178_fn(v77, v95)  // [nested_func depth=1]\n  let v179 = (@(x) x + 4294967296)(v1)  // [lambda_inc]\n  let v180 = v59.tolower()  // [string_tolower]\n  let v181_C = class {\n    _a = 0\n    _b = 0\n    constructor(xa, xb) { this._a = xa; this._b = xb }\n    function sum() { return this._a + this._b }\n    function diff() { return this._a - this._b }\n  }\n  let v181_obj = v181_C(v141, v22)\n  let v181 = v181_obj.sum() + v181_obj.diff()  // [class_method_call]\n  local v182 = 1\n  local v182_i = 0\n  while (v182_i < 5) {\n    v182 = v182 * ((v54 % 4) + 1)\n    v182_i++\n  }  // [while_mul]\n  local v183 = 0\n  foreach (v in v132) {\n    if (typeof v == \"integer\") v183 = v183 + v\n  }  // [foreach_array_sum]\n  let v184_fn = function(p0, p1) {\n    local u0_mat = [[-3, -128, -1],\n                     [42, 1000, '\\t']]\n    u0_mat[0][1] += v131\n    u0_mat[1][0] -= v131\n    let u0 = (u0_mat?[0]?[1] ?? 32767) + (u0_mat?[1]?[0] ?? -65535)  // [matrix_modify_read]\n    let u1 = v102.len() > 2 ? v102.slice(-2) : v102  // [string_slice_neg]\n    local u2 = -258\n    if (local u2_v = v53 & 0xFF; u2_v > 0x80000000) {\n      u2_v = u2_v - -129\n      u2 = u2_v\n    }  // [if_local_modify]\n    let u3 = v91.tostring()  // [bool_to_string]\n    let u4 = v85 != v12  // [int_cmp_ne]\n    return u4\n  }\n  let v184 = v184_fn(v85, v63)  // [nested_func depth=1]\n  let v185 = typeof v162 == \"string\"  // [typeof_string_check]\n  let v186_C = class {\n    xv = 0\n    constructor(x) { this.xv = x }\n    function _sub(o) { return this.getclass()(this.xv - o.xv) }\n  }\n  let v186_r = v186_C(v41) - v186_C(v4)\n  let v186 = v186_r.xv  // [meta_sub]\n  local v187 = v79\n  v187 += v57  // [modify_add_int]\n  let v188 = [v183, v150]  // [array_of_ints]\n  local v189 = 1\n  local v189_i = 0\n  while (v189_i < 1) {\n    v189 = v189 * ((v13 % 4) + 1)\n    v189_i++\n  }  // [while_mul]\n  local v190 = 0\n  foreach (_k, _v in v142) {\n    v190++\n  }  // [foreach_table_keys]\n  let v191 = v5 - v71  // [int_sub]\n  let v192 = type(v53)  // [type_function]\n  let v193_t = {[v180] = v28}\n  let v193 = v193_t?[v180] ?? 2147483648  // [table_computed_key_read]\n  let v194_fn = function(...) {\n    return vargv.len() > 0 ? vargv[0] : -2147483648\n  }\n  let v194 = v194_fn(v121)  // [vargv_first]\n  local v195 = v75\n  v195 += v148  // [modify_add_float]\n  local v196 = -65535\n  if (let v196_v = v96; v196_v > 257) {\n    v196 = v196_v * 2\n  }  // [if_let_positive]\n  let v197_fn = function(p0) {\n    let u0 = v27 >= 0 ? v27 : -v27  // [int_abs_ternary]\n    local u1 = 0\n    local u1_i = 0\n    do {\n      u1 += v193\n      u1_i++\n    } while (u1_i < 3)  // [do_while_count]\n    let u2 = v152.len() > 0\n      ? v152.reduce(@(acc, v) (typeof v == \"integer\" ? acc + v : acc), 0)\n      : -130  // [array_reduce_sum]\n    print($\"int={v136}\\n\")  // [print_int]\n    return u2\n  }\n  let v197 = v197_fn(v52)  // [nested_func depth=1]\n  const v198_BASE = 0x100\n  const v198_SCALE = 2\n  let v198 = v21 * v198_SCALE + v198_BASE  // [const_in_expr]\n  let v199 = typeof v89  // [typeof_expr]\n  let v200_fn = function(p0, p1) {\n    local u0 = 0\n    foreach (c in v163) {\n      if (c >= '0' && c <= '9') u0++\n    }  // [string_scan_digits]\n    v46.x <- v171\n    let u1 = v46.x  // [table_set_field]\n    let u2_fn = function(q0, q1) {\n      let w0 = v169.hasvalue(v82)  // [array_hasvalue]\n      let w1_fn = function(a, b = \";\") { return a + b }\n      let w1 = w1_fn(v23)  // [default_param_string]\n      global enum S126_E7 { LO = -4294967298, HI = 3 }\n      let w2 = v89 + S126_E7.LO + S126_E7.HI  // [enum_in_expr]\n      local w3 = v96\n      w3 /= v7  // [modify_div_int_unsafe]\n      local w4 = 0\n      local w4_i = 0\n      while (w4_i < 1) {\n        w4 = w4 + v38\n        w4_i++\n      }  // [while_sum]\n      return w4\n    }\n    let u2 = u2_fn(v7, v122)  // [nested_func depth=2]\n    let u3_fn = @(a, b = -2147483648, c = -65535) a * b + c\n    let u3 = u3_fn(u1)  // [default_param_lambda]\n    return u3\n  }\n  let v200 = v200_fn(v190, v8)  // [nested_func depth=1]\n  local v201 = v24\n  --v201  // [prefix_dec]\n  let v202_C = class {\n    _n = 0\n    constructor(n) { this._n = n & 7 }\n    function _nexti(idx) {\n      local next = idx == null ? 0 : idx + 1\n      return next < this._n ? next : null\n    }\n    function _get(idx) { return idx * -65536 }\n  }\n  let v202_obj = v202_C(v147)\n  local v202 = 0\n  foreach (_i, v in v202_obj) v202 += v  // [meta_nexti]\n  let v203_Base = class { xv = 0; constructor(x) { this.xv = x } }\n  let v203_Der = class(v203_Base) { constructor(x) { base.constructor(x) } }\n  let v203_obj = v203_Der(v182)\n  let v203 = v203_obj instanceof v203_Base  // [class_instanceof_base]\n\n  // --- dump pool ---\n  function _prn_t(_t) { let _a = []; _t.each(function(_k, _v) { _a.append(_sv(_k)); _a.append(_sv(_v)) }); _a.sort(); foreach (i, _v in _a) { if (i >= 10) { print(\"...\"); break }; if (i > 0) print(\", \"); print(_v) }; }\n  function _prn_a(_a) { foreach (i, _v in _a) { if (i >= 10) { print(\"...\"); break }; if (i > 0) print(\", \"); print(_v) }; }\n  print($\"v0={v0}\\n\")\n  print($\"v1={v1}\\n\")\n  print($\"v2={v2}\\n\")\n  print($\"v3={v3}\\n\")\n  print($\"v4={v4}\\n\")\n  print($\"v5={v5}\\n\")\n  print($\"v6={v6}\\n\")\n  print($\"v7={v7}\\n\")\n  print($\"v8={v8}\\n\")\n  print($\"v9={v9}\\n\")\n  print($\"v10={v10}\\n\")\n  print($\"v11={v11}\\n\")\n  print($\"v12={v12}\\n\")\n  print($\"v13={v13}\\n\")\n  print($\"v14={v14}\\n\")\n  print($\"v15={v15}\\n\")\n  print($\"v16={v16}\\n\")\n  print($\"v17={v17}\\n\")\n  print($\"v18={v18}\\n\")\n  print($\"v19={v19}\\n\")\n  print($\"v20={v20}\\n\")\n  print($\"v21={v21}\\n\")\n  print($\"v22={v22}\\n\")\n  print($\"v23={v23}\\n\")\n  print($\"v24={v24}\\n\")\n  print($\"v25={v25}\\n\")\n  print($\"v26={v26}\\n\")\n  print($\"v27={v27}\\n\")\n  print($\"v28={v28}\\n\")\n  print($\"v29={v29}\\n\")\n  print($\"v30={v30}\\n\")\n  print($\"v31={v31}\\n\")\n  print($\"v32={v32}\\n\")\n  print($\"v33={v33}\\n\")\n  print($\"v34={v34}\\n\")\n  print($\"v35={v35}\\n\")\n  print($\"v36={v36}\\n\")\n  print($\"v37={v37}\\n\")\n  print($\"v38={v38}\\n\")\n  print($\"v39={v39}\\n\")\n  print($\"v40={v40}\\n\")\n  print($\"v41={v41}\\n\")\n  print($\"v42={v42}\\n\")\n  print($\"v43={v43}\\n\")\n  print($\"v44={v44}\\n\")\n  print($\"v45={v45}\\n\")\n  print(\"v46={\"); _prn_t(v46); print(\"}\\n\")\n  print($\"v47={v47}\\n\")\n  print($\"v48={v48}\\n\")\n  print($\"v49={v49}\\n\")\n  print($\"v50={v50}\\n\")\n  print($\"v51={v51}\\n\")\n  print($\"v52={v52}\\n\")\n  print($\"v53={v53}\\n\")\n  print($\"v54={v54}\\n\")\n  print($\"v55={v55}\\n\")\n  print($\"v56={v56}\\n\")\n  print($\"v57={v57}\\n\")\n  print($\"v58={v58}\\n\")\n  print($\"v59={v59}\\n\")\n  print(\"v60=[\"); _prn_a(v60); print(\"]\\n\")\n  print($\"v61={v61}\\n\")\n  print($\"v62={v62}\\n\")\n  print($\"v63={v63}\\n\")\n  print($\"v64={v64}\\n\")\n  print($\"v65={v65}\\n\")\n  print($\"v66={v66}\\n\")\n  print($\"v67={v67}\\n\")\n  print($\"v68={v68}\\n\")\n  print($\"v69={v69}\\n\")\n  print($\"v70={v70}\\n\")\n  print($\"v71={v71}\\n\")\n  print(\"v72=[\"); _prn_a(v72); print(\"]\\n\")\n  print($\"v73={v73}\\n\")\n  print($\"v74={v74}\\n\")\n  print($\"v75={v75}\\n\")\n  print($\"v76={v76}\\n\")\n  print($\"v77={v77}\\n\")\n  print($\"v78={v78}\\n\")\n  print($\"v79={v79}\\n\")\n  print(\"v80=[\"); _prn_a(v80); print(\"]\\n\")\n  print($\"v81={v81}\\n\")\n  print($\"v82={v82}\\n\")\n  print($\"v83={v83}\\n\")\n  print($\"v84={v84}\\n\")\n  print($\"v85={v85}\\n\")\n  print($\"v86={v86}\\n\")\n  print($\"v87={v87}\\n\")\n  print($\"v88={v88}\\n\")\n  print($\"v89={v89}\\n\")\n  print(\"v90=[\"); _prn_a(v90); print(\"]\\n\")\n  print($\"v91={v91}\\n\")\n  print($\"v92={v92}\\n\")\n  print($\"v93={v93}\\n\")\n  print($\"v94={v94}\\n\")\n  print($\"v95={v95}\\n\")\n  print($\"v96={v96}\\n\")\n  print(\"v97=[\"); _prn_a(v97); print(\"]\\n\")\n  print($\"v98={v98}\\n\")\n  print($\"v99={v99}\\n\")\n  print($\"v100={v100}\\n\")\n  print($\"v101={v101}\\n\")\n  print($\"v102={v102}\\n\")\n  print($\"v103={v103}\\n\")\n  print($\"v104={v104}\\n\")\n  print($\"v105={v105}\\n\")\n  print($\"v106={v106}\\n\")\n  print($\"v107={v107}\\n\")\n  print($\"v108={v108}\\n\")\n  print($\"v109={v109}\\n\")\n  print($\"v110={v110}\\n\")\n  print($\"v111={v111}\\n\")\n  print(\"v112=[\"); _prn_a(v112); print(\"]\\n\")\n  print($\"v113={v113}\\n\")\n  print($\"v114={v114}\\n\")\n  print($\"v115={v115}\\n\")\n  print($\"v116={v116}\\n\")\n  print($\"v117={v117}\\n\")\n  print($\"v118={v118}\\n\")\n  print(\"v119={\"); _prn_t(v119); print(\"}\\n\")\n  print(\"v120={\"); _prn_t(v120); print(\"}\\n\")\n  print($\"v121={v121}\\n\")\n  print($\"v122={v122}\\n\")\n  print($\"v123={v123}\\n\")\n  print($\"v124={v124}\\n\")\n  print($\"v125={v125}\\n\")\n  print($\"v126={v126}\\n\")\n  print($\"v127={v127}\\n\")\n  print($\"v128={v128}\\n\")\n  print($\"v129={v129}\\n\")\n  print($\"v130={v130}\\n\")\n  print($\"v131={v131}\\n\")\n  print(\"v132=[\"); _prn_a(v132); print(\"]\\n\")\n  print($\"v133={v133}\\n\")\n  print($\"v134={v134}\\n\")\n  print($\"v135={v135}\\n\")\n  print($\"v136={v136}\\n\")\n  print($\"v137={v137}\\n\")\n  print($\"v138={v138}\\n\")\n  print(\"v139={\"); _prn_t(v139); print(\"}\\n\")\n  print($\"v140={v140}\\n\")\n  print($\"v141={v141}\\n\")\n  print(\"v142={\"); _prn_t(v142); print(\"}\\n\")\n  print($\"v143={v143}\\n\")\n  print($\"v144={v144}\\n\")\n  print($\"v145={v145}\\n\")\n  print(\"v146=[\"); _prn_a(v146); print(\"]\\n\")\n  print($\"v147={v147}\\n\")\n  print($\"v148={v148}\\n\")\n  print($\"v149={v149}\\n\")\n  print($\"v150={v150}\\n\")\n  print($\"v151={v151}\\n\")\n  print(\"v152=[\"); _prn_a(v152); print(\"]\\n\")\n  print($\"v153={v153}\\n\")\n  print($\"v154={v154}\\n\")\n  print(\"v155={\"); _prn_t(v155); print(\"}\\n\")\n  print($\"v156={v156}\\n\")\n  print($\"v157={v157}\\n\")\n  print($\"v158={v158}\\n\")\n  print(\"v159={\"); _prn_t(v159); print(\"}\\n\")\n  print(\"v160=[\"); _prn_a(v160); print(\"]\\n\")\n  print(\"v161={\"); _prn_t(v161); print(\"}\\n\")\n  print($\"v162={v162}\\n\")\n  print($\"v163={v163}\\n\")\n  print($\"v164={v164}\\n\")\n  print($\"v165={v165}\\n\")\n  print($\"v166={v166}\\n\")\n  print($\"v167={v167}\\n\")\n  print($\"v168={v168}\\n\")\n  print(\"v169=[\"); _prn_a(v169); print(\"]\\n\")\n  print(\"v170={\"); _prn_t(v170); print(\"}\\n\")\n  print($\"v171={v171}\\n\")\n  print($\"v172={v172}\\n\")\n  print($\"v173={v173}\\n\")\n  print(\"v174=[\"); _prn_a(v174); print(\"]\\n\")\n  print($\"v175={v175}\\n\")\n  print(\"v176=[\"); _prn_a(v176); print(\"]\\n\")\n  print(\"v177=[\"); _prn_a(v177); print(\"]\\n\")\n  print($\"v178={v178}\\n\")\n  print($\"v179={v179}\\n\")\n  print($\"v180={v180}\\n\")\n  print($\"v181={v181}\\n\")\n  print($\"v182={v182}\\n\")\n  print($\"v183={v183}\\n\")\n  print($\"v184={v184}\\n\")\n  print($\"v185={v185}\\n\")\n  print($\"v186={v186}\\n\")\n  print($\"v187={v187}\\n\")\n  print(\"v188=[\"); _prn_a(v188); print(\"]\\n\")\n  print($\"v189={v189}\\n\")\n  print($\"v190={v190}\\n\")\n  print($\"v191={v191}\\n\")\n  print($\"v192={v192}\\n\")\n  print($\"v193={v193}\\n\")\n  print($\"v194={v194}\\n\")\n  print($\"v195={v195}\\n\")\n  print($\"v196={v196}\\n\")\n  print($\"v197={v197}\\n\")\n  print($\"v198={v198}\\n\")\n  print($\"v199={v199}\\n\")\n  print($\"v200={v200}\\n\")\n  print($\"v201={v201}\\n\")\n  print($\"v202={v202}\\n\")\n  print($\"v203={v203}\\n\")\n} catch(e) { print(e) }\nprint(\"===\\n\")\n"
  },
  {
    "path": "testData/diagnostics/type_hints_01.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [parameter 1 of 'fn' has an invalid type 'float' ; expected: 'null|integer']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/type_hints_01.nut:5\n\nLOCALS\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/type_hints_01.nut",
    "content": "function fn(x: int|null) {\n  return x\n}\n\nfn(5.4)\n"
  },
  {
    "path": "testData/diagnostics/type_hints_02.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [parameter 2 of 'fn' has an invalid type 'float' ; expected: 'null|integer']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/type_hints_02.nut:5\n\nLOCALS\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/type_hints_02.nut",
    "content": "function fn(y, x: int|null) {\n  return x\n}\n\nfn(\"abc\", 5.4)\n"
  },
  {
    "path": "testData/diagnostics/type_hints_03.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [parameter 2 of 'fn' has an invalid type 'float' ; expected: 'null|integer']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/type_hints_03.nut:5\n\nLOCALS\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/type_hints_03.nut",
    "content": "function fn(y: null|string, x: int|null, z: null|table) {\n  return x\n}\n\nfn(null, 5.4, null)\n"
  },
  {
    "path": "testData/diagnostics/type_hints_04.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [parameter 1 of 'fn' has an invalid type 'string' ; expected: 'integer']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/type_hints_04.nut:5\n\nLOCALS\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/type_hints_04.nut",
    "content": "function fn(x: int, ...) {\n  return x\n}\n\nfn(\"abc\", \"\")\n"
  },
  {
    "path": "testData/diagnostics/type_hints_05.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [parameter 5 of 'fn' has an invalid type 'function' ; expected: 'table']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/type_hints_05.nut:5\n\nLOCALS\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/type_hints_05.nut",
    "content": "function fn(x: int, ...: table) {\n  return x\n}\n\nfn(4, {}, {}, {}, @() null)\n"
  },
  {
    "path": "testData/diagnostics/type_hints_06.diag.txt",
    "content": "\nAN ERROR HAS OCCURRED [parameter 2 of 'fn' has an invalid type 'null' ; expected: 'array']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/diagnostics/type_hints_06.nut:5\n\nLOCALS\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/diagnostics/type_hints_06.nut",
    "content": "function fn(x: int, ...: array) {\n  return x\n}\n\nfn(4, null, [], [], [])\n"
  },
  {
    "path": "testData/diagnostics/unfinished_hex.diag.txt",
    "content": "ERROR: expected hex digits after '0x'\ntestData/diagnostics/unfinished_hex.nut:1:8\n\nprintln(0x)\n        ^-\n\n\n"
  },
  {
    "path": "testData/diagnostics/unfinished_hex.nut",
    "content": "println(0x)\n"
  },
  {
    "path": "testData/diagnostics/var_scope_1.diag.txt",
    "content": "ERROR: Unknown variable [x]\ntestData/diagnostics/var_scope_1.nut:4:6\n\nprint(x)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/var_scope_1.nut",
    "content": "if (true)\n  local x = 5\n\nprint(x)\n"
  },
  {
    "path": "testData/diagnostics/var_scope_2.diag.txt",
    "content": "ERROR: Unknown variable [x]\ntestData/diagnostics/var_scope_2.nut:5:6\n\nprint(x)\n      ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/var_scope_2.nut",
    "content": "local function f() {\n  local x = 6\n}\n\nprint(x)\n"
  },
  {
    "path": "testData/diagnostics/var_scope_3.diag.txt",
    "content": "ERROR: Unknown variable [x]\ntestData/diagnostics/var_scope_3.nut:4:8\n\nelse\n  print(x)\n        ^\n\n\n"
  },
  {
    "path": "testData/diagnostics/var_scope_3.nut",
    "content": "if (true)\n  local x = 6\nelse\n  print(x)\n"
  },
  {
    "path": "testData/exec/array_methods.nut",
    "content": "let a = [1,2,3]\nlet Exception = class{\n  e = null\n  constructor(e){\n    this.e=e\n  }\n}\nfunction test(func, expected_res, name = null){\n  let name_s = name ? $\"'{name}': \" : \"\"\n  try{\n    let res = func()\n    assert(expected_res==res, @() $\"{name_s}Expected {expected_res}, got {res}\")\n    println(res)\n  }\n  catch(e){\n    assert(expected_res instanceof Exception, $\"{name_s} expected result '{expected_res}', got Exception('{e}')}\")\n    assert(expected_res.e == null || expected_res.e==e, $\"{name_s}expected Exception value = '{expected_res.e}', got '{e}'\")\n  }\n}\ntry{\n  test(@() a.contains(1), true, \"a.contains(1)\")\n  test(@() a.hasindex(0), true, \"a.hasindex(0)\")\n  test(@() a.hasindex(5), false)\n  test(@() a.hasindex(-1), false)\n  test(@() a.hasindex(a.len()-1), true, \"a.hasindex(a.len()-1)\")\n  test(@() a.hasvalue(5), false, \"a.hasvalue(5)\")\n  test(@() a.hasvalue(3), true)\n  test(@() a.pop(), 3)\n  test(@() a.insert(0,0)[1], 1)\n  test(@() a.remove(0), 0)\n  test(@() a.extend([5,6]).len(), 4)\n  test(@() a.resize(7, -1).top(), -1)\n  test(@() a.reverse().top(), 1)\n  test(@() a.sort().top(), 6, \"a.sort().top()\")\n  test(@() a.slice(0,3)[2], -1)\n  test(@() a.clear().len(), 0)\n  test(@() a.append(0, 1, 2).indexof(1), 1)\n  test(@() a.findindex(@(v) v==-1), null)\n  test(@() a.findindex(@(v) v%2!=0), 1)\n  test(@() a.findvalue(@(v) v==1), 1)\n  test(@() a.totable()[0], 0)\n  test(@() a.replace_with([-1,-2,-3]).top(), -3)\n  test(@() type(a.tostring())==\"string\", true)\n  test(@() a.swap(0,2)[0], -3)\n  test(@() [0,1].totable().swap(0,1)[0], 1)\n  print(\"ok\")\n}\ncatch(e){\n  println(e)\n}\n\n"
  },
  {
    "path": "testData/exec/array_methods.out",
    "content": "true\ntrue\nfalse\nfalse\ntrue\nfalse\ntrue\n3\n1\n0\n4\n-1\n1\n6\n-1\n0\n1\nnull\n1\n1\n0\n-3\ntrue\n-3\n1\nok"
  },
  {
    "path": "testData/exec/basics.nut",
    "content": "//tests for local bindings, local variables and const\nconst A = 2\nlet a = 1\nlocal b = 3\nb = 10\nlet b_0 = b\nb += a\nb -= 1\nb++\nb--\nb = b + A\nb = b - A\n\nb *= 2\nb /= 2\nb = b * 2\nb = b / 2\nb = (b + 1) * 2\nb = b / 2 -1\n\nassert(b == b_0)\n"
  },
  {
    "path": "testData/exec/basics.out",
    "content": ""
  },
  {
    "path": "testData/exec/call_constructor_recursion.nut",
    "content": "// Demonstrates SQVM::Call self-recursion via class constructor (1.5)\n//\n// When a class is called to create an instance, Call() does two things:\n//   1. CreateClassInstance() - allocates the instance\n//   2. Call(constructor, ...) - calls the constructor on the new instance\n//\n// sqvm.cpp:2436-2448 (case OT_CLASS):\n//   Call(class)                       // entry: closure type is OT_CLASS\n//     -> CreateClassInstance(class)   // line 2440 - allocates instance\n//     -> Call(constructor, ...)       // line 2445 - re-enters Call() with OT_CLOSURE\n//       -> Execute() runs constructor body\n//\n// If the constructor body creates another instance of the same class,\n// Execute() emits _OP_CALL with the class object, which calls Call(class)\n// again. Each level adds TWO native Call() frames (class + constructor):\n//\n//   Call(MyClass)          -- OT_CLASS dispatch, CreateClassInstance\n//     Call(constructor)    -- OT_CLOSURE dispatch -> Execute\n//       Call(MyClass)      -- from `this.getclass()()` in constructor body\n//         Call(constructor)\n//           Call(MyClass)\n//             ...\n//\n// No depth limit exists in Call() itself.\n//\n// RESULT: Unlike _tostring/_get metamethod recursion (which the VM catches\n// at ~99 deep with \"Native stack overflow\"), this path causes a HARD CRASH\n// of the process. The Call(OT_CLASS) branch does extra work per level\n// (CreateClassInstance + stack manipulation) consuming more native stack\n// per recursion step, so the process segfaults before the VM's stack\n// overflow probe (in Execute) gets a chance to fire.\n\n// ---- Controlled version: shows the recursion pattern safely ----\n\nlocal depth = 0\nlocal MAX = 10\n\nclass MyClass {\n  child = null\n  constructor() {\n    depth++\n    if (depth <= 5)\n      println($\"  Call(MyClass) -> Call(ctor) depth={depth}\")\n    // this.getclass() returns the OT_CLASS object\n    // calling it triggers Call(class) -> CreateClassInstance -> Call(ctor)\n    if (depth < MAX)\n      this.child = this.getclass()()\n  }\n}\n\nprintln($\"=== Controlled run (max {MAX}) ===\")\ndepth = 0\ntry {\n  local obj = MyClass()\n  println($\"Completed: depth reached {depth}\")\n} catch(e) {\n  println($\"Caught after depth={depth}: {e}\")\n}\n\n// ---- Unguarded version ----\n\nclass B {\n  child = null\n  constructor() {\n    this.child = this.getclass()()\n  }\n}\ntry {\n  local b = B()\n} catch(e) {\n  println($\"Caught: {e}\")  // never reached - process is dead\n}\n"
  },
  {
    "path": "testData/exec/call_constructor_recursion.out",
    "content": "=== Controlled run (max 10) ===\n  Call(MyClass) -> Call(ctor) depth=1\n  Call(MyClass) -> Call(ctor) depth=2\n  Call(MyClass) -> Call(ctor) depth=3\n  Call(MyClass) -> Call(ctor) depth=4\n  Call(MyClass) -> Call(ctor) depth=5\nCompleted: depth reached 10\nCaught: stack overflow, cannot resize stack\n"
  },
  {
    "path": "testData/exec/class_yield.nut",
    "content": "class A {\n    constructor() {\n        this.call_yield()\n    }\n\n    function call_yield() {\n        this.do_yield.call(0)\n    }\n\n    function do_yield() {\n        yield\n    }\n}\n\nA()\nprintln(\"OK\")"
  },
  {
    "path": "testData/exec/class_yield.out",
    "content": "OK\n"
  },
  {
    "path": "testData/exec/closure_hoist_typed_default.nut",
    "content": "// Closure hoisting must not move closures with non-literal typed default\n// parameters out of try-catch blocks when the default value type is unknown\n// at compile time. The _OP_CLOSURE instruction checks default value types\n// at runtime and can throw.\n\n// Non-literal default with type mismatch inside try-catch in a nested function.\n// The closure must not be hoisted because getExprLiteralTypeMask returns ~0u.\nlet wrongVal = vargv.len() < 10000 ? \"wrong\" : vargv[0] // must have unknown type during compilation\nlet test1 = function() {\n  local result = 0\n  try {\n    let fn = function(x: int = wrongVal) { return x }\n  } catch(e) {\n    result = 1\n  }\n  return result\n}\nassert(test1() == 1)\n\n// Valid typed literal defaults should still allow hoisting and work normally\nlet test2 = function() {\n  let fn = function(x: int = 42) { return x }\n  return fn()\n}\nassert(test2() == 42)\n\nprintln(\"OK\")"
  },
  {
    "path": "testData/exec/closure_hoist_typed_default.out",
    "content": "OK\n"
  },
  {
    "path": "testData/exec/closure_hoist_typed_return.nut",
    "content": "// Verify that scope-aware type deduction for closure hoisting produces\n// correct runtime behavior: hoisted closures with typed defaults from\n// const/function return types must work identically to non-hoisted versions.\n\nconst STR_CONST = \"hello\"\n\nfunction fnReturnsInt(x): int {\n  return x * x\n}\n\nfunction fnReturnsStringOrInt(x): string|int {\n  return x ? x : STR_CONST\n}\n\n// Hoisted: const value matches param type\nlet test1 = function() {\n  let fn = function(x: string = STR_CONST) { return x }\n  return fn()\n}\nassert(test1() == \"hello\")\n\n// Hoisted: function return type matches param type\nlet test2 = function() {\n  let fn = function(x: int = fnReturnsInt(3)) { return x }\n  return fn()\n}\nassert(test2() == 9)\n\n// Hoisted: union return type matches union param type\nlet test3 = function() {\n  let fn = function(x: string|int = fnReturnsStringOrInt(0)) { return x }\n  return fn()\n}\nassert(test3() == \"hello\")\n\nprintln(\"OK\")\n"
  },
  {
    "path": "testData/exec/closure_hoist_typed_return.out",
    "content": "OK"
  },
  {
    "path": "testData/exec/compare_int_float.nut",
    "content": "{ // >\n  let a = -1 > -1.0\n  let b = 5 > -1.0\n  let c = -1 > 5.0\n  assert(a == false)\n  assert(b == true)\n  assert(c == false)\n\n  assert(-1 > -1.0 == false)\n  assert(5 > -1.0 == true)\n  assert(-1 > 5.0 == false)\n\n  assert((-1 > -1.0 ? 55 : 66) == 66)\n  assert((5 > -1.0 ? 55 : 66) == 55)\n  assert((-1 > 5.0 ? 55 : 66) == 66)\n\n  if (-1 > -1.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (5 > -1.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (-1 > 5.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  let x = -1\n  let y = 5.0\n\n  let a1 = x > x\n  let b1 = y > x\n  let c1 = x > y\n  assert(a1 == false)\n  assert(b1 == true)\n  assert(c1 == false)\n\n  if (x > x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (y > x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (x > y) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n}\n\n{ // <\n  let a = -1 < -1.0\n  let b = 5 < -1.0\n  let c = -1 < 5.0\n  assert(a == false)\n  assert(b == false)\n  assert(c == true)\n\n  assert(-1 < -1.0 == false)\n  assert(5 < -1.0 == false)\n  assert(-1 < 5.0 == true)\n\n  assert((-1 < -1.0 ? 55 : 66) == 66)\n  assert((5 < -1.0 ? 55 : 66) == 66)\n  assert((-1 < 5.0 ? 55 : 66) == 55)\n\n  if (-1 < -1.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (5 < -1.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (-1 < 5.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  let x = -1\n  let y = 5.0\n\n  let a1 = x < x\n  let b1 = y < x\n  let c1 = x < y\n  assert(a1 == false)\n  assert(b1 == false)\n  assert(c1 == true)\n\n  if (x < x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (y < x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (x < y) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n}\n\n{ // >=\n  let a = -1 >= -1.0\n  let b = 5 >= -1.0\n  let c = -1 >= 5.0\n  assert(a == true)\n  assert(b == true)\n  assert(c == false)\n\n  assert(-1 >= -1.0 == true)\n  assert(5 >= -1.0 == true)\n  assert(-1 >= 5.0 == false)\n\n  assert((-1 >= -1.0 ? 55 : 66) == 55)\n  assert((5 >= -1.0 ? 55 : 66) == 55)\n  assert((-1 >= 5.0 ? 55 : 66) == 66)\n\n  if (-1 >= -1.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (5 >= -1.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (-1 >= 5.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  let x = -1\n  let y = 5.0\n\n  let a1 = x >= x\n  let b1 = y >= x\n  let c1 = x >= y\n  assert(a1 == true)\n  assert(b1 == true)\n  assert(c1 == false)\n\n  if (x >= x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (y >= x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (x >= y) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n}\n\n{ // <=\n  let a = -1 <= -1.0\n  let b = 5 <= -1.0\n  let c = -1 <= 5.0\n  assert(a == true)\n  assert(b == false)\n  assert(c == true)\n\n  assert(-1 <= -1.0 == true)\n  assert(5 <= -1.0 == false)\n  assert(-1 <= 5.0 == true)\n\n  assert((-1 <= -1.0 ? 55 : 66) == 55)\n  assert((5 <= -1.0 ? 55 : 66) == 66)\n  assert((-1 <= 5.0 ? 55 : 66) == 55)\n\n  if (-1 <= -1.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (5 <= -1.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (-1 <= 5.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  let x = -1\n  let y = 5.0\n\n  let a1 = x <= x\n  let b1 = y <= x\n  let c1 = x <= y\n  assert(a1 == true)\n  assert(b1 == false)\n  assert(c1 == true)\n\n  if (x <= x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (y <= x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (x <= y) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n}\n\n{ // ==\n  let a = -1 == -1.0\n  let b = 5 == -1.0\n  let c = -1 == 5.0\n  assert(a == true)\n  assert(b == false)\n  assert(c == false)\n\n  assert(-1 == -1.0 == true)\n  assert(5 == -1.0 == false)\n  assert(-1 == 5.0 == false)\n\n  assert((-1 == -1.0 ? 55 : 66) == 55)\n  assert((5 == -1.0 ? 55 : 66) == 66)\n  assert((-1 == 5.0 ? 55 : 66) == 66)\n\n  if (-1 == -1.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (5 == -1.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (-1 == 5.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  let x = -1\n  let y = 5.0\n\n  let a1 = x == x\n  let b1 = y == x\n  let c1 = x == y\n  assert(a1 == true)\n  assert(b1 == false)\n  assert(c1 == false)\n\n  if (x == x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (y == x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (x == y) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n}\n\n{ // !=\n  let a = -1 != -1.0\n  let b = 5 != -1.0\n  let c = -1 != 5.0\n  assert(a == false)\n  assert(b == true)\n  assert(c == true)\n\n  assert(-1 != -1.0 == false)\n  assert(5 != -1.0 == true)\n  assert(-1 != 5.0 == true)\n\n  assert((-1 != -1.0 ? 55 : 66) == 66)\n  assert((5 != -1.0 ? 55 : 66) == 55)\n  assert((-1 != 5.0 ? 55 : 66) == 55)\n\n  if (-1 != -1.0) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (5 != -1.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (-1 != 5.0) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  let x = -1\n  let y = 5.0\n\n  let a1 = x != x\n  let b1 = y != x\n  let c1 = x != y\n  assert(a1 == false)\n  assert(b1 == true)\n  assert(c1 == true)\n\n  if (x != x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (y != x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (x != y) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n}\n\nprint(\"ok\")\n"
  },
  {
    "path": "testData/exec/compare_int_float.out",
    "content": "ok"
  },
  {
    "path": "testData/exec/compare_int_int.nut",
    "content": "{ // >\n  let a = -1 > -1\n  let b = 5 > -1\n  let c = -1 > 5\n  assert(a == false)\n  assert(b == true)\n  assert(c == false)\n\n  assert(-1 > -1 == false)\n  assert(5 > -1 == true)\n  assert(-1 > 5 == false)\n\n  assert((-1 > -1 ? 55 : 66) == 66)\n  assert((5 > -1 ? 55 : 66) == 55)\n  assert((-1 > 5 ? 55 : 66) == 66)\n\n  if (-1 > -1) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (5 > -1) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (-1 > 5) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  let x = -1\n  let y = 5\n\n  let a1 = x > x\n  let b1 = y > x\n  let c1 = x > y\n  assert(a1 == false)\n  assert(b1 == true)\n  assert(c1 == false)\n\n  if (x > x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (y > x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (x > y) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n}\n\n{ // <\n  let a = -1 < -1\n  let b = 5 < -1\n  let c = -1 < 5\n  assert(a == false)\n  assert(b == false)\n  assert(c == true)\n\n  assert(-1 < -1 == false)\n  assert(5 < -1 == false)\n  assert(-1 < 5 == true)\n\n  assert((-1 < -1 ? 55 : 66) == 66)\n  assert((5 < -1 ? 55 : 66) == 66)\n  assert((-1 < 5 ? 55 : 66) == 55)\n\n  if (-1 < -1) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (5 < -1) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (-1 < 5) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  let x = -1\n  let y = 5\n\n  let a1 = x < x\n  let b1 = y < x\n  let c1 = x < y\n  assert(a1 == false)\n  assert(b1 == false)\n  assert(c1 == true)\n\n  if (x < x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (y < x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (x < y) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n}\n\n{ // >=\n  let a = -1 >= -1\n  let b = 5 >= -1\n  let c = -1 >= 5\n  assert(a == true)\n  assert(b == true)\n  assert(c == false)\n\n  assert(-1 >= -1 == true)\n  assert(5 >= -1 == true)\n  assert(-1 >= 5 == false)\n\n  assert((-1 >= -1 ? 55 : 66) == 55)\n  assert((5 >= -1 ? 55 : 66) == 55)\n  assert((-1 >= 5 ? 55 : 66) == 66)\n\n  if (-1 >= -1) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (5 >= -1) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (-1 >= 5) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  let x = -1\n  let y = 5\n\n  let a1 = x >= x\n  let b1 = y >= x\n  let c1 = x >= y\n  assert(a1 == true)\n  assert(b1 == true)\n  assert(c1 == false)\n\n  if (x >= x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (y >= x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (x >= y) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n}\n\n{ // <=\n  let a = -1 <= -1\n  let b = 5 <= -1\n  let c = -1 <= 5\n  assert(a == true)\n  assert(b == false)\n  assert(c == true)\n\n  assert(-1 <= -1 == true)\n  assert(5 <= -1 == false)\n  assert(-1 <= 5 == true)\n\n  assert((-1 <= -1 ? 55 : 66) == 55)\n  assert((5 <= -1 ? 55 : 66) == 66)\n  assert((-1 <= 5 ? 55 : 66) == 55)\n\n  if (-1 <= -1) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (5 <= -1) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (-1 <= 5) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  let x = -1\n  let y = 5\n\n  let a1 = x <= x\n  let b1 = y <= x\n  let c1 = x <= y\n  assert(a1 == true)\n  assert(b1 == false)\n  assert(c1 == true)\n\n  if (x <= x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (y <= x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (x <= y) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n}\n\n{ // ==\n  let a = -1 == -1\n  let b = 5 == -1\n  let c = -1 == 5\n  assert(a == true)\n  assert(b == false)\n  assert(c == false)\n\n  assert(-1 == -1 == true)\n  assert(5 == -1 == false)\n  assert(-1 == 5 == false)\n\n  assert((-1 == -1 ? 55 : 66) == 55)\n  assert((5 == -1 ? 55 : 66) == 66)\n  assert((-1 == 5 ? 55 : 66) == 66)\n\n  if (-1 == -1) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (5 == -1) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (-1 == 5) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  let x = -1\n  let y = 5\n\n  let a1 = x == x\n  let b1 = y == x\n  let c1 = x == y\n  assert(a1 == true)\n  assert(b1 == false)\n  assert(c1 == false)\n\n  if (x == x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (y == x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (x == y) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n}\n\n{ // !=\n  let a = -1 != -1\n  let b = 5 != -1\n  let c = -1 != 5\n  assert(a == false)\n  assert(b == true)\n  assert(c == true)\n\n  assert(-1 != -1 == false)\n  assert(5 != -1 == true)\n  assert(-1 != 5 == true)\n\n  assert((-1 != -1 ? 55 : 66) == 66)\n  assert((5 != -1 ? 55 : 66) == 55)\n  assert((-1 != 5 ? 55 : 66) == 55)\n\n  if (-1 != -1) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (5 != -1) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (-1 != 5) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  let x = -1\n  let y = 5\n\n  let a1 = x != x\n  let b1 = y != x\n  let c1 = x != y\n  assert(a1 == false)\n  assert(b1 == true)\n  assert(c1 == true)\n\n  if (x != x) {\n    assert(false)\n  } else {\n    assert(true)\n  }\n\n  if (y != x) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n\n  if (x != y) {\n    assert(true)\n  } else {\n    assert(false)\n  }\n}\n\nprint(\"ok\")\n"
  },
  {
    "path": "testData/exec/compare_int_int.out",
    "content": "ok"
  },
  {
    "path": "testData/exec/const_fold.nut",
    "content": "// Test AST-level constant folding\n// These expressions are fully const-evaluable and should be folded\n// to a single LOAD instruction during codegen.\n\n// Basic arithmetic\nassert(2 + 3 == 5)\nassert(10 - 3 == 7)\nassert(4 * 5 == 20)\nassert(15 / 3 == 5)\nassert(17 % 5 == 2)\n\n// Nested arithmetic\nassert((2 + 3) * (4 + 1) == 25)\nassert(1 + 2 + 3 + 4 + 5 == 15)\nassert(100 - 10 * 3 - 20 / 4 == 65)\n\n// String concatenation (NOT handled by peephole optimizer)\nassert(\"hello\" + \" \" + \"world\" == \"hello world\")\nassert(\"abc\" + \"def\" == \"abcdef\")\n\n// Comparison operators\nassert(3 > 2 == true)\nassert(3 < 2 == false)\nassert(3 >= 3 == true)\nassert(3 <= 2 == false)\nassert(3 == 3)\nassert(3 != 4)\n\n// Ternary with const condition\nassert((true ? \"yes\" : \"no\") == \"yes\")\nassert((false ? \"yes\" : \"no\") == \"no\")\nassert((1 > 0 ? 42 : 0) == 42)\n\n// Bitwise\nassert((0xFF & 0x0F) == 15)\nassert((1 << 4) == 16)\nassert((0xFF | 0x100) == 0x1FF)\nassert((0xFF ^ 0x0F) == 0xF0)\nassert((16 >> 2) == 4)\nassert((16 >>> 2) == 4)\n\n// Logical\nassert((true || false) == true)\nassert((true && false) == false)\nassert((false || true) == true)\nassert((false && true) == false)\n\n// Null coalescing\nassert((null ?? \"default\") == \"default\")\nassert((\"value\" ?? \"default\") == \"value\")\n\n// typeof\nassert(typeof 42 == \"integer\")\nassert(typeof \"hello\" == \"string\")\nassert(typeof 1.0 == \"float\")\nassert(typeof true == \"bool\")\n\n// Negation and bitwise not\nassert(-(-5) == 5)\nassert(!false == true)\nassert(!true == false)\nassert(~0 == -1)\nassert(~0xFF == -256)\n\n// Const identifiers in expressions\nconst A = 10\nconst B = 20\nassert(A + B == 30)\nassert(A * B + 5 == 205)\nassert(A > B == false)\nassert(A < B == true)\n\n// Enum values in expressions\nenum Color { RED = 1, GREEN = 2, BLUE = 4 }\nassert((Color.RED | Color.GREEN | Color.BLUE) == 7)\nassert(Color.RED + Color.GREEN == 3)\n\n// Mixed const and enum\nconst MASK = 0xFF\nassert((Color.BLUE & MASK) == 4)\n\n// Complex nested const expressions\nassert((A + B) * 2 - A == 50)\nassert((A > 5 ? A : B) == 10)\nassert((A < 5 ? A : B) == 20)\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/const_fold.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/const_in_closures.nut",
    "content": "function foo() {\n  const x = \"asdf\"\n  function bar() {\n    let a = x\n  }\n}"
  },
  {
    "path": "testData/exec/const_in_closures.out",
    "content": ""
  },
  {
    "path": "testData/exec/coroutines.nut",
    "content": "function coroutine_test(a,b) {\n    println($\"{a} {b}\")\n    local ret = suspend(\"suspend 1\")\n    println($\"the coroutine says {ret}\")\n    ret = suspend(\"suspend 2\");\n    println($\"the coroutine says {ret}\")\n    ret = suspend(\"suspend 3\");\n    println($\"the coroutine says {ret}\")\n    return \"I'm done\"\n}\n\nlet coro = newthread(coroutine_test)\n\nlocal susparam = coro.call(\"test\",\"coroutine\") //starts the coroutine\n\nlocal i = 1\ndo {\n    println($\"suspend passed [{susparam}]\")\n    susparam = coro.wakeup(\"ciao \"+i)\n    ++i\n}while(coro.getstatus()==\"suspended\")\n\nprintln($\"return passed [{susparam}]\")\n"
  },
  {
    "path": "testData/exec/coroutines.out",
    "content": "test coroutine\nsuspend passed [suspend 1]\nthe coroutine says ciao 1\nsuspend passed [suspend 2]\nthe coroutine says ciao 2\nsuspend passed [suspend 3]\nthe coroutine says ciao 3\nreturn passed [I'm done]\n"
  },
  {
    "path": "testData/exec/deep_loop_variable.nut",
    "content": "let x = { borders = [0, 0, 0, 0] }\nfor (; x.borders[2] < 5; x.borders[2]++)\n    println(x.borders[2])"
  },
  {
    "path": "testData/exec/deep_loop_variable.out",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "testData/exec/depth_check.nut",
    "content": "// Tailcall\n// Check how deep we can go\n\nfunction f(n) {\n  if (n > 0)\n    return f(n - 1)\n  return n\n}\ntry {\n  f(1000000)\n  println(\"OK\")\n} catch(e) {\n  println($\"Error: {e}\")\n}\n"
  },
  {
    "path": "testData/exec/depth_check.out",
    "content": "OK\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_destruct_idx.nut",
    "content": "// foreach with idx + destructured val: idx is in the foreach scope (shared\n// across iters by default), x/y are body-block locals (per-iter via parser\n// desugaring). When idx is captured by an inner closure, idx must also be\n// rebound per-iter.\n\nlet fns = []\nforeach (i, {x, y} in [{x = 1, y = 2}, {x = 10, y = 20}, {x = 100, y = 200}]) {\n  fns.append(@() i * 1000 + x * 10 + y)\n}\nforeach (f in fns) println(\"d1:\", f())\n\n// Same shape but idx not captured: only destructured fields captured. The\n// parser's body-Block scope already gives x/y per-iter; idx scan reports\n// no capture, so foreach uses the shared-slot path for idx.\nlet gs = []\nforeach (_i, {x, y} in [{x = 7, y = 8}, {x = 70, y = 80}]) {\n  gs.append(@() x + y)\n}\nforeach (g in gs) println(\"d2:\", g())\n\n// Destructured field default that *is* a closure (it captures an outer\n// var, but is evaluated per-iter so closures see fresh state each time).\nlet cap = 100\nlet hs = []\nforeach ({n = (function() { return cap })()} in [{n = 1}, {}, {n = 3}]) {\n  hs.append(@() n)\n}\nforeach (h in hs) println(\"d3:\", h())\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_destruct_idx.out",
    "content": "d1: 12\nd1: 1120\nd1: 3200\nd2: 15\nd2: 150\nd3: 1\nd3: 100\nd3: 3\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_idx_val.nut",
    "content": "// idx + val captured: both rebound per iteration.\nlet fns = []\nforeach (i, v in [\"a\", \"b\", \"c\"]) {\n  fns.append(@() i + \":\" + v)\n}\nforeach (f in fns) println(\"a1:\", f())\n\n// Only idx captured (val unused inside closure).\nlet gs = []\nforeach (i, _v in [100, 200, 300]) {\n  gs.append(@() i * 2)\n}\nforeach (g in gs) println(\"a2:\", g())\n\n// Closure captures idx via inner named function (not just lambda).\nlet hs = []\nforeach (i, v in [7, 8, 9]) {\n  function bind() { return i * 10 + v }\n  hs.append(bind)\n}\nforeach (h in hs) println(\"a3:\", h())\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_idx_val.out",
    "content": "a1: 0:a\na1: 1:b\na1: 2:c\na2: 0\na2: 2\na2: 4\na3: 7\na3: 18\na3: 29\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_plain_val.nut",
    "content": "// Plain `foreach (v in arr)`: closure captures `v`. Each closure must see\n// its own per-iteration value (not the final shared-slot value).\nlet fns = []\nforeach (v in [10, 20, 30]) {\n  fns.append(@() v)\n}\nforeach (f in fns) println(\"v1:\", f())\n\n// One-liner body form, same expectation.\nlet gs = []\nforeach (s in [\"a\", \"b\", \"c\"]) gs.append(@() s)\nforeach (g in gs) println(\"v2:\", g())\n\n// Nested foreach: inner closure captures both outer and inner val.\nlet pairs = []\nforeach (a in [1, 2]) {\n  foreach (b in [10, 20]) {\n    pairs.append(@() a * 100 + b)\n  }\n}\nforeach (f in pairs) println(\"v3:\", f())\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_plain_val.out",
    "content": "v1: 10\nv1: 20\nv1: 30\nv2: a\nv2: b\nv2: c\nv3: 110\nv3: 120\nv3: 210\nv3: 220\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_shadowed.nut",
    "content": "// Inner function declares its own param/local with the same name as an\n// outer foreach val. The capture scan over-approximates here (no shadow\n// tracking), so this triggers the per-iter path. Either way, the visible\n// behavior must be correct: closures returning the inner local must NOT\n// see the outer per-iter value, and closures actually capturing the outer\n// must see the per-iter value.\n\nlet outerCaps = []\nlet innerCaps = []\nforeach (v in [1, 2, 3]) {\n  // closure captures outer v\n  outerCaps.append(@() v)\n  // closure shadows v with its own param (no real capture of outer)\n  innerCaps.append(@(v) v * 10)\n}\nforeach (f in outerCaps) println(\"o:\", f())\nforeach (f in innerCaps) println(\"i:\", f(7))\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_capture_shadowed.out",
    "content": "o: 1\no: 2\no: 3\ni: 70\ni: 70\ni: 70\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destr_default_closure.nut",
    "content": "let outer_factor = 10\nfunction run() {\n  let acc = []\n  foreach ({n = (function(){ return outer_factor * 5 })()} in [{n = 1}, {}, {n = 3}]) {\n    acc.append(n)\n  }\n  return acc\n}\nlet r = run()\nprintln(r[0], r[1], r[2])\n\nfunction maker(scale) {\n  let out = []\n  foreach ({v = (@(s) s + 1)(scale)} in [{}, {v = 100}, {}]) {\n    out.append(v)\n  }\n  return out\n}\nlet m = maker(7)\nprintln(m[0], m[1], m[2])\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destr_default_closure.out",
    "content": "1 50 3\n8 100 8\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destruct_empty_pattern.nut",
    "content": "// Empty `{}` and `[]` destructuring patterns: pattern matches without\n// binding any field. Each iteration runs body once.\nlocal n = 0\nforeach ({} in [{a = 1}, {b = 2}, {}]) n++\nprintln(\"e1:\", n)\n\nlocal m = 0\nforeach ([] in [[1, 2, 3], [], [9]]) m++\nprintln(\"e2:\", m)\n\n// Same with idx.\nlocal sumIdx = 0\nforeach (i, {} in [{a = 1}, {b = 2}]) sumIdx += i\nprintln(\"e3:\", sumIdx)\n\n// Function-arg empty destructuring is now also accepted (shared\n// parseDestructuringFields helper).\nlet f = function({}) { return \"ok\" }\nprintln(\"e4:\", f({a = 1}))\n\nlet g = function([]) { return \"ok2\" }\nprintln(\"e5:\", g([1, 2]))\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destruct_empty_pattern.out",
    "content": "e1: 3\ne2: 3\ne3: 1\ne4: ok\ne5: ok2\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destructuring.nut",
    "content": "// f1: array destructure, no idx\nlet arr2d = [[1, 2, 3], [4, 5, 6]]\nforeach ([a, b, c] in arr2d) {\n  println(\"f1:\", a, b, c)\n}\n\n// f2: array destructure with idx\nforeach (i, [a, b, c] in arr2d) {\n  println(\"f2:\", i, a, b, c)\n}\n\n// f3: table destructure, no idx\nlet tbls = [{x = 1, y = 2}, {x = 3, y = 4}]\nforeach ({x, y} in tbls) {\n  println(\"f3:\", x, y)\n}\n\n// f4: table destructure with idx\nforeach (i, {x, y} in tbls) {\n  println(\"f4:\", i, x, y)\n}\n\n// f5: defaults on missing keys\nlet partial = [{x = 10}, {y = 20}, {}]\nforeach ({x = -1, y = -2} in partial) {\n  println(\"f5:\", x, y)\n}\n\n// f6: typed destructure with default\nforeach ({x: int = 0, y: int|null = null} in [{x = 5}, {y = 7}]) {\n  println(\"f6:\", x, y)\n}\n\n// f7: nested foreach destructures\nlet nested = [\n  [{p = 1, q = 2}, {p = 3}],\n  [{q = 9}]\n]\nforeach (i, row in nested) {\n  foreach (j, {p = 0, q = 0} in row) {\n    println(\"f7:\", i, j, p, q)\n  }\n}\n\n// f8: mixed -- outer destructured array, inner plain\nforeach ([first, second] in [[10, 20], [30, 40]]) {\n  println(\"f8:\", first, second)\n}\n\n// f9: destructure value while reading idx\nlet m = {alpha = {n = 1}, beta = {n = 2}}\nforeach (k, {n} in m) {\n  println(\"f9:\", k, n)\n}\n\n// f10: instance destructure\nclass Pt { x = 0; y = 0; constructor(x_, y_) { this.x = x_; this.y = y_ } }\nforeach (k, {x, y} in {a = Pt(1, 2), b = Pt(3, 4)}) {\n  println(\"f10:\", k, x, y)\n}\n\n// f11: empty defaults flow when iterating same array twice\nlet runs = [{}, {x = 5}]\nforeach ({x = 99} in runs) {\n  println(\"f11:\", x)\n}\nforeach ({x = 99} in runs) {\n  println(\"f11b:\", x)\n}\n\n// f12: capture destructured var in closure\nlet fns = []\nforeach ({v} in [{v = 1}, {v = 2}, {v = 3}]) {\n  fns.append(@() v)\n}\nforeach (f in fns) {\n  println(\"f12:\", f())\n}\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destructuring.out",
    "content": "f1: 1 2 3\nf1: 4 5 6\nf2: 0 1 2 3\nf2: 1 4 5 6\nf3: 1 2\nf3: 3 4\nf4: 0 1 2\nf4: 1 3 4\nf5: 10 -2\nf5: -1 20\nf5: -1 -2\nf6: 5 null\nf6: 0 7\nf7: 0 0 1 2\nf7: 0 1 3 0\nf7: 1 0 0 9\nf8: 10 20\nf8: 30 40\nf9: beta 2\nf9: alpha 1\nf10: a 1 2\nf10: b 3 4\nf11: 99\nf11: 5\nf11b: 99\nf11b: 5\nf12: 1\nf12: 2\nf12: 3\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destructuring_branches.nut",
    "content": "// B01: empty table pattern (parser: '{' immediately followed by '}')\nforeach ({} in [{a = 1}, {a = 2}]) println(\"B01\")\n\n// B02: empty array pattern (parser: '[' immediately followed by ']')\nforeach ([] in [[1, 2], [3]]) println(\"B02\")\n\n// B03: destructure-only val, no idx (firstIsDestr branch)\nforeach ({x} in [{x = 10}]) println(\"B03\", x)\n\n// B04: idx + destructured val (idx-then-destructure branch in parser)\nforeach (i, {x} in [{x = 10}, {x = 20}]) println(\"B04\", i, x)\n\n// B05: idx + plain val (existing path, regression guard)\nforeach (i, v in [11, 22]) println(\"B05\", i, v)\n\n// B06: plain val (existing path, regression guard)\nforeach (v in [33, 44]) println(\"B06\", v)\n\n// B07: type mask without default (runtime EmitCheckType, initializer == null)\nforeach ({n: int} in [{n = 1}, {n = 2}]) println(\"B07\", n)\n\n// B08: default without type mask (initializer present, typeMask == ~0u)\nforeach ({m = -9} in [{m = 5}, {}]) println(\"B08\", m)\n\n// B09: default + type mask combined (initializer present, typeMask present)\nforeach ({k: int = -1} in [{}, {k = 7}]) println(\"B09\", k)\n\n// B10: nullable union default\nforeach ({s: string|null = null} in [{s = \"ok\"}, {}]) println(\"B10\", s)\n\n// B11: array destructure index-based (DT_ARRAY codegen branch with GetNumericConstant)\nforeach ([a, b] in [[1, 2], [10, 20]]) println(\"B11\", a, b)\n\n// B12: array destructure with default for missing element\nforeach ([a, b = 99] in [[1], [10, 20]]) println(\"B12\", a, b)\n\n// B13: multiple decls inside one destructure with mixed shapes\nforeach ({a, b: int = 0, c = \"?\", d: int|null = null} in [\n  {a = 1, c = \"x\"},\n  {a = 2, b = 5, d = 42},\n  {a = 3}\n]) println(\"B13\", a, b, c, d)\n\nforeach ({arr} in [{arr = [1, 2]}, {arr = [3, 4, 5]}]) {\n  local sum = 0\n  foreach (n in arr) sum += n\n  println(\"B14\", sum)\n}\n\nlet cap = 100\nforeach ({v} in [{v = 1}, {v = 2}]) {\n  let make = function() { return v + cap }\n  println(\"B15\", make())\n}\n\nforeach (val in [7, 8]) println(\"B16\", val)\n\nfunction defv() { return 77 }\nforeach ({z = defv()} in [{z = 1}, {}, {z = 3}]) println(\"B17\", z)\n\nclass Acc {\n  data = null\n  constructor() { this.data = [] }\n  function ingest(rows) {\n    foreach ({tag = \"?\"} in rows) this.data.append(tag)\n  }\n}\nlet acc = Acc()\nacc.ingest([{tag = \"a\"}, {}, {tag = \"c\"}])\nforeach (s in acc.data) println(\"B18\", s)\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destructuring_branches.out",
    "content": "B01\nB01\nB02\nB02\nB03 10\nB04 0 10\nB04 1 20\nB05 0 11\nB05 1 22\nB06 33\nB06 44\nB07 1\nB07 2\nB08 5\nB08 -9\nB09 -1\nB09 7\nB10 ok\nB10 null\nB11 1 2\nB11 10 20\nB12 1 99\nB12 10 20\nB13 1 0 x null\nB13 2 5 ? 42\nB13 3 0 ? null\nB14 3\nB14 12\nB15 101\nB15 102\nB16 7\nB16 8\nB17 1\nB17 77\nB17 3\nB18 a\nB18 ?\nB18 c\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destructuring_complex.nut",
    "content": "// =====================================================================\n// 1. Three-level nested foreach with destructure at every level\n// =====================================================================\nlet world = [\n  {name = \"north\", regions = [\n    {tag = \"a\", cells = [{x = 1, y = 2}, {x = 3, y = 4}]},\n    {tag = \"b\", cells = [{x = 5, y = 6}]}\n  ]},\n  {name = \"south\", regions = [\n    {tag = \"c\", cells = [{x = 7, y = 8}, {x = 9, y = 10}]}\n  ]}\n]\nforeach (i, {name, regions} in world) {\n  foreach (j, {tag, cells} in regions) {\n    foreach (k, {x, y} in cells) {\n      println(\"L1:\", i, name, j, tag, k, x, y)\n    }\n  }\n}\n\n\n// =====================================================================\n// 2. Destructured value used inside an inner function defined per iter\n// =====================================================================\nlet factories = []\nforeach (i, {label, basev} in [{label = \"alpha\", basev = 10}, {label = \"beta\", basev = 100}]) {\n  let mult = i + 1\n  function build(extra) {\n    return label + \":\" + (basev * mult + extra)\n  }\n  factories.append(build)\n}\nforeach (f in factories) {\n  println(\"L2:\", f(7))\n}\n\n\n// =====================================================================\n// 3. Destructured value flows through nested functions and a class method\n// =====================================================================\nclass Counter {\n  total = 0\n  function add(v) { this.total += v; return this.total }\n}\nlet counter = Counter()\nlet pipeline = [{op = \"x\", n = 3}, {op = \"y\", n = 5}, {op = \"z\", n = 2}]\nforeach (i, {op, n} in pipeline) {\n  let local_op = op\n  function step() {\n    function inner() {\n      return counter.add(n * (i + 1))\n    }\n    return local_op + \"->\" + inner()\n  }\n  println(\"L3:\", step())\n}\nprintln(\"L3 total:\", counter.total)\n\n\n// =====================================================================\n// 4. Defaults + type masks combined with nested foreach\n// =====================================================================\nlet groups = [\n  {gid = 1, members = [{n = \"a\", age = 10}, {n = \"b\"}, {age = 99}]},\n  {gid = 2, members = []},\n  {gid = 3, members = [{n = \"c\", age = 7}]}\n]\nforeach ({gid, members} in groups) {\n  foreach ({n = \"?\", age: int|null = null} in members) {\n    println(\"L4:\", gid, n, age)\n  }\n}\n\n\n// =====================================================================\n// 5. Capturing destructured value per iteration via inner let-destructure\n// =====================================================================\nlet getters = []\nforeach (item in [{key = \"a\", val = 1}, {key = \"b\", val = 2}, {key = \"c\", val = 3}]) {\n  let {key, val} = item\n  getters.append(@() key + \"=\" + val)\n}\nforeach (g in getters) {\n  println(\"L5:\", g())\n}\n\n\n// =====================================================================\n// 6. Modifying the source table through destructure idx alias\n// =====================================================================\nlet mutable_rows = [{count = 1}, {count = 2}, {count = 3}]\nforeach (i, {count} in mutable_rows) {\n  // count is a copy of the field; mutate via index, not via destructured local\n  mutable_rows[i].count = count * 10\n}\nforeach ({count} in mutable_rows) {\n  println(\"L6:\", count)\n}\n\n\n// =====================================================================\n// 7. break / continue / return inside nested destructuring loops\n// =====================================================================\nfunction findFirstHigh(rows) {\n  foreach (i, {label, scores} in rows) {\n    foreach (j, {v} in scores) {\n      if (v < 50) continue\n      if (v > 200) return [label, i, j, v, \"stop\"]\n      if (v > 100) return [label, i, j, v, \"ok\"]\n    }\n  }\n  return null\n}\nlet r = findFirstHigh([\n  {label = \"first\",  scores = [{v = 10}, {v = 30}]},\n  {label = \"second\", scores = [{v = 70}, {v = 130}, {v = 9000}]},\n  {label = \"third\",  scores = [{v = 1}]}\n])\nif (r != null) {\n  let [a, b, c, d, e] = r\n  println(\"L7:\", a, b, c, d, e)\n}\n\n\n// =====================================================================\n// 8. Destructuring over class instances with inherited fields\n// =====================================================================\nclass Base {\n  x = 0\n  y = 0\n  constructor(x_, y_) { this.x = x_; this.y = y_ }\n}\nclass Derived (Base) {\n  z = 0\n  constructor(x_, y_, z_) { base.constructor(x_, y_); this.z = z_ }\n}\nlet pts = [Base(1, 2), Derived(3, 4, 5), Base(6, 7), Derived(8, 9, 10)]\nforeach (i, {x, y, z = -1} in pts) {\n  println(\"L8:\", i, x, y, z)\n}\n\n\n// =====================================================================\n// 9. Generator/coroutine + destructure from yielded values\n// =====================================================================\nlet gen = function() {\n  yield {tag = \"a\", n = 1}\n  yield {tag = \"b\", n = 2}\n  yield {tag = \"c\", n = 3}\n}\nlet g = gen()\nforeach (i, {tag, n} in g) {\n  println(\"L9:\", i, tag, n)\n}\n\n\n// =====================================================================\n// 10. Destructured value as constructor argument and method call result\n// =====================================================================\nclass Box {\n  v = 0\n  constructor(v_) { this.v = v_ }\n  function bump(d) { this.v += d; return this }\n  function get() { return this.v }\n}\nlet configs = [{init = 100, deltas = [1, 2, 3]}, {init = 1000, deltas = [10, 20]}]\nlet boxes = []\nforeach ({init, deltas} in configs) {\n  let b = Box(init)\n  foreach (d in deltas) b.bump(d)\n  boxes.append(b)\n}\nforeach (i, b in boxes) {\n  println(\"L10:\", i, b.get())\n}\n\n\n// =====================================================================\n// 11. Heterogeneous default types (int default vs string default vs null)\n// =====================================================================\nlet mixed = [\n  {n = 5, s = \"hello\", b = true},\n  {n = 7},\n  {s = \"world\"},\n  {},\n  {b = false, s = \"x\", n = 9}\n]\nforeach (i, {n: int = -1, s: string = \"?\", b: bool|null = null} in mixed) {\n  println(\"L11:\", i, n, s, b)\n}\n\n\n// =====================================================================\n// 12. Destructure with idx and value, then re-iterate inside body\n// =====================================================================\nlet matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\nforeach (i, [a, b, c] in matrix) {\n  let row_sum = a + b + c\n  // inner foreach over the same row by index access\n  let parts = []\n  foreach (cell in [a, b, c]) parts.append(cell * (i + 1))\n  println(\"L12:\", i, row_sum, parts[0], parts[1], parts[2])\n}\n\n\n// =====================================================================\n// 13. Function returning destructure-friendly tables, chained\n// =====================================================================\nfunction mkPair(a, b) { return {first = a, second = b} }\nlet pairs = [mkPair(1, \"one\"), mkPair(2, \"two\"), mkPair(3, \"three\")]\nlet folded = (function() {\n  let parts = []\n  foreach ({first, second} in pairs) {\n    parts.append(second + \"=\" + first)\n  }\n  return parts\n})()\nforeach (s in folded) {\n  println(\"L13:\", s)\n}\n\n\n// =====================================================================\n// 14. Closure capture of idx + destructured field; called after loop\n// =====================================================================\nlet bound = []\nforeach (i, {tag, weight} in [{tag = \"p\", weight = 3}, {tag = \"q\", weight = 7}]) {\n  let captured_tag = tag\n  let captured_weight = weight\n  bound.append(function() {\n    return captured_tag + \"@\" + i + \"=\" + captured_weight\n  })\n}\nforeach (f in bound) {\n  println(\"L14:\", f())\n}\n\n\n// =====================================================================\n// 15. Destructure in foreach inside a class method\n// =====================================================================\nclass Aggregator {\n  data = null\n  constructor() { this.data = [] }\n  function ingest(rows) {\n    foreach ({src, val = 0} in rows) {\n      this.data.append(src + \":\" + val)\n    }\n  }\n}\nlet agg = Aggregator()\nagg.ingest([{src = \"a\", val = 1}, {src = \"b\"}, {src = \"c\", val = 9}])\nforeach (s in agg.data) {\n  println(\"L15:\", s)\n}\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_destructuring_complex.out",
    "content": "L1: 0 north 0 a 0 1 2\nL1: 0 north 0 a 1 3 4\nL1: 0 north 1 b 0 5 6\nL1: 1 south 0 c 0 7 8\nL1: 1 south 0 c 1 9 10\nL2: alpha:17\nL2: beta:207\nL3: x->3\nL3: y->13\nL3: z->19\nL3 total: 19\nL4: 1 a 10\nL4: 1 b null\nL4: 1 ? 99\nL4: 3 c 7\nL5: a=1\nL5: b=2\nL5: c=3\nL6: 10\nL6: 20\nL6: 30\nL7: second 1 1 130 ok\nL8: 0 1 2 -1\nL8: 1 3 4 5\nL8: 2 6 7 -1\nL8: 3 8 9 10\nL9: 0 a 1\nL9: 1 b 2\nL9: 2 c 3\nL10: 0 106\nL10: 1 1030\nL11: 0 5 hello true\nL11: 1 7 ? null\nL11: 2 -1 world null\nL11: 3 -1 ? null\nL11: 4 9 x false\nL12: 0 6 1 2 3\nL12: 1 15 8 10 12\nL12: 2 24 21 24 27\nL13: one=1\nL13: two=2\nL13: three=3\nL14: p@0=3\nL14: q@1=7\nL15: a:1\nL15: b:0\nL15: c:9\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_no_capture.nut",
    "content": "// Regression guard for the zero-overhead path: when the body has no inner\n// function or lambda referencing idx/val, the codegen keeps idx/val in the\n// foreach's shared slot. Behavior must be identical to pre-capture-fix.\n\nlocal sum = 0\nforeach (v in [1, 2, 3, 4]) sum += v\nprintln(\"s1:\", sum)\n\nlocal pairs = 0\nforeach (i, v in [10, 20, 30]) pairs += i * 100 + v\nprintln(\"s2:\", pairs)\n\n// Nested function defined but doesn't reference outer idx/val: still\n// shared-slot path (over-approx may take the per-iter path, output is the\n// same either way - this asserts the semantic, not the strategy).\nlocal r = 0\nforeach (v in [5, 6]) {\n  function helper(x) { return x + 1 }\n  r += helper(v)\n}\nprintln(\"s3:\", r)\n\n// break/continue still work on shared-slot path.\nlocal first_even = -1\nforeach (v in [1, 3, 5, 4, 7]) {\n  if (v % 2 != 0) continue\n  first_even = v\n  break\n}\nprintln(\"s4:\", first_even)\n"
  },
  {
    "path": "testData/exec/destructuring/foreach_no_capture.out",
    "content": "s1: 10\ns2: 360\ns3: 13\ns4: 4\n"
  },
  {
    "path": "testData/exec/destructuring/function_param_destructuring.nut",
    "content": "function t31({x}) { println(\"t31:\", x) }\nt31({x = 1})\n\nfunction t32({x = 10}) { println(\"t32:\", x) }\nt32({})\n\nfunction t33({x: int = 3, y}) { println(\"t33:\", x, y) }\nt33({y = 5})\n\nfunction t34({x, y: float|null}) { println(\"t34:\", x, y) }\nt34({x = 1, y = null})\n\nfunction t35({x = 1}, [y]) { println(\"t35:\", x, y) }\nt35({}, [2])\n\nfunction t36({x: int = 1}, [y: int = 2]) { println(\"t36:\", x, y) }\nt36({}, [])\n\nfunction t37({x, y}, [a, b]) { println(\"t37:\", x, y, a, b) }\nt37({x = 1, y = 2}, [3, 4])\n\nfunction t38({x: int = 5}, [a, b: float = 2.2]) { println(\"t38:\", x, a, b) }\nt38({}, [1])\n\nfunction t39({x = null}, [a = null]) { println(\"t39:\", x, a) }\nt39({}, [])\n\nfunction t40({x}, _) { println(\"t40:\", x) }\nt40({x = 99}, [])\n\nfunction t41(a, {x = 10}) { println(\"t41:\", a, x) }\nt41(5, {})\n\nfunction t42({x = 10}, a = [1, 2, 3]) { println(\"t42:\", a, x) }\nt42({}, 5)\n\nfunction t43({x = 10}, a, {y = 12}) { println(\"t43:\", a, x, y) }\nt43({x = 2, y = 3}, 5, {})\n\nfunction t44({x = 10}, a, {y: int = 12}, ...) { println(\"t44:\", a, x, y, vargv[0]) }\nt44({}, 5, {e = 5}, 999)\n\nfunction t45([x], a, {y: int = 12}, ...) { println(\"t45:\", a, x, y, vargv[0]) }\nt45([1], 5, {e = 5}, 999)\n\n\nlet k31 = @({x}) println(\"k31:\", x)\nk31({x = 1})\n\nlet k32 = @({x = 10}) println(\"k32:\", x)\nk32({})\n\nlet k33 = @({x: int = 3, y}) println(\"k33:\", x, y)\nk33({y = 5})\n\nlet k34 = @({x, y: float|null}) println(\"k34:\", x, y)\nk34({x = 1, y = null})\n\nlet k35 = @({x = 1}, [y]) println(\"k35:\", x, y)\nk35({}, [2])\n\nlet k36 = @({x: int = 1}, [y: int = 2]) println(\"k36:\", x, y)\nk36({}, [])\n\nlet k37 = @({x, y}, [a, b]) println(\"k37:\", x, y, a, b)\nk37({x = 1, y = 2}, [3, 4])\n\nlet k38 = @({x: int = 5}, [a, b: float = 2.2]) println(\"k38:\", x, a, b)\nk38({}, [1])\n\nlet k39 = @({x = null}, [a = null]) println(\"k39:\", x, a)\nk39({}, [])\n\nlet k40 = @({x}, _) println(\"k40:\", x)\nk40({x = 99}, [])\n\nlet k41 = @(a, {x = 10}) println(\"k41:\", a, x)\nk41(5, {})\n\nlet k42 = @({x = 10}, a = [1, 2, 3]) println(\"k42:\", a, x)\nk42({}, 5)\n\nlet k43 = @({x = 10}, a, {y = 12}) println(\"k43:\", a, x, y)\nk43({x = 2, y = 3}, 5, {})\n\nlet k44 = @({x = 10}, a, {y: int = 12}, ...) println(\"k44:\", a, x, y, vargv[0])\nk44({}, 5, {e = 5}, 999)\n\nlet k45 = @([x], a, {y: int = 12}, ...) println(\"k45:\", a, x, y, vargv[0])\nk45([1], 5, {e = 5}, 999)\n\n\n//--------------------------------------------------\n// N1: object destructuring inside a nested function\n//--------------------------------------------------\nfunction n1() {\n  function inner({x = 10}) {\n    println(\"n1:\", x)\n  }\n  inner({})\n}\nn1()\n\n//--------------------------------------------------\n// N2: array destructuring inside a nested function\n//--------------------------------------------------\nfunction n2() {\n  function inner([a, b = 2]) {\n    println(\"n2:\", a, b)\n  }\n  inner([1])\n}\nn2()\n\n//--------------------------------------------------\n// N3: closure + destructuring\n//--------------------------------------------------\nfunction n3() {\n  let offset = 5\n  function inner({x = 1}) {\n    println(\"n3:\", x + offset)\n  }\n  inner({})\n}\nn3()\n\n//--------------------------------------------------\n// N4: outer argument + inner destructuring\n//--------------------------------------------------\nfunction n4({x = 3}) {\n  function inner([y = 4]) {\n    println(\"n4:\", x, y)\n  }\n  inner([])\n}\nn4({})\n\n//--------------------------------------------------\n// N5: name shadowing in a nested function\n//--------------------------------------------------\nfunction n5({x = 1}) {\n  function inner({x = 10}) {\n    println(\"n5:\", x)\n  }\n  inner({})\n}\nn5({x = 2})\n\n//--------------------------------------------------\n// N6: types in a nested function\n//--------------------------------------------------\nfunction n6() {\n  function inner({x: int = 7}, [y: int = 8]) {\n    println(\"n6:\", x, y)\n  }\n  inner({}, [])\n}\nn6()\n\n//--------------------------------------------------\n// N7: multiple levels of nested functions\n//--------------------------------------------------\nfunction n7() {\n  function mid({x = 1}) {\n    function inner([y = 2]) {\n      println(\"n7:\", x, y)\n    }\n    inner([])\n  }\n  mid({})\n}\nn7()\n\n//--------------------------------------------------\n// N8: passing destructured values further\n//--------------------------------------------------\nfunction n8() {\n  function mid({x = 3}) {\n    function inner(v) {\n      println(\"n8:\", v)\n    }\n    inner(x)\n  }\n  mid({})\n}\nn8()\n\n//--------------------------------------------------\n// N9: destructuring + null in a nested function\n//--------------------------------------------------\nfunction n9() {\n  function inner({x: int|null = null}) {\n    println(\"n9:\", x)\n  }\n  inner({})\n}\nn9()\n\n//--------------------------------------------------\n// N10: destructuring + varargs in a nested function\n//--------------------------------------------------\nfunction n10() {\n  function inner({x = 1}, ...) {\n    println(\"n10:\", x, vargv[0])\n  }\n  inner({}, 99)\n}\nn10()\n\n\nfunction c1(\n  cfg = {\n    handlers = [\n      function({x = 1}) {\n        function inner({y = 2}) {\n          println(\"c1:\", x, y)\n        }\n        inner({})\n      }\n    ]\n  }\n) {\n  cfg.handlers[0]({})\n}\nc1()\n\n\nfunction c2(\n  data = {\n    make = function() {\n      return function(\n        opts = {\n          run = function([a = 3, b = 4]) {\n            function inner({x = 5}) {\n              println(\"c2:\", a, b, x)\n            }\n            inner({})\n          }\n        }\n      ) {\n        opts.run([])\n      }\n    }\n  }\n) {\n  let f = data.make()\n  f()\n}\nc2()\n\n\nfunction e1(\n  cfg = class {\n    counter = 0\n    function next({step = 1}) {\n      this.counter += step\n      return this.counter\n    }\n  }()\n) {\n  println(\"e1:\", cfg.next({}), cfg.next({step = 2}))\n}\ne1()\ne1()\n\n\nfunction e2(\n  box = {\n    fns = [\n      function({x = 1}) {\n        return function([y = 2]) {\n          println(\"e2:\", x, y)\n        }\n      }\n    ]\n  }\n) {\n  let g = box.fns[0]({})\n  g([])\n}\ne2()\n\n\nfunction e3(\n  state = {\n    init = function() {\n      return function({x = 10}, ...) {\n        println(\"e3:\", x, vargv.len())\n      }\n    }\n  }\n) {\n  let f = state.init()\n  f({}, 1, 2, 3)\n}\ne3()\n\n\nfunction e4(\n  make = function(\n    cfg = {\n      wrap = function(fn) {\n        return function({x = 1}) {\n          fn(x)\n        }\n      }\n    }\n  ) {\n    return cfg.wrap(\n      function(v) {\n        println(\"e4:\", v)\n      }\n    )\n  }\n) {\n  let f = make()\n  f({})\n}\ne4()\n\n\nfunction e5(\n  cfg = {\n    a = function({x = 1}) {\n      function b([y = 2]) {\n        function c({z = 3}) {\n          println(\"e5:\", x, y, z)\n        }\n        c({})\n      }\n      b([])\n    }\n  }\n) {\n  cfg.a({})\n}\ne5()\n\n\n\nfunction t2({a = {x = 0}}) {\n  a.x++\n  println(\"t2:\", a.x)\n}\n\nt2({})\nt2({})\n\n\nfunction t3([arr = []]) {\n  arr.append(1)\n  println(\"t3:\", arr.len())\n}\n\nt3([])\nt3([])\n\n\nfunction t4(\n  [cfg: table = {\n    count = 0,\n    inc = function() {\n      this.count++\n      return this.count\n    }\n  }]\n) {\n  println(\"t4:\", cfg.inc())\n}\n\nt4([])\nt4([])\n\nfunction t5(\n  cfg = {\n    make = function() {\n      return function({x = {y = 0}}) {\n        x.y++\n        println(\"t5:\", x.y)\n      }\n    }\n  }\n) {\n  let f = cfg.make()\n  f({})\n}\n\nt5()\nt5()\n\n"
  },
  {
    "path": "testData/exec/destructuring/function_param_destructuring.out",
    "content": "t31: 1\nt32: 10\nt33: 3 5\nt34: 1 null\nt35: 1 2\nt36: 1 2\nt37: 1 2 3 4\nt38: 5 1 2.2\nt39: null null\nt40: 99\nt41: 5 10\nt42: 5 10\nt43: 5 2 12\nt44: 5 10 12 999\nt45: 5 1 12 999\nk31: 1\nk32: 10\nk33: 3 5\nk34: 1 null\nk35: 1 2\nk36: 1 2\nk37: 1 2 3 4\nk38: 5 1 2.2\nk39: null null\nk40: 99\nk41: 5 10\nk42: 5 10\nk43: 5 2 12\nk44: 5 10 12 999\nk45: 5 1 12 999\nn1: 10\nn2: 1 2\nn3: 6\nn4: 3 4\nn5: 10\nn6: 7 8\nn7: 1 2\nn8: 3\nn9: null\nn10: 1 99\nc1: 1 2\nc2: 3 4 5\ne1: 1 3\ne1: 4 6\ne2: 1 2\ne3: 10 3\ne4: 1\ne5: 1 2 3\nt2: 1\nt2: 1\nt3: 1\nt3: 1\nt4: 1\nt4: 1\nt5: 1\nt5: 1\n"
  },
  {
    "path": "testData/exec/div64_by_minus_one_opt.nut",
    "content": "let min_int = -0x7FFFFFFF_FFFFFFFF-1\ntry {\n    print( min_int / -1 )\n} catch(e) {\n    print(\"OK\")\n}"
  },
  {
    "path": "testData/exec/div64_by_minus_one_opt.out",
    "content": "OK"
  },
  {
    "path": "testData/exec/div64_by_minus_one_vm.nut",
    "content": "try {\n    local x = -0x7FFFFFFFFFFFFFFF - 1\n    local y = @(a) -a\n    print( x / y(1) )\n} catch (e) {\n    print(\"OK\")\n}"
  },
  {
    "path": "testData/exec/div64_by_minus_one_vm.out",
    "content": "OK"
  },
  {
    "path": "testData/exec/div_by_minus_one_opt.nut",
    "content": "print( (-0x7FFFFFFF-1) / -1 )\n"
  },
  {
    "path": "testData/exec/div_by_minus_one_opt.out",
    "content": "2147483648"
  },
  {
    "path": "testData/exec/div_by_minus_one_vm.nut",
    "content": "local x = -0x7FFFFFFF - 1\nlocal y = @(a) -a\nprint( x / y(1) )\n"
  },
  {
    "path": "testData/exec/div_by_minus_one_vm.out",
    "content": "2147483648"
  },
  {
    "path": "testData/exec/fallback_get_recursion.nut",
    "content": "// Demonstrates SQVM::FallBackGet <-> SQVM::Get recursion (1.3)\n//\n// Note: The pure delegation chain path (table -> delegate -> table)\n// requires setdelegate() which is a C API only, not exposed to script.\n// But the SAME FallBackGet function also handles OT_INSTANCE via _get\n// metamethod (sqvm.cpp:2172-2188), which re-enters Get().\n//\n// Call chain for `a.missing_key` where a is instance of class with _get:\n//   GetImpl(a, \"missing_key\")           // sqvm.cpp:2053\n//     -> key not found in instance slots\n//     -> FallBackGet(a, \"missing_key\")  // sqvm.cpp:2159\n//       -> case OT_INSTANCE:            // sqvm.cpp:2172\n//       -> GetMetaMethod(MT_GET) -> found _get\n//       -> Call(_get, [a, \"missing_key\"]) // sqvm.cpp:2178\n//         -> Execute() runs _get body\n//           -> body accesses b.missing_key\n//           -> GetImpl(b, \"missing_key\")\n//             -> FallBackGet(b, \"missing_key\")\n//               -> Call(_get, [b, \"missing_key\"])\n//                 -> body accesses a.missing_key  <-- infinite loop!\n\nlocal depth = 0\nlocal a = null\nlocal b = null\n\nclass A {\n  other = null\n  function _get(key) {\n    depth++\n    if (depth <= 5)\n      println($\"  A._get('{key}') depth={depth}, forwarding to B...\")\n    // Accessing .missing on the other instance triggers\n    // Get -> FallBackGet -> _get on that instance\n    return this.other.missing\n  }\n}\n\nclass B {\n  other = null\n  function _get(key) {\n    depth++\n    if (depth <= 5)\n      println($\"  B._get('{key}') depth={depth}, forwarding to A...\")\n    return this.other.missing\n  }\n}\n\na = A()\nb = B()\na.other = b\nb.other = a\n\nprintln(\"Accessing a.x ...\")\ntry {\n  // This triggers: Get(a,\"x\") -> FallBackGet -> _get -> Get(b,\"missing\")\n  //   -> FallBackGet -> _get -> Get(a,\"missing\") -> ... infinite\n  local val = a.x\n  println($\"val = {val}\")\n} catch(e) {\n  println($\"  ... (skipping depths 6..{depth})\")\n  println($\"Caught after depth={depth}: {e}\")\n}\n"
  },
  {
    "path": "testData/exec/fallback_get_recursion.out",
    "content": "Accessing a.x ...\n  A._get('x') depth=1, forwarding to B...\n  B._get('missing') depth=2, forwarding to A...\n  A._get('missing') depth=3, forwarding to B...\n  B._get('missing') depth=4, forwarding to A...\n  A._get('missing') depth=5, forwarding to B...\n  ... (skipping depths 6..99)\nCaught after depth=99: Error in '_get' metamethod: Native stack overflow\n"
  },
  {
    "path": "testData/exec/fuzzer_seed_106.nut",
    "content": "// #disable-optimizer\n// seed = 106\ntry{\nlocal count = 0\nlet to_log = function(id, s) { let tp = typeof(s); print($\"{id}: \"); print(tp == \"integer\" || tp == \"float\" || tp == \"string\" ? s : tp); print(\"\\n\"); if (count++ > 1000) print[\"stop\"]; }\n{\n  let t6 = { }\n  let a7 = [ (-5), ]\n  let t54 = { f0=-3317007163456823286 f1=-4 }\n  let t55 = { }\n  let a57 = [ ]\n  let v58 = -2\n  let v60 = 3\n  let t59 = { f0=((v60) & (11)) }\n  let a61 = [ 4, 11, ]\n  let t62 = { }\n  let a64 = [ (((13 > 10 - 9)) ? ((6)) : (4)), ]\n  let v65 = (((7 != 8)) ? ((((-5 == -4)) ? (5) : (6))) : (2)) - 9\n  let a63 = [ 5, (a64?[0] ?? v65), ]\n  let t56 = { f0=-1 f1=(((((((a57?[0] ?? 7) == v58)) ? (11) : (2)) == ((-3 - (((((4) | (-4)) < ((1) & (3)))) ? (-4 - 10) : (13 - 467615902768935684))) & (10)))) ? ((t59?[\"f1\"] ?? ((5) & (10))) + (((((((10 >= 2)) ? (1) : ((a61?[1] ?? (t62?[\"f1\"] ?? 8))))) > 10 + 0 + (((10 == 6)) ? (9) : (2)))) ? (6) : ((-1)))) : ((a63?[1] ?? -2))) }\n  let a66 = [ ]\n  let t67 = { f0=2 }\n  let fni68 = @() 12\n  let v69 = 13\n  let fni70 = @() 8\n  let a71 = [ ]\n  let v72 = v60\n  let v74 = -2\n  let a73 = [ (v74), ]\n  let v76 = -3\n  let v75 = v76\n  let t78 = { }\n  let a79 = [ ]\n  let t80 = { }\n  let t81 = { }\n  let v82 = 8\n  {\n    local loop0 = 1\n    while (loop0++ < -4)\n    {\n      let v2 = (-3)\n      let v3 = 9\n      let a4 = [ ]\n      let v5 = (2)\n      let t1 = { f0=v2 f1=(v3 + (a4?[1] ?? -5 - v5)) }\n      continue\n      to_log(\"1\", t1.f1)\n      to_log(\"2\", v2)\n      to_log(\"3\", v3)\n      to_log(\"4\", a4)\n      to_log(\"5\", v5)\n      to_log(\"6\", t1)\n    }\n  }\n  {\n    local loop8 = (t6?.f0 ?? a7[0])\n    while (loop8++ < -1)\n    {\n      let gen11 = function () { yield 14; yield 7; yield 6; }\n      let t52 = { }\n      let a53 = [ 12 + -5, -3, ]\n      foreach (t9, t10 in gen11())\n      {\n          let v51 = (((t52?[\"f1\"] ?? (13))) & ((((a53?[1] ?? -1)) & (-5))))\n          break\n          to_log(\"7\", 1)\n          break\n          if (-2)\n          {\n              let v50 = v51\n              let fn12 = function fn12(p28, p30, p34) {\n                let fn13 = function fn13() {\n                  let v16 = {m0 = -5, m1 = 6, m2 = 11, }\n                  let fn17 = function fn17(p18) {\n                      to_log(\"8\", (((4 > 12)) ? (-4) : (11)))\n                      to_log(\"9\", 8)\n                      to_log(\"10\", 5 + p18)\n                      try\n                      {\n                          let v19 = 7\n                          to_log(\"11\", v19)\n                          to_log(\"12\", -3)\n                          to_log(\"13\", v19)\n                        }\n                      catch(err20)\n                      {\n                          to_log(\"14\", ((11) | (9)))\n                        }\n                    }\n                  foreach (t14, t15 in v16)\n                    fn17(7)\n                  to_log(\"15\", v16)\n                  to_log(\"16\", fn17)\n                }\n                let v22 = 6\n                let fni21 = @() ((v22) | (((9) & (10))))\n                let a25 = [ 1, ]\n                let v27 = (((-3 <= -5)) ? (2) : (v22))\n                let fni26 = @() v27\n                let v29 = -1\n                fn13()\n                {\n                  local loop23 = ((-4500801829576294150) | (fni21()))\n                  while (loop23++ < (a25?[0] ?? fni26()))\n                  {\n                    let a24 = [ ]\n                    to_log(\"17\", 7)\n                    to_log(\"18\", (a24?[1] ?? (-1)))\n                    to_log(\"19\", a24)\n                  }\n                }\n                to_log(\"20\", t10)\n                to_log(\"21\", -1 - p28)\n                if (v29)\n                  to_log(\"22\", 7)\n                else\n                {\n                    let fni49 = @() 12\n                    to_log(\"23\", p30)\n                    try\n                    {\n                        to_log(\"24\", 14)\n                        0/0\n                      }\n                    catch(err43)\n                    {\n                        let gen33 = function () { return 2; yield 13; yield 14; }\n                        let fn35 = function fn35() {\n                          let v37 = (((3 == -4)) ? (-1) : (3))\n                          let gen42 = function () { }\n                          for (local loop36 = 0; loop36 < v37; loop36++)\n                          {\n                              let fn38 = function fn38() {\n                                let v39 = 5\n                                to_log(\"29\", v39)\n                                to_log(\"30\", 5)\n                                to_log(\"31\", v39)\n                              }\n                              to_log(\"28\", -8447515169283609172)\n                              fn38()\n                              to_log(\"32\", fn38)\n                            }\n                          to_log(\"33\", 5)\n                          foreach (t40, t41 in gen42())\n                          {\n                              if (!((9 <= 2)))\n                              {\n                                  to_log(\"34\", -2)\n                                }\n                              to_log(\"35\", -1)\n                              if (!((-1 > 8)))\n                              {\n                                  to_log(\"36\", -1)\n                                  to_log(\"37\", (((14 == 13)) ? (-3) : (12)))\n                                  to_log(\"38\", 2)\n                                  to_log(\"39\", 0)\n                                  to_log(\"40\", 3)\n                                }\n                              to_log(\"41\", 13)\n                              to_log(\"42\", -3)\n                            }\n                          to_log(\"43\", 4)\n                          to_log(\"44\", v37)\n                          to_log(\"45\", gen42)\n                        }\n                        foreach (t31, t32 in gen33())\n                        {\n                            to_log(\"25\", p34)\n                            to_log(\"26\", 6)\n                            to_log(\"27\", ((11) | (-4)))\n                          }\n                        fn35()\n                        to_log(\"46\", gen33)\n                        to_log(\"47\", fn35)\n                      }\n                    for (local loop44 = 5; loop44 < 5; loop44++)\n                    {\n                        let t45 = { f0=-2 f1=14 }\n                        let fni46 = @() 3\n                        let a47 = [ -4, ]\n                        let v48 = 13\n                        to_log(\"48\", 11)\n                        to_log(\"49\", 5)\n                        to_log(\"50\", (((t45.f1)) & (fni46())) - (((2 != 5793629195146322613)) ? (14) : (8)))\n                        to_log(\"51\", (((a47[0] == 9)) ? (((787389375239146782 - 12) | (v48))) : (10)))\n                        to_log(\"52\", t45)\n                        to_log(\"53\", fni46)\n                        to_log(\"54\", a47)\n                        to_log(\"55\", v48)\n                      }\n                    to_log(\"56\", fni49())\n                    to_log(\"57\", fni49)\n                  }\n                to_log(\"58\", fn13)\n                to_log(\"59\", v22)\n                to_log(\"60\", fni21)\n                to_log(\"61\", a25)\n                to_log(\"62\", v27)\n                to_log(\"63\", fni26)\n                to_log(\"64\", v29)\n              }\n              fn12(3, ((v50) & (v50)), (13))\n              to_log(\"65\", 1)\n              to_log(\"66\", v50)\n              to_log(\"67\", fn12)\n            }\n          to_log(\"68\", v51)\n        }\n      to_log(\"69\", gen11)\n      to_log(\"70\", t52)\n      to_log(\"71\", a53)\n    }\n  }\n  {\n    local loop77 = (((11 == (t54?.f0 ?? 12))) ? ((t55?[\"f0\"] ?? 7)) : (((-1) & (((t56?[\"f1\"] ?? ((10) & (-3))) + (a66?[0] ?? (t67?[\"f0\"] ?? (((v65 < -4)) ? (-2) : (((13) | (6)))))) + fni68()))))) + (((v65 != v69)) ? ((((fni70() > (((-1 >= -2)) ? (0) : ((a71?[0] ?? v65))))) ? (-5) : (v72 - (a73?[1] ?? v75)))) : (-3))\n    do\n      to_log(\"72\", 11)\n    while (loop77++ < (t78?[\"f1\"] ?? ((5 - (((8 <= (a79?[0] ?? 14))) ? (-5) : (12)) + (((8 <= ((((t80?.f0 ?? -4) <= (t81?[\"f0\"] ?? -5))) ? (2) : (14)))) ? (10) : (6))) & (6))))\n  }\n  to_log(\"73\", -1)\n  {\n    local loop83 = (((11 >= (((v82) + 10) & (-5)))) ? (-6760683509134506842) : (2))\n    while (loop83++ < 11)\n    {\n      to_log(\"74\", 0)\n    }\n  }\n  to_log(\"75\", t6)\n  to_log(\"76\", a7)\n  to_log(\"77\", t54)\n  to_log(\"78\", t55)\n  to_log(\"79\", a57)\n  to_log(\"80\", v58)\n  to_log(\"81\", v60)\n  to_log(\"82\", t59)\n  to_log(\"83\", a61)\n  to_log(\"84\", t62)\n  to_log(\"85\", a64)\n  to_log(\"86\", v65)\n  to_log(\"87\", a63)\n  to_log(\"88\", t56)\n  to_log(\"89\", a66)\n  to_log(\"90\", t67)\n  to_log(\"91\", fni68)\n  to_log(\"92\", v69)\n  to_log(\"93\", fni70)\n  to_log(\"94\", a71)\n  to_log(\"95\", v72)\n  to_log(\"96\", v74)\n  to_log(\"97\", a73)\n  to_log(\"98\", v76)\n  to_log(\"99\", v75)\n  to_log(\"100\", t78)\n  to_log(\"101\", a79)\n  to_log(\"102\", t80)\n  to_log(\"103\", t81)\n  to_log(\"104\", v82)\n}} catch (q) {print(q)}\n\n"
  },
  {
    "path": "testData/exec/fuzzer_seed_106.out",
    "content": "69: function\n70: table\n71: array\n69: function\n70: table\n71: array\n69: function\n70: table\n71: array\n69: function\n70: table\n71: array\n72: 11\n73: -1\n74: 0\n74: 0\n74: 0\n74: 0\n74: 0\n74: 0\n74: 0\n74: 0\n74: 0\n75: table\n76: array\n77: table\n78: table\n79: array\n80: -2\n81: 3\n82: table\n83: array\n84: table\n85: array\n86: -3\n87: array\n88: table\n89: array\n90: table\n91: function\n92: 13\n93: function\n94: array\n95: 3\n96: -2\n97: array\n98: -3\n99: -3\n100: table\n101: array\n102: table\n103: table\n104: 8\n"
  },
  {
    "path": "testData/exec/fuzzer_seed_3250.nut",
    "content": "//#disable-optimizer\nlet v2 = 10\nlet v34 = -10\nlet v33 = (v2 > v34) ? v34 : 8\nprintln(v33)\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/fuzzer_seed_3250.out",
    "content": "-10\nok\n"
  },
  {
    "path": "testData/exec/fuzzer_seed_7200.nut",
    "content": "let v0 = -11\nif (v0 > v0) { }\nprint(v0)"
  },
  {
    "path": "testData/exec/fuzzer_seed_7200.out",
    "content": "-11"
  },
  {
    "path": "testData/exec/import_correct.nut",
    "content": "from \"math\" import sin, cos, abs\nfrom \"string\" import format, printf\nfrom \"io\" import *\nimport \"datetime\"\nimport \"debug\" as Debug\n\n// Test that keywords work as identifiers\nlocal import = 123\nlocal from = [1, 2, 3]\nfunction useKeywords() {\n    println(\"import value:\", import)\n    println(\"from length:\", from.len())\n}\n\nuseKeywords()\nprintln(sin(0), abs(-5))\n"
  },
  {
    "path": "testData/exec/import_correct.out",
    "content": "import value: 123\nfrom length: 3\n0 5\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_1.nut",
    "content": "#allow-compiler-internals\nlet a = $${return 123;}\nprintln(a)"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_1.out",
    "content": "123\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_2.nut",
    "content": "#allow-compiler-internals\nprintln($${return 123;})"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_2.out",
    "content": "123\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_3.nut",
    "content": "#allow-compiler-internals\nlet x = 555\nlet a = $${return 123;}\nlet y = 888\nprintln(x, a, y)"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_3.out",
    "content": "555 123 888\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_4.nut",
    "content": "#allow-compiler-internals\nlet a = 654 + $${return 123;}\nprintln(a)"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_4.out",
    "content": "777\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_5.nut",
    "content": "#allow-compiler-internals\nlet a = $${return 123;} + 654\nprintln(a)"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_5.out",
    "content": "777\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_6.nut",
    "content": "#allow-compiler-internals\nprintln(654 + $${return 123;})"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_6.out",
    "content": "777\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_7.nut",
    "content": "#allow-compiler-internals\nprintln($${return 123;} + 654)"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_7.out",
    "content": "777\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_8.nut",
    "content": "#allow-compiler-internals\nlet lam = @(a, b) $${ return a - b }\n\nlet xx = $${\n  let x = 4\n  function fn(a) { return $${return a != 4 ? a * 2 : 3} }\n  println(lam(fn(x), 100))\n}\nprintln(xx)\n"
  },
  {
    "path": "testData/exec/inexpr_block/inexpr_block_8.out",
    "content": "-97\nnull\n"
  },
  {
    "path": "testData/exec/inexpr_block/test_codeblock.nut",
    "content": "#allow-compiler-internals\nlet x = 0\n\ntry {\n\n  let a = $${\n    local t = 5 + x\n    if (t > 4)\n      t /= x\n    return t\n  }\n\n  println(a)\n\n} catch (e) {\n  println(e)\n}\n\n"
  },
  {
    "path": "testData/exec/inexpr_block/test_codeblock.out",
    "content": "division by zero\n"
  },
  {
    "path": "testData/exec/inexpr_block/test_codeblock_return_in_try.nut",
    "content": "#allow-compiler-internals\n\ntry {\n  let a = $${\n    return 42\n  }\n  println($\"a = {a}\")\n  assert(a == 42)\n} catch (e) {\n  println($\"caught: {e}\")\n}\nprintln(\"DONE\")\n"
  },
  {
    "path": "testData/exec/inexpr_block/test_codeblock_return_in_try.out",
    "content": "a = 42\nDONE\n"
  },
  {
    "path": "testData/exec/inexpr_block/test_codeblock_try.nut",
    "content": "#allow-compiler-internals\n\n// Test 1: simple return from CodeBlockExpr inside try\ntry {\n  let a = $${ return 42 }\n  assert(a == 42, $\"expected 42, got {a}\")\n} catch (e) {\n  assert(false, $\"unexpected exception: {e}\")\n}\n\n// Test 2: conditional return from CodeBlockExpr inside try\ntry {\n  let b = $${\n    local x = 10\n    if (x > 5)\n      return x * 2\n    return -1\n  }\n  assert(b == 20, $\"expected 20, got {b}\")\n} catch (e) {\n  assert(false, $\"unexpected exception: {e}\")\n}\n\n// Test 3: exception INSIDE CodeBlockExpr is caught by outer try\nlocal caught = false\ntry {\n  let c = $${\n    throw \"boom\"\n    return 0\n  }\n  assert(false, \"should not reach here\")\n} catch (e) {\n  caught = true\n  assert(e == \"boom\", $\"expected 'boom', got '{e}'\")\n}\nassert(caught, \"exception should have been caught\")\n\n// Test 4: try inside CodeBlockExpr\nlet d = $${\n  try {\n    throw \"inner\"\n    return -1\n  } catch (e) {\n    return 99\n  }\n}\nassert(d == 99, $\"expected 99, got {d}\")\n\n// Test 5: try inside CodeBlockExpr inside try\ntry {\n  let e = $${\n    try {\n      throw \"nested\"\n      return -1\n    } catch (ex) {\n      return 77\n    }\n  }\n  assert(e == 77, $\"expected 77, got {e}\")\n} catch (ex) {\n  assert(false, $\"unexpected exception: {ex}\")\n}\n\n// Test 6: foreach inside CodeBlockExpr inside try\ntry {\n  let f = $${\n    local sum = 0\n    foreach (v in [1, 2, 3, 4, 5])\n      sum += v\n    return sum\n  }\n  assert(f == 15, $\"expected 15, got {f}\")\n} catch (e) {\n  assert(false, $\"unexpected exception: {e}\")\n}\n\n// Test 7: null return from CodeBlockExpr inside try\ntry {\n  let g = $${ return null }\n  assert(g == null, $\"expected null, got {g}\")\n} catch (e) {\n  assert(false, $\"unexpected exception: {e}\")\n}\n\n// Test 8: bare return (no value) from CodeBlockExpr inside try\ntry {\n  let h = $${ return }\n  assert(h == null, $\"expected null, got {h}\")\n} catch (e) {\n  assert(false, $\"unexpected exception: {e}\")\n}\n\nprint(\"ALL CODEBLOCK+TRY TESTS PASSED\\n\")\n"
  },
  {
    "path": "testData/exec/inexpr_block/test_codeblock_try.out",
    "content": "ALL CODEBLOCK+TRY TESTS PASSED\n"
  },
  {
    "path": "testData/exec/integers.nut",
    "content": "assert(0x0 == 0)\nassert(0x1 == 1)\nassert(0xf == 15)\nassert(0x0F == 15)\nassert(0x00F == 15)\nassert(0x000F == 15)\nassert(0x0000F == 15)\nassert(0x00000F == 15)\nassert(0x000000F == 15)\nassert(0x0000000F == 15)\nassert(0x00000000F == 15)\nassert(0x000000000F == 15)\nassert(0x0000000000F == 15)\nassert(0x00000000000F == 15)\nassert(0x000000000000F == 15)\nassert(0x0000000000000F == 15)\nassert(0x00000000000000F == 15)\nassert(0x000000000000000F == 15)\nassert(0x00000_0000000_000F == 15)\nassert(0x_____________________________________________________________________________________________________________________F == 15)\nassert(0xf0123456789aBcDE == -1147797409030816546)\nassert(99999999999999999 + 1234567890 == 100000001234567889)\nassert('A' == 65)\nassert('\\t' == 9)\nassert(' ' == 32)\nassert(\"\\U12\"[0] == 0x12)\nassert(\"\\U7F\"[0] == 0x7F)\nassert(~0 == -1)\nassert(~1 == -2)\nassert(0xFFFFFFFFFFFFFFFE == -2)\nassert(0x8000000000000000 == -9223372036854775807 - 1)\nassert(100 + 10 + 1 == 111)\nassert(111 - 10 - 1 == 100)\nassert(100 * 10 * 1 == 1000)\nassert(100 / 10 / 1 == 10)\nassert(101 % 10 % 1 == 0)\n\nlocal a100 = 100\nlocal a10 = 10\nlet a1 = a10 / 10\nlocal a111 = a100 + a1 + a10\nlocal a101 = a100 + a1\n\nassert(a100 + a10 + a1 == 111)\nassert(a111 - a10 - a1 == a100)\nassert(a100 * a10 * a1 == 1000)\nassert(a100 / a10 / a1 == a10)\nassert(a101 % a10 % a1 == 0)\n\nassert((100 << 10 << 1) == 100 * 1024 * 2)\nassert((100 >> 1) == 50)\nassert((0x8000000000000000 >>> 63) == 1)\nassert(0x0000000000000000.tostring() == \"0\")\nassert(0x8000000000000000.tostring() == \"-9223372036854775808\")\nassert(0x7FFFFFFFFFFFFFFF.tostring() == \"9223372036854775807\")\nassert(0x8000000000000000 == \"-9223372036854775808\".tointeger())\nassert(0x7FFFFFFFFFFFFFFF == \"9223372036854775807\".tointeger())\nassert((true).tointeger() == 1)\nassert((false).tointeger() == 0)\nassert(!!0x8000000000000000 == true)\nassert(!!0x0000000000000000 == false)\nassert(0x8000000000000000 + 0x8000000000000001 == 1)\n\nassert([11 12 13][2] == 13)\nassert([11,12,-13][2] == -13)\nassert([11,12 13][2] == 13)\nassert([11,12 13,][2] == 13)\nassert([11 12 - 13][1] == -1)\n\nlocal a = 1\nassert((a *= -10) == -10)\nassert((a *= -10) == 100)\nassert((a *= -10) == -1000)\nassert((a *= -10) == 10000)\nassert((a *= -10) == -100000)\nassert((a *= -10) == 1000000)\nassert((a *= -10) == -10000000)\nassert((a *= -10) == 100000000)\nassert((a *= -10) == -1000000000)\nassert((a *= -10) == 10000000000)\nassert((a *= -10) == -100000000000)\n"
  },
  {
    "path": "testData/exec/integers.out",
    "content": ""
  },
  {
    "path": "testData/exec/is_frozen.nut",
    "content": "\n\nlet a1 = [10, 20, 30]\nlet a2 = freeze([10, 20, 30])\n\nprintln($\"Array R: {a1.is_frozen()}\")\nprintln($\"Array F: {a2.is_frozen()}\")\n\n\nlet t1 = { a = 10, b = 20, c = 30 }\nlet t2 = freeze({ a = 10, b = 20, c = 30 })\n\nprintln($\"Table R: {t1.is_frozen()}\")\nprintln($\"Table F: {t2.is_frozen()}\")\n\n\nlet C = class {}\nlet F  = freeze(class {})\n\nprintln($\"Class R: {C.is_frozen()}\")\nprintln($\"Class F: {F.is_frozen()}\")\n\n\nlet ri = C()\nlet fi = freeze(C())\n\nprintln($\"Instance R: {ri.is_frozen()}\")\nprintln($\"Instance F: {fi.is_frozen()}\")\n\n\nlet ai = freeze([{}, {}])\nforeach(i, v in ai) println($\"Array foreach {i}: {v.is_frozen()}\")\nai.each(@(v, i) println($\"Array each {i}: {v.is_frozen()}\"))\n\n\nlet ti = freeze({[{a=1}]={}, [{a=2}]={}})\nforeach(k, v in ti) println($\"Table foreach: {k.is_frozen()} {v.is_frozen()}\")\nti.each(@(v, k) println($\"Table each: {k.is_frozen()} {v.is_frozen()}\"))\n"
  },
  {
    "path": "testData/exec/is_frozen.out",
    "content": "Array R: false\nArray F: true\nTable R: false\nTable F: true\nClass R: false\nClass F: true\nInstance R: false\nInstance F: true\nArray foreach 0: true\nArray foreach 1: true\nArray each 0: true\nArray each 1: true\nTable foreach: true true\nTable foreach: true true\nTable each: true true\nTable each: true true\n"
  },
  {
    "path": "testData/exec/locals_chain.nut",
    "content": "local a=5, b=a, c=a, d=b\nprintln($\"{a}, {b}, {c}, {d}\")\n\nlet x=6, y=x, z=x, w=y\nprintln($\"{x}, {y}, {z}, {w}\")\n"
  },
  {
    "path": "testData/exec/locals_chain.out",
    "content": "5, 5, 5, 5\n6, 6, 6, 6\n"
  },
  {
    "path": "testData/exec/metamethod_error.nut",
    "content": "class SetThrows {\n  function _set(key, val) {\n    throw \"Not supported\"\n  }\n}\n\nclass GetThrows {\n  function _get(key) {\n    throw \"Read denied\"\n  }\n}\n\nclass ThrowsNonString {\n  function _set(key, val) {\n    throw 42\n  }\n}\n\n// Test _set string error\ntry {\n  let x = SetThrows()\n  x.foo = 123\n  assert(false, \"should have thrown\")\n} catch (e) {\n  assert(e == \"Error in '_set' metamethod: Not supported\", $\"unexpected: {e}\")\n}\n\n// Test _get string error\ntry {\n  let x = GetThrows()\n  let _ = x.foo\n  assert(false, \"should have thrown\")\n} catch (e) {\n  assert(e == \"Error in '_get' metamethod: Read denied\", $\"unexpected: {e}\")\n}\n\n// Test non-string error object\ntry {\n  let x = ThrowsNonString()\n  x.foo = 123\n  assert(false, \"should have thrown\")\n} catch (e) {\n  assert(e == \"Error in '_set' metamethod: '42' (type='integer')\", $\"unexpected: {e}\")\n}\n\nprintln(\"ALL PASSED\")\n"
  },
  {
    "path": "testData/exec/metamethod_error.out",
    "content": "ALL PASSED\n"
  },
  {
    "path": "testData/exec/mod64_by_minus_one_opt.nut",
    "content": "print( (-0x7FFFFFFF_FFFFFFFF-1) % -1 )\n"
  },
  {
    "path": "testData/exec/mod64_by_minus_one_opt.out",
    "content": "0"
  },
  {
    "path": "testData/exec/mod64_by_minus_one_vm.nut",
    "content": "local x = -0x7FFFFFFF_FFFFFFFF - 1\nlocal y = @(a) -a\nprint( x % y(1) )\n"
  },
  {
    "path": "testData/exec/mod64_by_minus_one_vm.out",
    "content": "0"
  },
  {
    "path": "testData/exec/mod_by_minus_one_opt.nut",
    "content": "print( (-0x7FFFFFFF-1) % -1 )\n"
  },
  {
    "path": "testData/exec/mod_by_minus_one_opt.out",
    "content": "0"
  },
  {
    "path": "testData/exec/mod_by_minus_one_vm.nut",
    "content": "local x = -0x7FFFFFFF - 1\nlocal y = @(a) -a\nprint( x % y(1) )\n"
  },
  {
    "path": "testData/exec/mod_by_minus_one_vm.out",
    "content": "0"
  },
  {
    "path": "testData/exec/native_fields.nut",
    "content": "// Test native field access (MEMBER_TYPE_NATIVE_FIELD)\n// NativeVec has float x,y,z and int32 w as native fields\n\nfrom \"test.native\" import NativeVec\n\n// Basic read after construction\nlocal v = NativeVec(1.0, 2.0, 3.0, 42)\nprintln($\"construct: {v.x} {v.y} {v.z} {v.w}\")\n\n// Write float fields\nv.x = 10.0\nv.y = 20.0\nv.z = 30.0\nprintln($\"write float: {v.x} {v.y} {v.z}\")\n\n// Write int field\nv.w = 100\nprintln($\"write int: {v.w}\")\n\n// Type coercion: assign int to float field\nv.x = 7\nprintln($\"int to float: {v.x}\")\n\n// Type coercion: assign float to int field\nv.w = 3.14\nprintln($\"float to int: {v.w}\")\n\n// Default construction (zeros)\nlocal v2 = NativeVec()\nprintln($\"default: {v2.x} {v2.y} {v2.z} {v2.w}\")\n\n// Multiple instances are independent\nv.x = 100.0\nprintln($\"independent: {v.x} {v2.x}\")\n\n// _tostring works alongside native fields\nprintln(v2.tostring())\n\n// Increment on int native field\nv.w = 5\nv.w++\nprintln($\"w after ++: {v.w}\")\nv.w--\nprintln($\"w after --: {v.w}\")\n\n// Increment on float native field\nv.x = 1.5\nv.x++\nprintln($\"x after ++: {v.x}\")\nv.x--\nprintln($\"x after --: {v.x}\")\n\n// Compound assignment\nv.w = 10\nv.w += 5\nprintln($\"w after +=5: {v.w}\")\nv.x = 2.0\nv.x *= 3.0\nprintln($\"x after *=3: {v.x}\")\n\n// Clone copies native field values\nv.x = 11.0\nv.y = 22.0\nv.z = 33.0\nv.w = 44\nlocal vc = clone v\nprintln($\"clone: {vc.x} {vc.y} {vc.z} {vc.w}\")\nvc.x = 0.0\nprintln($\"clone independent: {v.x} {vc.x}\")\n\n// foreach over instance reads native fields\nlocal v3 = NativeVec(1.0, 2.0, 3.0, 99)\nlocal keys = []\nlocal vals = []\nforeach (k, val in v3) {\n  keys.append(k)\n  vals.append(val)\n}\n// Native fields should appear in enumeration\nprintln($\"foreach has x: {keys.indexof(\"x\") != null}\")\nprintln($\"foreach has w: {keys.indexof(\"w\") != null}\")\nprintln($\"foreach x val: {vals[keys.indexof(\"x\")]}\")\nprintln($\"foreach w val: {vals[keys.indexof(\"w\")]}\")\n\n// 'in' operator\nprintln($\"x in v: {\"x\" in v}\")\nprintln($\"w in v: {\"w\" in v}\")\nprintln($\"q in v: {\"q\" in v}\")\n\n// Non-literal key access (goes through _OP_GET/_OP_SET, not _OP_GET_LITERAL/_OP_SET_LITERAL)\nlocal key = \"x\"\nv[key] = 77.0\nprintln($\"non-literal get: {v[key]}\")\n\n// Type mismatch errors\n// Literal path (_OP_SET_LITERAL)\ntry { v.x = \"hello\" } catch(e) println($\"err literal: {e}\")\n// Non-literal path (_OP_SET)\ntry { local k = \"x\"; v[k] = \"hello\" } catch(e) println($\"err non-literal: {e}\")\n// Null assignment\ntry { v.x = null } catch(e) println($\"err null: {e}\")\n\nprintln(\"PASSED\")\n"
  },
  {
    "path": "testData/exec/native_fields.out",
    "content": "construct: 1 2 3 42\nwrite float: 10 20 30\nwrite int: 100\nint to float: 7\nfloat to int: 3\ndefault: 0 0 0 0\nindependent: 100 0\nNativeVec(0, 0, 0, 0)\nw after ++: 6\nw after --: 5\nx after ++: 2.5\nx after --: 1.5\nw after +=5: 15\nx after *=3: 6\nclone: 11 22 33 44\nclone independent: 11 0\nforeach has x: true\nforeach has w: true\nforeach x val: 1\nforeach w val: 99\nx in v: true\nw in v: true\nq in v: false\nnon-literal get: 77\nerr literal: type mismatch in native field assignment\nerr non-literal: type mismatch in native field assignment\nerr null: type mismatch in native field assignment\nPASSED\n"
  },
  {
    "path": "testData/exec/opt/fuzz_52807_min.nut",
    "content": "local v1 = -111\nv1 = 12\nlocal loop2 = v1 - v1\nprintln(v1)\nprintln(loop2)\n"
  },
  {
    "path": "testData/exec/opt/fuzz_52807_min.out",
    "content": "12\n0\n"
  },
  {
    "path": "testData/exec/opt/fuzz_min.nut",
    "content": "local v1 = -111\nv1 = 3\nlocal loop2 = v1 - -5 + 12\nprintln(v1)\nprintln(loop2)\n"
  },
  {
    "path": "testData/exec/opt/fuzz_min.out",
    "content": "3\n20\n"
  },
  {
    "path": "testData/exec/opt/modify_local_var.nut",
    "content": "//#disable-optimizer\nlocal cnt1 = 11\ncnt1 = 222\ncnt1 -= cnt1 / 3333\nprintln(cnt1)\n"
  },
  {
    "path": "testData/exec/opt/modify_local_var.out",
    "content": "222\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_addi.nut",
    "content": "// Test: reassigned local used in ADDI fold (2-instruction fold: LOAD, ADDI)\n// The peephole folds LOADINT+MOVE into LOADINT targeting the local's register.\n// The ADDI fold must not replace that LOADINT with a result targeting a different register.\n\n// Pattern: local x = A; x = B; local y = x + C + D\n// After peephole: LOADINT x_reg B, ADDI y_reg C x_reg, ADDI y_reg D y_reg\n// The first ADDI fold must not destroy x's value.\n\n{\n  local v1 = -111\n  v1 = 3\n  local loop2 = v1 - -5 + 12\n  assert(v1 == 3, $\"expected v1==3, got {v1}\")\n  assert(loop2 == 20, $\"expected loop2==20, got {loop2}\")\n}\n\n{\n  local a = 100\n  a = 5\n  local b = a + 10\n  assert(a == 5, $\"expected a==5, got {a}\")\n  assert(b == 15, $\"expected b==15, got {b}\")\n}\n\n{\n  local a = 100\n  a = 5\n  local b = a + 10 + 20\n  assert(a == 5, $\"expected a==5, got {a}\")\n  assert(b == 35, $\"expected b==35, got {b}\")\n}\n\n// Chain of ADDI folds\n{\n  local x = -1\n  x = 7\n  local y = x + 1 + 2 + 3\n  assert(x == 7, $\"expected x==7, got {x}\")\n  assert(y == 13, $\"expected y==13, got {y}\")\n}\n\n// Negative immediates\n{\n  local x = 999\n  x = 20\n  local y = x - 5 - 3\n  assert(x == 20, $\"expected x==20, got {x}\")\n  assert(y == 12, $\"expected y==12, got {y}\")\n}\n\nprintln(\"opt_reassign_addi: OK\")\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_addi.out",
    "content": "opt_reassign_addi: OK\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_arith.nut",
    "content": "// Test: reassigned local used in arithmetic (3-instruction fold: LOAD, LOAD, ARITH)\n// The peephole optimizer merges LOADINT+MOVE into a dual-purpose LOADINT.\n// The post-pass const folder must not destroy the reassignment side effect.\n\n// Pattern: local x = A; x = B; x -= x / C\n// After peephole: LOADINT reg B (also assigns x), LOADINT tmp C, DIV, SUB\n// The fold must preserve x = B.\n{\n  local x = 11\n  x = 222\n  x -= x / 3333\n  assert(x == 222, $\"expected 222, got {x}\")\n}\n\n// Same with addition\n{\n  local x = 99\n  x = 10\n  x += x / 5\n  assert(x == 12, $\"expected 12, got {x}\")\n}\n\n// Same with multiplication\n{\n  local x = 99\n  x = 7\n  x *= x + 1\n  // Can't fold x*x at compile time, but ensure x==7\n  assert(x == 56, $\"expected 56, got {x}\")\n}\n\n// Reassign then binary op where result goes to different register\n{\n  local x = 50\n  x = 10\n  local y = x + 5\n  assert(x == 10, $\"expected x==10, got {x}\")\n  assert(y == 15, $\"expected y==15, got {y}\")\n}\n\n// Reassign then binary op with two constants after peephole\n{\n  local x = 50\n  x = 10\n  local y = x * 3 + 1\n  assert(x == 10, $\"expected x==10, got {x}\")\n  assert(y == 31, $\"expected y==31, got {y}\")\n}\n\nprintln(\"opt_reassign_arith: OK\")\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_arith.out",
    "content": "opt_reassign_arith: OK\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_chain.nut",
    "content": "// Test: chained constant expressions after reassignment.\n// Ensures multi-step folding doesn't lose intermediate assignments.\n\n// Two-step chain: x = B; y = x op const1 op const2\n{\n  local x = 100\n  x = 5\n  local y = x + 10 + 20\n  assert(x == 5, $\"expected x==5, got {x}\")\n  assert(y == 35, $\"expected y==35, got {y}\")\n}\n\n// Subtraction chain\n{\n  local x = 100\n  x = 50\n  local y = 100 - x - 10\n  assert(x == 50, $\"expected x==50, got {x}\")\n  assert(y == 40, $\"expected y==40, got {y}\")\n}\n\n// Mixed operations\n{\n  local a = 0\n  a = 6\n  local b = 0\n  b = 7\n  local c = a + b\n  assert(a == 6, $\"expected a==6, got {a}\")\n  assert(b == 7, $\"expected b==7, got {b}\")\n  assert(c == 13, $\"expected c==13, got {c}\")\n}\n\n// Multiple reassignments before use\n{\n  local x = 1\n  x = 2\n  x = 3\n  local y = x + 10\n  assert(x == 3, $\"expected x==3, got {x}\")\n  assert(y == 13, $\"expected y==13, got {y}\")\n}\n\n// Reassign used in comparison (JCMP fold path)\n{\n  local x = 100\n  x = 5\n  local r = x < 10\n  assert(x == 5, $\"expected x==5, got {x}\")\n  assert(r, $\"expected x < 10 to be true\")\n}\n\n// Reassign with float\n{\n  local x = 1.0\n  x = 3.0\n  local y = x + 1.0\n  assert(x == 3.0, $\"expected x==3.0, got {x}\")\n  assert(y == 4.0, $\"expected y==4.0, got {y}\")\n}\n\n// Reassign float, same-register fold\n{\n  local x = 1.0\n  x = 5.0\n  local y = x - x\n  assert(x == 5.0, $\"expected x==5.0, got {x}\")\n  assert(y == 0.0, $\"expected y==0.0, got {y}\")\n}\n\n// JCMP same-register: both sides of comparison are the same reassigned variable (seed 916086 pattern)\n{\n  local v0 = -111\n  v0 = -3\n  if (v0 >= v0)\n    assert(true, \"v0 >= v0 should be true\")\n  else\n    assert(false, \"v0 >= v0 was false - optimizer used stale register value\")\n}\n\n// JCMP same-register with different initial value\n{\n  local v0 = 999\n  v0 = 42\n  if (v0 == v0)\n    assert(true, \"v0 == v0 should be true\")\n  else\n    assert(false, \"v0 == v0 was false\")\n}\n\n// JCMP same-register: less-than (always false for same value)\n{\n  local v0 = 100\n  v0 = 7\n  if (v0 < v0)\n    assert(false, \"v0 < v0 should be false\")\n  else\n    assert(true, \"v0 < v0 is correctly false\")\n}\n\nprintln(\"opt_reassign_chain: OK\")\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_chain.out",
    "content": "opt_reassign_chain: OK\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_in_scope.nut",
    "content": "// Test: reassigned locals used across nested scopes and control flow.\n// Ensures optimizer respects liveness in more complex code patterns.\n\n// Reassign inside block, use after\n{\n  local x = 10\n  x = 20\n  local y = x + 1\n  if (y > 0) {\n    assert(x == 20, $\"expected x==20, got {x}\")\n  }\n  assert(y == 21, $\"expected y==21, got {y}\")\n}\n\n// Reassign, use in loop init\n{\n  local x = 100\n  x = 3\n  local sum = 0\n  for (local i = x + 1; i < 10; i++)\n    sum += i\n  assert(x == 3, $\"expected x==3, got {x}\")\n  assert(sum == 4+5+6+7+8+9, $\"expected sum==39, got {sum}\")\n}\n\n// Reassign, use in function call argument\n{\n  local x = 50\n  x = 7\n  local arr = [x + 1, x + 2, x + 3]\n  assert(x == 7, $\"expected x==7, got {x}\")\n  assert(arr[0] == 8, $\"expected arr[0]==8, got {arr[0]}\")\n  assert(arr[1] == 9, $\"expected arr[1]==9, got {arr[1]}\")\n  assert(arr[2] == 10, $\"expected arr[2]==10, got {arr[2]}\")\n}\n\n// Multiple locals reassigned\n{\n  local a = 1\n  local b = 2\n  a = 10\n  b = 20\n  local c = a + b\n  assert(a == 10, $\"expected a==10, got {a}\")\n  assert(b == 20, $\"expected b==20, got {b}\")\n  assert(c == 30, $\"expected c==30, got {c}\")\n}\n\n// Reassign with compound expression using self\n{\n  local x = 100\n  x = 8\n  x = x + 2  // x should be 10\n  local y = x + 5\n  assert(x == 10, $\"expected x==10, got {x}\")\n  assert(y == 15, $\"expected y==15, got {y}\")\n}\n\nprintln(\"opt_reassign_in_scope: OK\")\n"
  },
  {
    "path": "testData/exec/opt/opt_reassign_in_scope.out",
    "content": "opt_reassign_in_scope: OK\n"
  },
  {
    "path": "testData/exec/opt/opt_same_reg_fold.nut",
    "content": "// Test: both loads in 3-instruction fold target the same register.\n// When loadA and loadB write to the same register, loadA's value is dead\n// (overwritten by loadB). The optimizer must not use loadA's stale value.\n\n// Pattern: local x = A; x = B; local y = x - x\n// After peephole: LOADINT reg A, LOADINT reg B, SUB y_reg reg reg\n// Both loads target the same register. Result must be B - B = 0, not A - B.\n\n{\n  local v1 = -111\n  v1 = 12\n  local loop2 = v1 - v1\n  assert(v1 == 12, $\"expected v1==12, got {v1}\")\n  assert(loop2 == 0, $\"expected loop2==0, got {loop2}\")\n}\n\n{\n  local x = 99\n  x = 5\n  local y = x + x\n  assert(x == 5, $\"expected x==5, got {x}\")\n  assert(y == 10, $\"expected y==10, got {y}\")\n}\n\n{\n  local x = 99\n  x = 7\n  local y = x * x\n  assert(x == 7, $\"expected x==7, got {x}\")\n  assert(y == 49, $\"expected y==49, got {y}\")\n}\n\n// Division by self\n{\n  local x = 50\n  x = 13\n  local y = x / x\n  assert(x == 13, $\"expected x==13, got {x}\")\n  assert(y == 1, $\"expected y==1, got {y}\")\n}\n\n// Modulo by self\n{\n  local x = 50\n  x = 13\n  local y = x % x\n  assert(x == 13, $\"expected x==13, got {x}\")\n  assert(y == 0, $\"expected y==0, got {y}\")\n}\n\n// Bitwise XOR with self\n{\n  local x = 50\n  x = 0xFF\n  local y = x ^ x\n  assert(x == 0xFF, $\"expected x==255, got {x}\")\n  assert(y == 0, $\"expected y==0, got {y}\")\n}\n\n// Bitwise AND with self\n{\n  local x = 50\n  x = 0xAB\n  local y = x & x\n  assert(x == 0xAB, $\"expected x==171, got {x}\")\n  assert(y == 0xAB, $\"expected y==171, got {y}\")\n}\n\nprintln(\"opt_same_reg_fold: OK\")\n"
  },
  {
    "path": "testData/exec/opt/opt_same_reg_fold.out",
    "content": "opt_same_reg_fold: OK\n"
  },
  {
    "path": "testData/exec/opt/sqf916086.nut",
    "content": "//#disable-optimizer\n// seed = 916086\ntry{\nlocal count = 0\nlet to_log = function(id, s) { let tp = typeof(s); print($\"{id}: \"); print(tp == \"integer\" || tp == \"float\" || tp == \"string\" ? s : tp); print(\"\\n\"); if (count++ > 1000) print[\"stop\"]; }\n{\n  local v0 = -111\n  v0 = -3\n  if (v0 >= v0)\n    to_log(\"1\", 8)\n}} catch (q) {print(q)}\nprint(\"===\\n\")"
  },
  {
    "path": "testData/exec/opt/sqf916086.out",
    "content": "1: 8\n===\n"
  },
  {
    "path": "testData/exec/optimizer.nut",
    "content": "println(\"OPTIMIZER OFF\")\n\nfunction test_opt_off() {\n  #disable-optimizer\n  for (local i = 0; i < (true ? 5 : 1); i++)\n    println(\"X\")\n}\n\ntest_opt_off()\n\n\nprintln(\"OPTIMIZER ON\")\n\nfunction test_opt_on() {\n  #enable-optimizer\n  for (local i = 0; i < (true ? 5 : 1); i++)\n    println(\"X\")\n}\n\ntest_opt_on()\n"
  },
  {
    "path": "testData/exec/optimizer.out",
    "content": "OPTIMIZER OFF\nX\nX\nX\nX\nX\nOPTIMIZER ON\nX\nX\nX\nX\nX\n"
  },
  {
    "path": "testData/exec/optimizer_add.nut",
    "content": "let x = 0x7FFF_FFFF\nlet y = 0x1\nassert(x + y == 0x8000_0000)\nassert(0x7FFF_FFFF + 0x1 == 0x8000_0000)\n"
  },
  {
    "path": "testData/exec/optimizer_add.out",
    "content": ""
  },
  {
    "path": "testData/exec/optimizer_mul.nut",
    "content": "let x = 0x100_0000\nlet y = 0x100\nassert(x * y == 0x1_0000_0000)\nassert(0x100_0000 * 0x100 == 0x1_0000_0000)\n"
  },
  {
    "path": "testData/exec/optimizer_mul.out",
    "content": ""
  },
  {
    "path": "testData/exec/parenCallee.nut",
    "content": "\nlet f = @(v) v + 1\n\nfunction foo() {\n    return ((((f))))(10)\n}"
  },
  {
    "path": "testData/exec/parenCallee.out",
    "content": ""
  },
  {
    "path": "testData/exec/ph_optimizer_null_call_1.nut",
    "content": "let x = [@() 444]\nlet z = 0\nprintln(x[z]?())\n"
  },
  {
    "path": "testData/exec/ph_optimizer_null_call_1.out",
    "content": "444\n"
  },
  {
    "path": "testData/exec/ph_optimizer_null_call_2.nut",
    "content": "let tab = {\n  x = [ @() 444 ]\n}\n\nlocal zero = 0\nprintln(tab?.x[zero]())\n\n"
  },
  {
    "path": "testData/exec/ph_optimizer_null_call_2.out",
    "content": "444\n"
  },
  {
    "path": "testData/exec/ph_optimizer_null_call_3.nut",
    "content": "let x = [[[[@() 444]]]]\nlet z = 0\nprintln(x?[z][z][z][z]())\n\n"
  },
  {
    "path": "testData/exec/ph_optimizer_null_call_3.out",
    "content": "444\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_01.nut",
    "content": "let x = [4.0][0]\nlet y: float = x\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_01.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_02.nut",
    "content": "local y: table|null = null\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_02.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_03.nut",
    "content": "local y: array = []\ny.append(333)\ny = []\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_03.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_04.nut",
    "content": "local y: int = 5\ny = 8\ny += 4\nprintln(y)\n\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_04.out",
    "content": "12\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_05.nut",
    "content": "local y: array = []\n\nfunction fn() {\n    y.append(333)\n    y = []\n}\n\nfn()\n\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_05.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_06.nut",
    "content": "local y: int = 5\n\nfunction fn() {\n    y = 8\n    y += 4\n}\n\nfn()\n\nprintln(y)\n\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_06.out",
    "content": "12\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_07.nut",
    "content": "let arr = [{}]\nlet [y: table] = arr\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_07.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_08.nut",
    "content": "let tab = { x = \"ttt\" }\nlet { x: string|null } = tab\nreturn x\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_08.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_09.nut",
    "content": "let arr = [{x = 5}]\nlet [y: table = {}] = arr\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_09.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_10.nut",
    "content": "local x = {}\n\nfunction fn(x, v: string|table = x) {\n    return v\n}\n\nfn(0, \"123\")\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_type_10.out",
    "content": ""
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_01.nut",
    "content": "let x = [4.0][0]\nlet y: table = x\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_01.out",
    "content": "\nAN ERROR HAS OCCURRED [type 'float' differs from the declared type 'table']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/exec/runtime_type_check/assign_wrong_type_01.nut:2\n\nLOCALS\n[x] 4\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/assign_wrong_type_01.nut (testData/exec/runtime_type_check/assign_wrong_type_01.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_02.nut",
    "content": "local y: table|null = 4\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_02.out",
    "content": "ERROR: expression of type 'int' cannot be assigned to type 'table|null'\ntestData/exec/runtime_type_check/assign_wrong_type_02.nut:1:0\n\nlocal y: table|null = 4\n^----------------------\nreturn y\n\n\nError [Failed to compile file testData/exec/runtime_type_check/assign_wrong_type_02.nut (testData/exec/runtime_type_check/assign_wrong_type_02.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_03.nut",
    "content": "local y: array = []\ny.append(333)\ny = {}\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_03.out",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'array'\ntestData/exec/runtime_type_check/assign_wrong_type_03.nut:3:0\n\ny.append(333)\ny = {}\n^\nreturn y\n\n\nError [Failed to compile file testData/exec/runtime_type_check/assign_wrong_type_03.nut (testData/exec/runtime_type_check/assign_wrong_type_03.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_04.nut",
    "content": "local y: int = 5\ny = 8\ny += 4.5\nprintln(y)\n\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_04.out",
    "content": "\nAN ERROR HAS OCCURRED [type 'float' differs from the declared type 'int']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/exec/runtime_type_check/assign_wrong_type_04.nut:3\n\nLOCALS\n[y] 12.5\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/assign_wrong_type_04.nut (testData/exec/runtime_type_check/assign_wrong_type_04.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_05.nut",
    "content": "local y: array = []\n\nfunction fn() {\n    y.append(333)\n    y = {}\n}\n\nfn()\n\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_05.out",
    "content": "ERROR: expression of type 'table' cannot be assigned to type 'array'\ntestData/exec/runtime_type_check/assign_wrong_type_05.nut:5:4\n\n    y.append(333)\n    y = {}\n    ^\n}\n\n\nError [Failed to compile file testData/exec/runtime_type_check/assign_wrong_type_05.nut (testData/exec/runtime_type_check/assign_wrong_type_05.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_06.nut",
    "content": "local y: int = 5\n\nfunction fn() {\n    y = 8\n    y += 4.5\n}\n\nfn()\n\nprintln(y)\n\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_06.out",
    "content": "\nAN ERROR HAS OCCURRED [type 'float' differs from the declared type 'int']\n\nCALLSTACK\n*FUNCTION [fn()] testData/exec/runtime_type_check/assign_wrong_type_06.nut:5\n*FUNCTION [__main__()] testData/exec/runtime_type_check/assign_wrong_type_06.nut:10\n\nLOCALS\n[y] 8\n[this] NULL\n[fn] CLOSURE=FN:fn\n[y] 8\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/assign_wrong_type_06.nut (testData/exec/runtime_type_check/assign_wrong_type_06.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_07.nut",
    "content": "let arr = [4.0]\nlet [y: table] = arr\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_07.out",
    "content": "\nAN ERROR HAS OCCURRED [type 'float' differs from the declared type 'table']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/exec/runtime_type_check/assign_wrong_type_07.nut:2\n\nLOCALS\n[y] 4\n[arr] ARRAY=[4]\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/assign_wrong_type_07.nut (testData/exec/runtime_type_check/assign_wrong_type_07.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_08.nut",
    "content": "let tab = { x = 4.0 }\nlet { x: string|null } = tab\nreturn x\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_08.out",
    "content": "\nAN ERROR HAS OCCURRED [type 'float' differs from the declared type 'string|null']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/exec/runtime_type_check/assign_wrong_type_08.nut:2\n\nLOCALS\n[x] 4\n[tab] TABLE={x=4}\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/assign_wrong_type_08.nut (testData/exec/runtime_type_check/assign_wrong_type_08.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_09.nut",
    "content": "let arr = [4.0]\nlet [y: table = \"test\"] = arr\nreturn y\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_09.out",
    "content": "ERROR: expression of type 'string' cannot be assigned to type 'table'\ntestData/exec/runtime_type_check/assign_wrong_type_09.nut:2:5\n\nlet arr = [4.0]\nlet [y: table = \"test\"] = arr\n     ^----------------\nreturn y\n\n\nError [Failed to compile file testData/exec/runtime_type_check/assign_wrong_type_09.nut (testData/exec/runtime_type_check/assign_wrong_type_09.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_10.nut",
    "content": "local x = null\n\nfunction fn(x, v: string|table = x) {\n    return v\n}\n\nfn(0, \"123\")\n"
  },
  {
    "path": "testData/exec/runtime_type_check/assign_wrong_type_10.out",
    "content": "\nAN ERROR HAS OCCURRED [default param (2) type 'null' differs from the declared type 'string|table']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/exec/runtime_type_check/assign_wrong_type_10.nut:3\n\nLOCALS\n[x] NULL\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/assign_wrong_type_10.nut (testData/exec/runtime_type_check/assign_wrong_type_10.nut)]\n"
  },
  {
    "path": "testData/exec/runtime_type_check/return_type.nut",
    "content": "\nfunction fn(x: int, y: any): int {\n    return x * y\n}\n\nprintln(fn(5, 2))\n"
  },
  {
    "path": "testData/exec/runtime_type_check/return_type.out",
    "content": "10\n"
  },
  {
    "path": "testData/exec/runtime_type_check/return_wrong_type.nut",
    "content": "\nfunction fn(x: int, y: any): int {\n    return x * y\n}\n\nprintln(fn(5, 1.25))\n"
  },
  {
    "path": "testData/exec/runtime_type_check/return_wrong_type.out",
    "content": "\nAN ERROR HAS OCCURRED [type 'float' differs from the declared type 'int']\n\nCALLSTACK\n*FUNCTION [fn()] testData/exec/runtime_type_check/return_wrong_type.nut:3\n*FUNCTION [__main__()] testData/exec/runtime_type_check/return_wrong_type.nut:6\n\nLOCALS\n[y] 1.25\n[x] 5\n[this] NULL\n[fn] CLOSURE=FN:fn\n[vargv] ARRAY=[]\n[this] NULL\nError [Failed to run script testData/exec/runtime_type_check/return_wrong_type.nut (testData/exec/runtime_type_check/return_wrong_type.nut)]\n"
  },
  {
    "path": "testData/exec/spec/class.nut",
    "content": "class Foo {\n    //constructor\n\n    testy = null\n    constructor(a) {\n        this.testy = [\"stuff\",1,2,3,a]\n    }\n    //member function\n    function PrintTesty() {\n        foreach(i,val in this.testy) {\n            println(\"idx = \"+i+\" = \"+val)\n        }\n    }\n    //property\n}\n\nlet foo = Foo(42)\n\nfoo.PrintTesty()\n"
  },
  {
    "path": "testData/exec/spec/class.out",
    "content": "idx = 0 = stuff\nidx = 1 = 1\nidx = 2 = 2\nidx = 3 = 3\nidx = 4 = 42\n"
  },
  {
    "path": "testData/exec/spec/classInher.nut",
    "content": "class Foo {\n    function DoSomething() {\n        println(\"I'm the base\")\n    }\n    function DoIt() {\n        this.DoSomething()\n    }\n}\n\nclass SuperFoo(Foo) {\n    //overridden method\n    function DoSomething() {\n        println(\"I'm the derived\")\n    }\n    function DoIt() {\n        base.DoIt()\n    }\n}\n\n//creates a new instance of SuperFoo\nlet inst = SuperFoo()\n\n//prints \"I'm the derived\"\ninst.DoIt()\n"
  },
  {
    "path": "testData/exec/spec/classInher.out",
    "content": "I'm the derived\n"
  },
  {
    "path": "testData/exec/spec/class_extend.nut",
    "content": "class B {}\n\nclass A(B) {}\n\nclass D(class {}) {}\n\nclass E(class(class {}) {}) {}\n\nclass F(class(class(class{}) {}) {}) {}\n\nclass G(class { a = 1 }) { a = 2 } { println(1) } { println(2) }\n"
  },
  {
    "path": "testData/exec/spec/class_extend.out",
    "content": "1\n2\n"
  },
  {
    "path": "testData/exec/spec/clone.nut",
    "content": "\n\nlet t = {\n    a = 10, b = 20\n}\n\nlet ct0 = clone t\n\n#forbid-clone-operator\n\nlet ct1 = t.clone()\n\n#allow-clone-operator\n\nlet ct2 = clone t\n\n#forbid-clone-operator\n\nlet ct3 = t.clone()\n\nprintln($\"Table t->a: original = {t.a}, cloned op = {ct2.a}, cloned method {ct3.a}\")\nprintln($\"Table t->b: original = {t.b}, cloned op = {ct2.b}, cloned method {ct3.b}\")\n\nlet arr = [\"a\", \"b\", \"c\"]\n\nlet arr1 = arr.clone()\n\n#allow-clone-operator\n\nlet arr2 = clone arr\n\n\nprintln($\"Array[0]: original = {arr[0]}, cloned op = {arr2[0]}, cloned method {arr1[0]}\")\nprintln($\"Array[1]: original = {arr[1]}, cloned op = {arr2[1]}, cloned method {arr1[1]}\")\nprintln($\"Array[2]: original = {arr[2]}, cloned op = {arr2[2]}, cloned method {arr1[2]}\")\n\nlet s = \"test\"\n\nlet s1 = clone s\n\n#forbid-clone-operator\nlet s2 = s.clone()\n\nprintln($\"String: orig '{s}', cloned op '{s1}', cloned method '{s2}'\")\n\nclass C {\n    x = 10\n}\n\nlet obj = C()\n\nlet obj1 = obj.clone()\n\n#allow-clone-operator\n\nlet obj2 = clone obj\n\nprintln($\"Instance: orig {obj.x}, cloned op {obj2.x}, cloned method {obj1.x}\")\n\ntry {\n    let c1 = clone C\n    println(\"Class: clone op -- FAILED\")\n} catch (e) {\n    println($\"Class: clone op -- OK, exception '{e}'\")\n}\n\n#forbid-clone-operator\n\ntry {\n    let c1 = C.clone()\n    println(\"Class: clone method -- FAILED\")\n} catch (e) {\n    println($\"Class: clone method -- OK, exception '{e}'\")\n}\n\nlet inum = 10\nlet fnum = 5.5\n\nlet inum1 = inum.clone()\nlet fnum1 = fnum.clone()\n\n#allow-clone-operator\n\nlet inum2 = clone inum\nlet fnum2 = clone fnum\n\nprintln($\"Integer: orig {inum}, cloned op {inum2}, cloned method {inum1}\")\nprintln($\"Float: orig {fnum}, cloned op {fnum2}, cloned method {fnum1}\")\n\nlet cls = @(x) $\"x = '{x}'\"\n\nlet cls1 = clone cls\n\n#forbid-clone-operator\n\nlet cls2 = cls.clone()\n\nprintln($\"Closure: orig {cls(42)}, cloned op {cls1(42)}, cloned method {cls2(42)}\")\n"
  },
  {
    "path": "testData/exec/spec/clone.out",
    "content": "Table t->a: original = 10, cloned op = 10, cloned method 10\nTable t->b: original = 20, cloned op = 20, cloned method 20\nArray[0]: original = a, cloned op = a, cloned method a\nArray[1]: original = b, cloned op = b, cloned method b\nArray[2]: original = c, cloned op = c, cloned method c\nString: orig 'test', cloned op 'test', cloned method 'test'\nInstance: orig 10, cloned op 10, cloned method 10\nClass: clone op -- OK, exception 'cloning a class'\nClass: clone method -- OK, exception 'cloning a class'\nInteger: orig 10, cloned op 10, cloned method 10\nFloat: orig 5.5, cloned op 5.5, cloned method 5.5\nClosure: orig x = '42', cloned op x = '42', cloned method x = '42'\n"
  },
  {
    "path": "testData/exec/spec/closure.nut",
    "content": "\nfunction foo(a, b, c) {\n  if (a) {\n    local x = 10\n    local z = 20\n    if (b) {\n      local w = 30\n      local y = 40\n      if (c) {\n        local u = 490\n        return function(q) {\n          return q + u + w\n        }\n      }\n    } else {\n      return function(t) {\n        return t + x\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "testData/exec/spec/closure.out",
    "content": ""
  },
  {
    "path": "testData/exec/spec/conditionalFor.nut",
    "content": "for (local i = 0; i < (true ? 5 : 1); i++)\n  print(\"X\")"
  },
  {
    "path": "testData/exec/spec/conditionalFor.out",
    "content": "XXXXX"
  },
  {
    "path": "testData/exec/spec/const.nut",
    "content": "const a = 5\nconst b = \"foo\"\nconst c = null\nconst d = [1, 2, 3, {x=555}]\nconst e = b\nconst f = d[1]\nconst g = d[3].x\n\nprintln(d[3].x)\nprintln(e)\nprintln(f)\nprintln(g)\n\n// Inline constant\nlet x = const [5,6,7,d,e]\nprintln(x[2])\n\nlet y = 2>3 ? const [1,2,3] : const [8,9,0]\nprintln(y[2])\n"
  },
  {
    "path": "testData/exec/spec/const.out",
    "content": "555\nfoo\n2\n555\n7\n0\n"
  },
  {
    "path": "testData/exec/spec/constFolding.nut",
    "content": "let a = 1\nlet c = a + 1\nprint(c)\nlet b = 1\nlet d = 2 + b\nprint(d)\nlet e = 3\nlet f = 4\nlet g = e + f\nprint(g)\n\nlet v0 = 1\nif (v0 > v0) { }\nprint(v0)\n\n"
  },
  {
    "path": "testData/exec/spec/constFolding.out",
    "content": "2371"
  },
  {
    "path": "testData/exec/spec/constFoldingCond.nut",
    "content": "print((((((-14 != 24)) ? (242) : (264)) + -12 - 78) & (157)))\n"
  },
  {
    "path": "testData/exec/spec/constFoldingCond.out",
    "content": "152"
  },
  {
    "path": "testData/exec/spec/const_func.nut",
    "content": "const function non_pure() { println(\"Non-pure, can be declared as constant, but can't be called as constant initializer\") }\nnon_pure()\n\n\nconst double = @[pure](x) x*2\nconst quad = const @[pure](x) double(double(x))\nconst r0 = quad(5)\nprintln(r0)\n\nconst square = function [pure](x) {\n  return x*x\n}\nconst r1 = square(5)\nprintln(r1)\n\nconst greet = const @[pure](name = \"world\") $\"Hello, {name}\"\nprintln(greet())\nprintln(greet(\"Kitty\"))\n\nconst function [pure] cube(x) {\n  return x*x*x\n}\nprintln(cube(3))\n\nconst function [pure] add(a, b) {\n  return a + b\n}\nprintln(add(10, 20))\n\nglobal const function [pure] multiply(x, y) {\n  return x * y\n}\nprintln(multiply(4, 5))\n\n\nconst function[pure] container(x) {\n  function nested(y) {\n    return x*y\n  }\n  return nested(5)\n}\n\nconst z = container(111)\nprintln(z)\n\nconst table = {\n  function foo() {}\n  bar = @() 12345\n}\n\nprintln(table.bar())\n"
  },
  {
    "path": "testData/exec/spec/const_func.out",
    "content": "Non-pure, can be declared as constant, but can't be called as constant initializer\n20\n25\nHello, world\nHello, Kitty\n27\n30\n20\n555\n12345\n"
  },
  {
    "path": "testData/exec/spec/const_func_freevars.nut",
    "content": "const with_outer_vars_1 = @\"\nlet w = 123\nconst function[pure] container2(x) {\n  function nested(y) {\n    return x*y*w //<-----\n  }\n  return nested(5)\n}\n\nconst z2 = container2(111)\nprintln(z)\n\"\ntry {\n  compilestring(with_outer_vars_1)\n} catch (e) {\n  println(e)\n}\n\n\nconst with_outer_vars_2 = @\"\nlet w = 123\nconst function[pure] container3(x) {\n  function nested(y) {\n    return x*y\n  }\n  return nested(5)*w //<-----\n}\n\nconst z2 = container2(111)\nprintln(z)\n\"\ntry {\n  compilestring(with_outer_vars_2)\n} catch (e) {\n  println(e)\n}\n"
  },
  {
    "path": "testData/exec/spec/const_func_freevars.out",
    "content": "ERROR: const function cannot have outer variables\nERROR: const function cannot have outer variables\n"
  },
  {
    "path": "testData/exec/spec/const_math_eval.nut",
    "content": "const tests = [\n  \"const a = 1 / 0\"\n  \"const a = 1 % 0\"\n  \"const a = (-0x7FFFFFFF-1) / -1\"\n  \"const a = (-0x7FFFFFFF_FFFFFFFF-1) / -1\"\n  \"const a = (-0x7FFFFFFF_FFFFFFFF-1) % -1\"\n  \"const a = (-0x7FFFFFFF_FFFFFFFF-1) % (-0x7FFFFFFF_FFFFFFFF-1)\"\n\n  \"const a = 0x7FFFFFFF_FFFFFFFF + 1\"\n  \"const a = (-0x7FFFFFFF_FFFFFFFF-1) - 1\"\n  \"const a = 0x7FFFFFFF_FFFFFFFF * 2\"\n  \"const a = (-0x7FFFFFFF_FFFFFFFF-1) * -1\"\n\n  \"const a = -(-0x7FFFFFFF-1)\"\n  \"const a = -(-0x7FFFFFFF_FFFFFFFF-1)\"\n\n  \"const a = 1 / 0.0\"\n  \"const a = -1 / 0.0\"\n  \"const a = 1 % 0.0\"\n  \"const a = 0.0 / 0.0\"\n  \"const a = 1 / -0.0\"\n\n  \"const a = 1e309\"\n  \"const a = 1e-324\"\n  \"const a = (0.0/0.0) + 1.0\"\n\n//  \"const a = 1 << -1\"\n//  \"const a = 1 << 64\"\n  \"const a = 0x80000000 << 1\"\n  \"const a = (-1) >> 1\"\n  \"const a = (-1) >>> 1\"\n]\n\nforeach (test in tests) {\n  println($\"Testing [{test}]\")\n  let src = $\"{test}\\nprintln(a)\"\n  try {\n    let closure = compilestring(src, \"test\", {println})\n    closure()\n  }\n  catch (e) {\n    println(e)\n  }\n  println()\n}\n"
  },
  {
    "path": "testData/exec/spec/const_math_eval.out",
    "content": "Testing [const a = 1 / 0]\nERROR: integer division by zero\n\nTesting [const a = 1 % 0]\nERROR: integer modulo by zero\n\nTesting [const a = (-0x7FFFFFFF-1) / -1]\n2147483648\n\nTesting [const a = (-0x7FFFFFFF_FFFFFFFF-1) / -1]\nERROR: integer overflow\n\nTesting [const a = (-0x7FFFFFFF_FFFFFFFF-1) % -1]\n0\n\nTesting [const a = (-0x7FFFFFFF_FFFFFFFF-1) % (-0x7FFFFFFF_FFFFFFFF-1)]\n0\n\nTesting [const a = 0x7FFFFFFF_FFFFFFFF + 1]\n-9223372036854775808\n\nTesting [const a = (-0x7FFFFFFF_FFFFFFFF-1) - 1]\n9223372036854775807\n\nTesting [const a = 0x7FFFFFFF_FFFFFFFF * 2]\n-2\n\nTesting [const a = (-0x7FFFFFFF_FFFFFFFF-1) * -1]\n-9223372036854775808\n\nTesting [const a = -(-0x7FFFFFFF-1)]\n2147483648\n\nTesting [const a = -(-0x7FFFFFFF_FFFFFFFF-1)]\n-9223372036854775808\n\nTesting [const a = 1 / 0.0]\nERROR: float division by zero\n\nTesting [const a = -1 / 0.0]\nERROR: float division by zero\n\nTesting [const a = 1 % 0.0]\nERROR: float modulo by zero\n\nTesting [const a = 0.0 / 0.0]\nERROR: float division by zero\n\nTesting [const a = 1 / -0.0]\nERROR: float division by zero\n\nTesting [const a = 1e309]\nERROR: float constant overflow\n\nTesting [const a = 1e-324]\nERROR: float constant underflow\n\nTesting [const a = (0.0/0.0) + 1.0]\nERROR: float division by zero\n\nTesting [const a = 0x80000000 << 1]\n4294967296\n\nTesting [const a = (-1) >> 1]\n-1\n\nTesting [const a = (-1) >>> 1]\n9223372036854775807\n\n"
  },
  {
    "path": "testData/exec/spec/const_with_expr.nut",
    "content": "// Unary\n\nconst o = 4\nconst a = -o\nconst b = !false\nconst c = ~a\nconst d = typeof(c)\n\nprintln(a, b, c, d)\n\n// Binary and ternary\n\nconst tbl = {[\"integer\"] = 5}\nconst x = tbl[typeof o] + (o | 0xFF) + (o % 3) - (b ? 6 : o)\n\nprintln(x)\n\n"
  },
  {
    "path": "testData/exec/spec/const_with_expr.out",
    "content": "-4 true 3 integer\n255\n"
  },
  {
    "path": "testData/exec/spec/delegate_get.nut",
    "content": "\nlet t = {\n    rawget = function (k) { return $\"HAHA -- {k}\" },\n    a = \"10\",\n    b = \"Foo Foo\"\n}\n\nlet x = t.$rawget(\"b\")\nlet y = t.rawget(\"b\")\n\nprintln($\"rawget(\\\"b\\\") = {y}, $rawget(\\\"b\\\") = {x}\")\n\nlet z = t?.$foo\nlet nz = t?.foo\n\nprintln($\"t?.$foo = {z}, t?.foo = {nz}\")\n\ntry {\n    let vf = t.$bar\n    println(\"FAIL: '$bar' is not a built-in member of table but successfully accessed\")\n} catch (e) {\n    println($\"OK: '$bar' is not a built-in member of table and access raised exectpion: \\\"{e}\\\"\")\n}\n\n#forbid-implicit-type-methods\n\nprintln(\"Forbid implicit type methods\")\n\ntry {\n    let rg1 = t.rawget\n    println(\"OK: 'rawget' is field in table\")\n} catch (e) {\n    println($\"FAIL: 'rawget' is field in table. Exception: \\\"{e}\\\"\")\n}\n\ntry {\n    let ks = t.keys\n    println(\"FAIL: 'keys' is built-in method of table which are forbiden.\")\n} catch (e) {\n    println($\"OK: 'keys' is built-in method of table. Exception: \\\"{e}\\\"\")\n}\n\ntry {\n    let rg2 = t.$rawget\n    println(\"OK: 'rawget' is built-in method of table accessed via '$'\")\n} catch (e) {\n    println($\"FAIL: 'rawget' is built-in method of table accessed via '$'. Exception: \\\"{e}\\\"\")\n}\n\ntry {\n    let nks = t?.keys\n    let nks2 = t?.$keys\n    println($\"OK: Safe access of built-in method 'keys' in both '$' and regular cases succeseded\")\n} catch (e) {\n    println($\"FAIL: Safe access of built-in method 'keys' failed. Exception: \\\"{e}\\\"\")\n}\n\n#allow-implicit-type-methods\n\nprintln(\"Allow implicit type methods\")\n\ntry {\n    let rg1 = t.rawget\n    println(\"OK: 'rawget' is field in table\")\n} catch (e) {\n    println($\"FAIL: 'rawget' is field in table. Exception: \\\"{e}\\\"\")\n}\n\ntry {\n    let ks = t.keys\n    println($\"OK: 'keys' is built-in method of table.\")\n} catch (e) {\n    println(\"FAIL: 'keys' is built-in method of table which are forbiden.\")\n}\n\ntry {\n    let rg2 = t.$rawget\n    println(\"OK: 'rawget' is built-in method of table accessed via '$'\")\n} catch (e) {\n    println($\"FAIL: 'rawget' is built-in method of table accessed via '$'. Exception: \\\"{e}\\\"\")\n}\n"
  },
  {
    "path": "testData/exec/spec/delegate_get.out",
    "content": "rawget(\"b\") = HAHA -- b, $rawget(\"b\") = Foo Foo\nt?.$foo = null, t?.foo = null\nOK: '$bar' is not a built-in member of table and access raised exectpion: \"the index 'bar' (type='string') does not exist\"\nForbid implicit type methods\nOK: 'rawget' is field in table\nOK: 'keys' is built-in method of table. Exception: \"the index 'keys' (type='string') does not exist\"\nOK: 'rawget' is built-in method of table accessed via '$'\nOK: Safe access of built-in method 'keys' in both '$' and regular cases succeseded\nAllow implicit type methods\nOK: 'rawget' is field in table\nOK: 'keys' is built-in method of table.\nOK: 'rawget' is built-in method of table accessed via '$'\n"
  },
  {
    "path": "testData/exec/spec/destruct.nut",
    "content": "let arr = [123, 567]\nlet [a, b = 22, c = 11] = arr\nprintln(a) // => 123\nprintln(b) // => 567\nprintln(c) // => 567\n\nfunction foo() {\n  return {x = 555, y=777, z=999, w=111}\n}\nlet {x, y=1, q=3} = foo()\nprintln(x) // => 555\nprintln(y) // => 777\nprintln(q) // => 3\n"
  },
  {
    "path": "testData/exec/spec/destruct.out",
    "content": "123\n567\n11\n555\n777\n3\n"
  },
  {
    "path": "testData/exec/spec/dowstmt.nut",
    "content": "local a=0\ndo {\n    println(a)\n    a += 1\n} while(a>100)\n"
  },
  {
    "path": "testData/exec/spec/dowstmt.out",
    "content": "0\n"
  },
  {
    "path": "testData/exec/spec/enums.nut",
    "content": "enum Foo {\n  x = 1,\n  y = 2,\n  z = 3\n}\n\nprintln(Foo.x)\nprintln(Foo.y)\nprintln(Foo.z)"
  },
  {
    "path": "testData/exec/spec/enums.out",
    "content": "1\n2\n3\n"
  },
  {
    "path": "testData/exec/spec/foreachstmt.nut",
    "content": "function foreach_show(a)\n{\n  foreach (val in a)\n      println ($\"value={val}\")\n  foreach (idx, val in a)\n      println($\"index={idx} value={val}\")\n}\n\nforeach_show([10,23,33,41,589,56])\n//tables\nforeach_show({x = 10, y = 11.5, z = \"str\", w = true})\n\n//generators\nfunction range(n) {\n  for (local i=0; i<n; ++i)\n    yield i\n}\nforeach_show(range(3))\n\nforeach (p in range(3)) {\n  println(p)\n}\n\nforeach (p in range(0)) {\n  println(p)\n}\n"
  },
  {
    "path": "testData/exec/spec/foreachstmt.out",
    "content": "value=10\nvalue=23\nvalue=33\nvalue=41\nvalue=589\nvalue=56\nindex=0 value=10\nindex=1 value=23\nindex=2 value=33\nindex=3 value=41\nindex=4 value=589\nindex=5 value=56\nvalue=11.5\nvalue=str\nvalue=true\nvalue=10\nindex=y value=11.5\nindex=z value=str\nindex=w value=true\nindex=x value=10\nvalue=0\nvalue=1\nvalue=2\n0\n1\n2\n"
  },
  {
    "path": "testData/exec/spec/forstmt.nut",
    "content": "\nfor (local a=0;a<10;a+=1)\n    println(a)\n//or\n\n\nfor (;;) {\n    println(\"loops forever\")\n    break;\n}\n"
  },
  {
    "path": "testData/exec/spec/forstmt.out",
    "content": "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nloops forever\n"
  },
  {
    "path": "testData/exec/spec/func_pure_attr.nut",
    "content": "local counter = 123\n\nfunction external() {\n  return 0\n}\n\nfunction foo() {\n  external()\n}\n\nfunction [pure] bar() {\n  external()\n}\n\nlet a = @() external()+123\nlet b = @ [pure] () external()+123\n\nprintln($\"{foo.getfuncinfos().pure}\")\nprintln($\"{bar.getfuncinfos().pure}\")\nprintln($\"{a.getfuncinfos().pure}\")\nprintln($\"{b.getfuncinfos().pure}\")\n"
  },
  {
    "path": "testData/exec/spec/func_pure_attr.out",
    "content": "false\ntrue\nfalse\ntrue\n"
  },
  {
    "path": "testData/exec/spec/generators.nut",
    "content": "function geny(n) {\n  for (local i=0; i<n; ++i)\n    yield i\n  return null\n}\n\nprintln(\"FOR\")\nlet gtor = geny(5)\nfor (local x=resume gtor; x!=null; x=resume gtor)\n  println(x)\n\n\nprintln(\"FOREACH\")\nforeach (x in geny(3))\n  println(x)\n"
  },
  {
    "path": "testData/exec/spec/generators.out",
    "content": "FOR\n0\n1\n2\n3\n4\nFOREACH\n0\n1\n2\n"
  },
  {
    "path": "testData/exec/spec/ifstmt.nut",
    "content": "\nlocal a = 10, b = 20;\nif (a > b)\n    a = b\nelse\n    b = a\n////\nif ( a == 10 ) {\n    b = a + b\n    return a - 10\n}\n"
  },
  {
    "path": "testData/exec/spec/ifstmt.out",
    "content": ""
  },
  {
    "path": "testData/exec/spec/sort.nut",
    "content": "// Basic ascending sort with comparator\nlet a = [4, 2, 5]\na.sort(@(a, b) a<=>b)\nprintln(\"Basic ascending:\")\na.each(@(v) println(v))\n\n// Descending sort\nlet b = [4, 2, 5, 1, 3]\nb.sort(@(a, b) b<=>a)\nprintln(\"\\nDescending:\")\nb.each(@(v) println(v))\n\n// Default sort (no comparator)\nlet c = [8, 3, 9, 1, 5]\nc.sort()\nprintln(\"\\nDefault sort:\")\nc.each(@(v) println(v))\n\n// Sorting strings\nlet d = [\"zebra\", \"apple\", \"mango\", \"banana\"]\nd.sort(@(a, b) a<=>b)\nprintln(\"\\nString sort:\")\nd.each(@(v) println(v))\n\n// Already sorted array\nlet e = [1, 2, 3, 4, 5]\ne.sort(@(a, b) a<=>b)\nprintln(\"\\nAlready sorted:\")\ne.each(@(v) println(v))\n\n// Array with duplicates\nlet f = [3, 1, 4, 1, 5, 9, 2, 6, 5]\nf.sort(@(a, b) a<=>b)\nprintln(\"\\nWith duplicates:\")\nf.each(@(v) println(v))\n\n// Single element\nlet g = [42]\ng.sort(@(a, b) a<=>b)\nprintln(\"\\nSingle element:\")\ng.each(@(v) println(v))\n\n// Empty array\nlet h = []\nh.sort(@(a, b) a<=>b)\nprintln(\"\\nEmpty array:\")\nh.each(@(v) println(v))\n\n// Negative numbers\nlet i = [-5, 3, -2, 0, 7, -1]\ni.sort(@(a, b) a<=>b)\nprintln(\"\\nNegative numbers:\")\ni.each(@(v) println(v))\n\n// Floats\nlet j = [3.14, 2.71, 1.41, 2.5]\nj.sort(@(a, b) a<=>b)\nprintln(\"\\nFloats:\")\nj.each(@(v) println(v))\n\n// Custom comparator - sort by absolute value\nlet k = [-5, 3, -2, 0, 7, -1]\nk.sort(@(a, b) (a < 0 ? -a : a) <=> (b < 0 ? -b : b))\nprintln(\"\\nBy absolute value:\")\nk.each(@(v) println(v))\n\n// Sort array of tables by a field\nlet m = [\n  {name = \"Charlie\", age = 25},\n  {name = \"Alice\", age = 30},\n  {name = \"Bob\", age = 20}\n]\nm.sort(@(a, b) a.age <=> b.age)\nprintln(\"\\nTables by age:\")\nm.each(@(v) println(v.name + \": \" + v.age))\n\n// Reverse sorted array\nlet n = [9, 7, 5, 3, 1]\nn.sort(@(a, b) a<=>b)\nprintln(\"\\nReverse sorted input:\")\nn.each(@(v) println(v))\n\n// Large array\nlet p = []\nfor (local x = 10; x >= 1; x--)\n  p.append(x)\np.sort(@(a, b) a<=>b)\nprintln(\"\\nLarge array (10 elements):\")\np.each(@(v) println(v))\n\n// Resize is forbidden\nprintln(\"\\nTrying to resize during sorting:\")\ntry {\n  p.sort(function(a, b) {\n    p.resize(17)\n    return a<=>b\n  })\n} catch (e) {\n  println(e)\n}\n"
  },
  {
    "path": "testData/exec/spec/sort.out",
    "content": "Basic ascending:\n2\n4\n5\n\nDescending:\n5\n4\n3\n2\n1\n\nDefault sort:\n1\n3\n5\n8\n9\n\nString sort:\napple\nbanana\nmango\nzebra\n\nAlready sorted:\n1\n2\n3\n4\n5\n\nWith duplicates:\n1\n1\n2\n3\n4\n5\n5\n6\n9\n\nSingle element:\n42\n\nEmpty array:\n\nNegative numbers:\n-5\n-2\n-1\n0\n3\n7\n\nFloats:\n1.41\n2.5\n2.71\n3.14\n\nBy absolute value:\n0\n-1\n-2\n3\n-5\n7\n\nTables by age:\nBob: 20\nCharlie: 25\nAlice: 30\n\nReverse sorted input:\n1\n3\n5\n7\n9\n\nLarge array (10 elements):\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n\nTrying to resize during sorting:\narray resized during sort operation\n"
  },
  {
    "path": "testData/exec/spec/stringtmplt.nut",
    "content": "local foo = 123\nprint($\"\\{ foo = {foo} \\}\")\n"
  },
  {
    "path": "testData/exec/spec/stringtmplt.out",
    "content": "{ foo = 123 }"
  },
  {
    "path": "testData/exec/spec/trystmt.nut",
    "content": "function foo(a, b, c) {\n  try {\n    println($\"TRYING {a}\")\n    throw b\n  } catch (e) {\n    println($\"CAUGHT {e}\")\n  }\n  println($\"FINISHING {c}\")\n}\n\n\nfoo(1, 2, 3)\n"
  },
  {
    "path": "testData/exec/spec/trystmt.out",
    "content": "TRYING 1\nCAUGHT 2\nFINISHING 3\n"
  },
  {
    "path": "testData/exec/spec/whilestmt.nut",
    "content": "function testy(n) {\n    local a = 0\n    while (a < n)\n      a += 1\n\n    while (1) {\n        if (a < 0)\n            break\n        println(a)\n        a -= 1\n    }\n}\n\ntesty(10)\n"
  },
  {
    "path": "testData/exec/spec/whilestmt.out",
    "content": "10\n9\n8\n7\n6\n5\n4\n3\n2\n1\n0\n"
  },
  {
    "path": "testData/exec/stack_metamethod.nut",
    "content": "local A = class {\n  function _call(...) {}\n}\n\nlocal a = A()\n\nfunction fn1(n, ...) {\n  local a1, b1, c1, d1\n  if (n > 0) {\n    a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,\n      )\n    fn1(n - 1)\n  }\n}\n\nfn1(10000)\n"
  },
  {
    "path": "testData/exec/stack_metamethod.out",
    "content": ""
  },
  {
    "path": "testData/exec/stack_metamethod_few_args.nut",
    "content": "local A = class {\n  function _call(...) {}\n}\n\nlocal a = A()\n\nfunction fn1(n, ...) {\n  if (n > 0) {\n    a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)\n    fn1(n - 1)\n  }\n}\n\nfn1(10000)\n"
  },
  {
    "path": "testData/exec/stack_metamethod_few_args.out",
    "content": ""
  },
  {
    "path": "testData/exec/stack_metamethod_locals.nut",
    "content": "local A = class {\n  function _call(...) {\n  }\n}\n\nlocal a = A()\n\nfunction fn1(n, ...) {\n  local a000, a001, a002, a003, a004, a005, a006, a007, a008, a009;\n  local a010, a011, a012, a013, a014, a015, a016, a017, a018, a019;\n  local a020, a021, a022, a023, a024, a025, a026, a027, a028, a029;\n  local a030, a031, a032, a033, a034, a035, a036, a037, a038, a039;\n  local a040, a041, a042, a043, a044, a045, a046, a047, a048, a049;\n  local a050, a051, a052, a053, a054, a055, a056, a057, a058, a059;\n  local a060, a061, a062, a063, a064, a065, a066, a067, a068, a069;\n  local a070, a071, a072, a073, a074, a075, a076, a077, a078, a079;\n  local a080, a081, a082, a083, a084, a085, a086, a087, a088, a089;\n  local a090, a091, a092, a093, a094, a095, a096, a097, a098, a099;\n\n  local a100, a101, a102, a103, a104, a105, a106, a107, a108, a109;\n  local a110, a111, a112, a113, a114, a115, a116, a117, a118, a119;\n  local a120, a121, a122, a123, a124, a125, a126, a127, a128, a129;\n  local a130, a131, a132, a133, a134, a135, a136, a137, a138, a139;\n  local a140, a141, a142, a143, a144, a145, a146, a147, a148, a149;\n  local a150, a151, a152, a153, a154, a155, a156, a157, a158, a159;\n  local a160, a161, a162, a163, a164, a165, a166, a167, a168, a169;\n  local a170, a171, a172, a173, a174, a175, a176, a177, a178, a179;\n  local a180, a181, a182, a183, a184, a185, a186, a187, a188, a189;\n\n  if (n > 0) {\n    a(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0)\n    fn1(n - 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0)\n  }\n\n}\n\ntry {\n  fn1(500)\n  fn1(500)\n  println(\"OK\")\n}\ncatch (e) {\n  println(\"Exception:\", e)\n}\n"
  },
  {
    "path": "testData/exec/stack_metamethod_locals.out",
    "content": "OK\n"
  },
  {
    "path": "testData/exec/staticmemo/no_memo_mutable_args.nut",
    "content": "// Test: file-level 'let' variables holding mutable values must NOT cause\n// auto-static-memoization when passed to [pure] functions.\n\nlet config = { value = 10 }\n\n// --- pure function returning a primitive derived from mutable state ---\n\nfunction [pure] readValue(t) {\n    return t.value\n}\n\nfunction getFromConfig() {\n    return readValue(config)\n}\n\nassert(getFromConfig() == 10)\nconfig.value = 42\nassert(getFromConfig() == 42)\nprintln(\"primitive return: ok\")\n\n\n// --- pure function creating a new table from mutable state ---\n\nconfig.value = 100\n\nfunction [pure] snapshot(t) {\n    return { captured = t.value }\n}\n\nfunction takeSnapshot() {\n    return snapshot(config)\n}\n\nassert(takeSnapshot().captured == 100)\nconfig.value = 200\nassert(takeSnapshot().captured == 200)\nprintln(\"new table return: ok\")\n\n\n// --- pure function returning its argument (must not freeze it) ---\n\nlet data = { x = 1 }\n\nfunction [pure] passthrough(t) {\n    return t\n}\n\nfunction getData() {\n    return passthrough(data)\n}\n\nlet d = getData()\nd.x = 999\nassert(d.x == 999)\nassert(data.x == 999)\nprintln(\"passthrough not frozen: ok\")\n\n\n// --- multiple mutable arguments ---\n\nlet left  = { n = 1 }\nlet right = { n = 2 }\n\nfunction [pure] addFields(a, b) {\n    return a.n + b.n\n}\n\nfunction computeSum() {\n    return addFields(left, right)\n}\n\nassert(computeSum() == 3)\nleft.n = 10\nright.n = 20\nassert(computeSum() == 30)\nprintln(\"two mutable args: ok\")\n\n\n// --- nested pure calls ---\n\nconfig.value = 5\n\nfunction [pure] double(n) {\n    return n * 2\n}\n\nfunction getDoubled() {\n    return double(readValue(config))\n}\n\nassert(getDoubled() == 10)\nconfig.value = 50\nassert(getDoubled() == 100)\nprintln(\"nested pure calls: ok\")\n"
  },
  {
    "path": "testData/exec/staticmemo/no_memo_mutable_args.out",
    "content": "primitive return: ok\nnew table return: ok\npassthrough not frozen: ok\ntwo mutable args: ok\nnested pure calls: ok\n"
  },
  {
    "path": "testData/exec/staticmemo/no_memo_mutable_result.nut",
    "content": "// Auto-static-memo must not memoize pure functions returning mutable containers\nlet t = freeze({a = 1})\nfunction f() {\n  let v = t.values()\n  v.sort()\n}\nf()\nprint(\"OK\\n\")\n"
  },
  {
    "path": "testData/exec/staticmemo/no_memo_mutable_result.out",
    "content": "OK\n"
  },
  {
    "path": "testData/exec/staticmemo/static_assign_itself.nut",
    "content": "local x = 333\nx = static x\nprintln(x)\n\nlocal y = {a = 444}\ny = static y\nprintln(y.a)\n\nlocal z = [555, 666]\nz = static z\nprintln(z[1])\n\nlocal w = [777, 888]\nw = static w\nw = static w\nprintln(w[1])\n\nlocal a = 111\na = static a\na = static a\nprintln(a)\n\n"
  },
  {
    "path": "testData/exec/staticmemo/static_assign_itself.out",
    "content": "333\n444\n666\n888\n111\n"
  },
  {
    "path": "testData/exec/staticmemo/static_exception.nut",
    "content": "local div = 0\n\nfunction fn() {\n  try {\n    let tab = static { x = 123 / div }\n    println(tab.x)\n  } catch (e) {\n    println(\"exception\")\n  }\n}\n\nfn()\nfn()\n\ndiv = 2\nfn()\nfn()\n"
  },
  {
    "path": "testData/exec/staticmemo/static_exception.out",
    "content": "exception\nexception\n61\n61\n"
  },
  {
    "path": "testData/exec/staticmemo/static_freeze.nut",
    "content": "let t = static {x = null}\ntry {\n  t.x = \"fail\"\n  println(t.x)\n} catch (e) {\n  println(\"success\")\n}\n"
  },
  {
    "path": "testData/exec/staticmemo/static_freeze.out",
    "content": "success\n"
  },
  {
    "path": "testData/exec/staticmemo/static_loop.nut",
    "content": "for (local x = 111; x < 116; x++)\n  println(static x)\n\n"
  },
  {
    "path": "testData/exec/staticmemo/static_loop.out",
    "content": "111\n111\n111\n111\n111\n"
  },
  {
    "path": "testData/exec/staticmemo/static_nested.nut",
    "content": "for (local x = 111; x < 114; x++)\n  println(static static static static static x)\n\nprintln(\"\")\nlocal y = 222\nfor (local x = y; x < 224; x++) {\n  println(static static ~(static static static ~x + static(x * 2) + static x))\n  println(~(~y + (y * 2) + y))\n}\n\n"
  },
  {
    "path": "testData/exec/staticmemo/static_nested.out",
    "content": "111\n111\n111\n\n-444\n-444\n-444\n-444\n"
  },
  {
    "path": "testData/exec/staticmemo/static_opt.nut",
    "content": "function fn() {\n  println(static (1 + 2 + 4 + 8))\n  println(static (1 | 2 | 4 | 8))\n  let s = \"===\"\n  println(s)\n}\n\nfn()\nfn()\n"
  },
  {
    "path": "testData/exec/staticmemo/static_opt.out",
    "content": "15\n15\n===\n15\n15\n===\n"
  },
  {
    "path": "testData/exec/staticmemo/static_opt2.nut",
    "content": "let fni2 = @() 335\nlet A8 = class { function _get(idx) { return idx + -3 }}\nlet ci8 = A8()\nlet fni11 = @() 11\nlet fni9 = @(p10) p10 - fni11()\nlet t12 = { f0=3 }\nlet A13 = class { function _get(idx) { return idx + 3 }}\nlet ci13 = A13()\nlet t7 = { f0=(((static(ci8[((298) | (10 - -3))]) == 999)) ? (10) : (t12[\"f0\"])) f1=ci13[2] }\nprintln(t7.f0)\nprintln(t7.f1)\n"
  },
  {
    "path": "testData/exec/staticmemo/static_opt2.out",
    "content": "3\n5\n"
  },
  {
    "path": "testData/exec/staticmemo/static_reset1.nut",
    "content": "let { reset_static_memos } = require(\"modules\")\n\nlocal a, s\n\nfunction sw() { return a }\n\n\nfunction func() {\n\n  function xx1() {\n    for (local i = 0; i < 1000; i++)\n      s += (static(sw())) + (static sw())\n  }\n\n  function xx2() {\n    for (local i = 0; i < 1000; i++)\n      s += static sw()\n  }\n\n  s = 0\n  xx1()\n  xx2()\n  println(s)\n\n\n  s = 0\n  xx1()\n  xx2()\n  println(s)\n\n}\n\na = 1\nfunc()\n\nreset_static_memos()\nprintln(\"\")\n\na = 2\nfunc()\n"
  },
  {
    "path": "testData/exec/staticmemo/static_reset1.out",
    "content": "3000\n3000\n\n6000\n6000\n"
  },
  {
    "path": "testData/exec/staticmemo/static_reset2.nut",
    "content": "let { reset_static_memos } = require(\"modules\")\n\nlocal a, s\n\nfunction sw() { return a }\n\n\nfunction func() {\n\n  function xx() {\n    s = 0\n    for (local i = 0; i < 1000; i++)\n      s += static sw()\n  }\n\n  reset_static_memos()\n  reset_static_memos()\n\n  a = 1\n  xx()\n  println(s)\n\n  reset_static_memos()\n\n  a = 2\n  xx()\n  println(s)\n\n  reset_static_memos()\n}\n\nfunc()\nfunc()\n"
  },
  {
    "path": "testData/exec/staticmemo/static_reset2.out",
    "content": "1000\n2000\n1000\n2000\n"
  },
  {
    "path": "testData/exec/staticmemo/static_reset_module.nut",
    "content": "function fn(x) {\n  x++\n  println(static x)\n  x++\n  println(x)\n}\n\nfn(10)\nfn(20)\n\nrequire(\"static_reset1.nut\")\n\nfn(30)\nfn(40)\n"
  },
  {
    "path": "testData/exec/staticmemo/static_reset_module.out",
    "content": "11\n12\n11\n22\n3000\n3000\n\n6000\n6000\n31\n32\n31\n42\n"
  },
  {
    "path": "testData/exec/staticmemo/static_tables.nut",
    "content": "local add = 0\n\nfunction fn() {\n  let x = static {a = 222 + add}\n  println(x.a)\n\n  let y = static({a = 222 + add})\n  println(y.a)\n\n  let z = static {a = 222 + add}.__update({a = 333 + add})\n  println(z.a)\n\n  let w = static {a = 222 + add}.__update(static {a = 333 + add})\n  println(z.a)\n\n  println(\"\");\n}\n\nfn()\nadd = 1\nfn()\n"
  },
  {
    "path": "testData/exec/staticmemo/static_tables.out",
    "content": "222\n222\n333\n333\n\n222\n222\n333\n333\n\n"
  },
  {
    "path": "testData/exec/staticmemo/static_types.nut",
    "content": "class A {\n  function fn() { return 444 }\n}\n\nlet a = A()\n\nprintln(static null)\nprintln(static true)\nprintln(static 123)\nprintln(static 123.25)\nprintln(static \"asdf\")\nprintln((static [678])[0])\nprintln((static {a = 987})[\"a\"])\nprintln(\"closure\" == typeof static println)\nprintln(static println(\"print\"))\nprintln(typeof static A)\nprintln(typeof static a)\nprintln(typeof static a.fn)\n\nfunction t()\n{\n  println(static a.fn())\n}\n\nt()\nt()\n"
  },
  {
    "path": "testData/exec/staticmemo/static_types.out",
    "content": "null\ntrue\n123\n123.25\nasdf\n678\n987\nfalse\nprint\nnull\nclass\ninstance\nfunction\n444\n444\n"
  },
  {
    "path": "testData/exec/stdlib/blob_methods.nut",
    "content": "let { blob, casti2f, castf2i, swap2, swap4, swapfloat } = require(\"iostream\")\n\nlet b = blob(16)\nassert(b.len() == 16)\nassert(typeof b == \"blob\")\n\nb.resize(4)\nassert(b.len() == 4)\n\nb[0] = 0xAA\nb[1] = 0xBB\nb[2] = 0xCC\nb[3] = 0xDD\nassert(b[0] == 0xAA)\nassert(b[1] == 0xBB)\nassert(b[2] == 0xCC)\nassert(b[3] == 0xDD)\n\nlet s = blob(4)\ns[0] = 0x12\ns[1] = 0x34\ns[2] = 0x56\ns[3] = 0x78\ns.swap2()\nassert(s[0] == 0x34 && s[1] == 0x12 && s[2] == 0x78 && s[3] == 0x56)\n\nlet q = blob(4)\nq[0] = 0x11; q[1] = 0x22; q[2] = 0x33; q[3] = 0x44\nq.swap4()\nassert(q[0] == 0x44 && q[1] == 0x33 && q[2] == 0x22 && q[3] == 0x11)\n\nlet t = blob(5)\nt[0] = 104\nt[1] = 101\nt[2] = 108\nt[3] = 108\nt[4] = 111\nassert(t.as_string() == \"hello\")\n\nlet bi = blob(3)\nbi[0] = 10; bi[1] = 20; bi[2] = 30\nlocal sum = 0\nforeach (_, v in bi) {\n  sum += v\n}\nassert(sum == 60)\n\nlet orig = blob(3)\norig[0] = 1; orig[1] = 2; orig[2] = 3\nlet cp = clone orig\nassert(cp.len() == 3)\nassert(cp[0] == 1 && cp[1] == 2 && cp[2] == 3)\ncp[0] = 99\nassert(orig[0] == 1)\n\nlet i = 0x3f800000\nlet f = casti2f(i)\nassert(typeof f == \"float\")\nlet ii = castf2i(f)\nassert(ii == i)\n\nassert(swap2(0x1234) == 0x3412)\nassert(swap4(0x11223344) == 0x44332211)\nlet sf = swapfloat(1.0)\nassert(typeof sf == \"float\")\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nlet zz = blob(4)\nmustThrow(\"blob.ctor\",    @() blob(null))\nmustThrow(\"resize\",       @() zz.resize(null))\nmustThrow(\"_set.1\",       @() zz._set(null, 0))\nmustThrow(\"_set.2\",       @() zz._set(0, null))\nmustThrow(\"_get\",         @() zz._get(null))\nmustThrow(\"_cloned\",      @() zz._cloned(null))\nmustThrow(\"casti2f\",      @() casti2f(null))\nmustThrow(\"castf2i\",      @() castf2i(null))\nmustThrow(\"g.swap2\",      @() swap2(null))\nmustThrow(\"g.swap4\",      @() swap4(null))\nmustThrow(\"g.swapfloat\",  @() swapfloat(null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/blob_methods.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/copy_content_with_replace.nut",
    "content": "// Arrays\n\nlet a = [1, 2, 3, 4]\nlet b = [5, 6, 7]\n\nlet aRef = a.replace_with(b)\nb[0] = 999\n\nassert(aRef == a)\nassert(a[0]==5)\n\nprintln(\"== a ==\")\nforeach (x in a)\n  println(x)\nprintln(\"== aRef ==\")\nforeach (x in aRef)\n  println(x)\nprintln(\"== b ==\")\nforeach (x in b)\n  println(x)\n\n// Tables\n\nlet p = {x=123, y=456}\nlet q = {z=777}\n\nlet pRef = p.replace_with(q)\nq.z = \"foo\"\n\nassert(pRef == p)\nassert(p.z == 777)\nassert(\"x\" not in p)\n\n\nprintln(\"== p ==\")\nforeach (k, v in p)\n  println(k, \"=\", v)\nprintln(\"== pRef ==\")\nforeach (k, v in pRef)\n  println(k, \"=\", v)\nprintln(\"== q ==\")\nforeach (k, v in q)\n  println(k, \"=\", v)\n"
  },
  {
    "path": "testData/exec/stdlib/copy_content_with_replace.out",
    "content": "== a ==\n5\n6\n7\n== aRef ==\n5\n6\n7\n== b ==\n999\n6\n7\n== p ==\nz = 777\n== pRef ==\nz = 777\n== q ==\nz = foo\n"
  },
  {
    "path": "testData/exec/stdlib/datetime.nut",
    "content": "let { clock, time, date } = require(\"datetime\")\n\nassert(typeof clock() == \"float\")\nassert(clock() >= 0.0)\n\nassert(typeof time() == \"integer\")\nassert(time() > 0)\n\nlet d = date()\nassert(typeof d == \"table\")\nassert(\"sec\" in d)\nassert(\"min\" in d)\nassert(\"hour\" in d)\nassert(\"day\" in d)\nassert(\"month\" in d)\nassert(\"year\" in d)\nassert(\"wday\" in d)\nassert(\"yday\" in d)\nassert(d.sec >= 0 && d.sec <= 60)\nassert(d.min >= 0 && d.min <= 59)\nassert(d.hour >= 0 && d.hour <= 23)\nassert(d.day >= 1 && d.day <= 31)\nassert(d.month >= 0 && d.month <= 11)\nassert(d.year >= 2020)\nassert(d.wday >= 0 && d.wday <= 6)\nassert(d.yday >= 0 && d.yday <= 365)\n\nlet t = time()\nlet dLocal = date(t, 'l')\nlet dUtc = date(t, 'u')\nassert(typeof dLocal == \"table\")\nassert(typeof dUtc == \"table\")\nassert(dLocal.year >= 2020)\nassert(dUtc.year >= 2020)\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nmustThrow(\"date.1\", @() date(null))\nmustThrow(\"date.2\", @() date(t, null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/datetime.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/debug.nut",
    "content": "let dbg = require(\"debug\")\n\nlet info = dbg.getbuildinfo()\n\nprintln($\"Version: {info.version}\")\nprintln($\"seterrorhandler: {type(dbg.seterrorhandler)}\")\nprintln($\"setdebughook: {type(dbg.setdebughook)}\")\nprintln($\"getstackinfos: {type(dbg.getstackinfos)}\")\nprintln($\"error: {type(error)}\")\nprintln($\"errorln: {type(errorln)}\")\n\nif (info.gc == \"enabled\") {\n    if (type(dbg.collectgarbage) == \"function\") {\n        println($\"collectgarbage: OK\")\n    } else {\n        println($\"collectgarbage: FAIL\")\n    }\n    if (type(dbg.resurrectunreachable) == \"function\") {\n        println($\"resurrectunreachable: OK\")\n    } else {\n        println($\"resurrectunreachable: FAIL\")\n    }\n} else {\n    if (dbg?.collectgarbage == null) {\n        println($\"collectgarbage: OK\")\n    } else {\n        println($\"collectgarbage: FAIL\")\n    }\n    if (dbg?.resurrectunreachable == null) {\n        println($\"resurrectunreachable: OK\")\n    } else {\n        println($\"resurrectunreachable: FAIL\")\n    }\n}\n\nprintln($\"getobjflags: {type(getobjflags)}\")\nprintln($\"getbuildinfo: {type(dbg.getbuildinfo)}\")\n\nfunction fn(x: int, y: float): float {\n    return x * y\n}\n\nprintln($\"get_function_decl_string: {dbg.get_function_decl_string(fn)}\")\nprintln($\"type_mask_to_string(6) = {dbg.type_mask_to_string(6)}\")\n"
  },
  {
    "path": "testData/exec/stdlib/debug.out",
    "content": "Version: 4.20.0\nseterrorhandler: function\nsetdebughook: function\ngetstackinfos: function\nerror: function\nerrorln: function\ncollectgarbage: OK\nresurrectunreachable: OK\ngetobjflags: function\ngetbuildinfo: function\nget_function_decl_string: pure (table|userdata|instance|class|null).fn(x: int, y: float): float\ntype_mask_to_string(6) = number\n"
  },
  {
    "path": "testData/exec/stdlib/debug_extras.nut",
    "content": "let debugLib = require(\"debug\")\nlet { getlocals, format_call_stack_string, script_watchdog_kick, set_script_watchdog_timeout_msec, get_function_info_table, seterrorhandler, setdebughook } = debugLib\n\nfunction testLocals() {\n  local a = 1\n  local b = \"hello\"\n  local c = [1, 2, 3]\n  let locals = getlocals(1)\n  assert(typeof locals == \"table\")\n  assert(locals.a == 1)\n  assert(locals.b == \"hello\")\n  assert(locals.c.len() == 3)\n}\ntestLocals()\n\nlet prev = set_script_watchdog_timeout_msec(1000)\nassert(typeof prev == \"integer\")\nscript_watchdog_kick()\nset_script_watchdog_timeout_msec(prev)\n\nfunction targetFn(x: int, y: int): int { return x + y }\nlet info = get_function_info_table(targetFn)\nassert(typeof info == \"table\")\nassert(info.functionName == \"targetFn\")\nassert(info.native == false)\nassert(typeof info.requiredArgs == \"integer\")\n\nlet s = format_call_stack_string()\nassert(typeof s == \"string\")\nassert(s.len() > 0)\n\nfunction myErrorHandler(_err) {}\nseterrorhandler(myErrorHandler)\nseterrorhandler(null)\n\nfunction myDebugHook(_event, _src, _line, _name) {}\nsetdebughook(myDebugHook)\nsetdebughook(null)\n\ntry {\n  seterrorhandler(\"bad\")\n  println(\"FAIL: seterrorhandler accepted string\")\n} catch (e) {\n  assert(typeof e == \"string\")\n}\n\ntry {\n  setdebughook(42)\n  println(\"FAIL: setdebughook accepted int\")\n} catch (e) {\n  assert(typeof e == \"string\")\n}\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nmustThrow(\"getstackinfos\",                  @() debugLib.getstackinfos(null))\nmustThrow(\"getlocals.1\",                    @() getlocals(null))\nmustThrow(\"getlocals.2\",                    @() getlocals(1, null))\nmustThrow(\"set_script_watchdog_timeout_msec\", @() set_script_watchdog_timeout_msec(null))\nmustThrow(\"get_function_decl_string\",       @() debugLib.get_function_decl_string(null))\nmustThrow(\"type_mask_to_string\",            @() debugLib.type_mask_to_string(null))\nmustThrow(\"get_function_info_table\",        @() get_function_info_table(null))\nmustThrow(\"doc\",                            @() debugLib.doc(null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/debug_extras.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/deep_hash.nut",
    "content": "from \"math\" import *\nfrom \"string\" import *\n\nclass A {\n  w = 333\n}\n\nlet inst1 = A()\nlet inst2 = A()\n\nassert(deep_hash({}) == deep_hash({}))\nassert(deep_hash({x = 3}) == deep_hash({x = 3}))\nassert(deep_hash({x = {y = 444}}, 2) == deep_hash({x = {y = 111}}, 2))\nassert(deep_hash({xxx = {y = 444}}, 2) != deep_hash({qqq = {y = 444}}, 2))\nassert(deep_hash([{x = 3}, null, 0.75]) == deep_hash([{x = 3}, null, 0.75]))\nassert(deep_hash([{x = 3}, null, 0.75]) != deep_hash([{x = 4}, null, 0.75]))\n\nassert(deep_hash([1, 2, 3]) == deep_hash([1, 2, 3]))\nassert(deep_hash([1, 2, 3]) != deep_hash([3, 2, 1]))\n\nassert(deep_hash(inst1) == deep_hash(inst2))\ninst2.w = 999\nassert(deep_hash(inst1) != deep_hash(inst2))\n\nassert(hash(\"a123\") == deep_hash(\"a123\"))\nassert(hash(\"a123\") != deep_hash(\"XXX\"))\n\nassert(hash(\"a123\") == hash(\"a123\"))\nassert(hash(\"a123\") != hash(\"XXX\"))\n\nassert(hash(0) != hash(false))\nassert(hash(0) != hash(0.0))\nassert(hash(-0.0) != hash(0.0))\nassert(hash(\"\") != hash(0))\nassert(hash(\"\") != hash([]))\nassert(hash({}) != hash([]))\n\nassert(hash(0) > 100000)\nassert(hash(null) > 100000)\nassert(hash(0.0) > 100000)\nassert(hash(\"\") > 100000)\nassert(hash({}) > 100000)\nassert(hash([]) > 100000)\nassert(hash(class {}) > 100000)\n\nlocal arr = []\nlocal cnt = 1000\nwhile (cnt--) {\n  arr.append(cnt)\n  assert(deep_hash(arr) > 0)\n}\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/deep_hash.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/deep_regex.nut",
    "content": "// Test: Regex matching with deeply nested repetitions\n// Tries to overflow stack during match execution\nlet { regexp } = require(\"string\")\n\n// Deep alternation chains that create recursive match paths\nprint(\"Test 1: nested groups with +\\n\")\nlocal depths = [1, 10, 100, 300, 600, 900, 1900, 2800, 5000, 10000, 50000]\nforeach (depth in depths) {\n  local pattern = \"\"\n  for (local i = 0; i < depth; i++)\n    pattern += \"(\"\n  pattern += \"a+\"\n  for (local i = 0; i < depth; i++)\n    pattern += \")\"\n  print(\"  depth \" + depth + \"... \")\n  try {\n    local r = regexp(pattern)\n    local res = r.search(\"aaa\")\n    print(\"OK\\n\")\n  } catch(e) {\n    print(\"ERROR: \" + e + \"\\n\")\n    break\n  }\n}\n\n// Test 2: Long alternation creating wide regex tree\nprint(\"Test 2: long alternation\\n\")\nlocal alt_counts = [1, 10, 100, 300, 600, 900, 1900, 2800, 5000, 10000, 50000]\nforeach (count in alt_counts) {\n  local pattern = \"\"\n  for (local i = 0; i < count; i++) {\n    if (i > 0) pattern += \"|\"\n    pattern += \"a\"\n  }\n  print(\"  alternatives \" + count + \"... \")\n  try {\n    local r = regexp(pattern)\n    local res = r.search(\"a\")\n    print(\"OK\\n\")\n  } catch(e) {\n    print(\"ERROR: \" + e + \"\\n\")\n    break\n  }\n}\n\n// Test 3: Repetition operator with long input\nprint(\"Test 3: long match\\n\")\nlocal lens = [1, 10, 100, 300, 600, 900, 1900, 2800, 5000, 10000, 50000]\nforeach (len in lens) {\n  local str = \"\"\n  for (local i = 0; i < len; i++)\n    str += \"a\"\n  print(\"  len \" + len + \"... \")\n  try {\n    local r = regexp(@\"a+\")\n    local res = r.search(str)\n    print(\"OK\\n\")\n  } catch(e) {\n    print(\"ERROR: \" + e + \"\\n\")\n    break\n  }\n}\n\nprint(\"ALL DONE\\n\")\n"
  },
  {
    "path": "testData/exec/stdlib/deep_regex.out",
    "content": "Test 1: nested groups with +\n  depth 1... OK\n  depth 10... OK\n  depth 100... OK\n  depth 300... ERROR: pattern exceeds maximum allowed nesting depth\nTest 2: long alternation\n  alternatives 1... OK\n  alternatives 10... OK\n  alternatives 100... OK\n  alternatives 300... OK\n  alternatives 600... OK\n  alternatives 900... OK\n  alternatives 1900... ERROR: pattern too complex\nTest 3: long match\n  len 1... OK\n  len 10... OK\n  len 100... OK\n  len 300... OK\n  len 600... OK\n  len 900... OK\n  len 1900... OK\n  len 2800... OK\n  len 5000... OK\n  len 10000... OK\n  len 50000... OK\nALL DONE\n"
  },
  {
    "path": "testData/exec/stdlib/delegates.nut",
    "content": "from \"string\" import *\n\nprint(\"=== STRING METHODS TESTS ===\\n\")\n\nlet s = \"Hello, World!\"\nprintln(\"len: \" + s.len())  // 13\nprintln(\"tostring: '\" + s.tostring() + \"'\")\ntry println(\"tointeger (invalid): \" + s.tointeger()) catch(e) println(e)\ntry println(\"tofloat (invalid): \" + s.tofloat()) catch(e) println(e)\nprintln(\"hash: \" + s.hash())\n\nprintln(\"tolower: '\" + s.tolower() + \"'\")\nprintln(\"toupper: '\" + s.toupper() + \"'\")\nprintln(\"tolower partial: '\" + s.tolower(0, 5) + \"'\")\nprintln(\"toupper partial: '\" + s.toupper(7, 12) + \"'\")\n\nprintln(\"indexof 'World': \" + s.indexof(\"World\"))\nprintln(\"indexof 'o' from 5: \" + s.indexof(\"o\", 5))\nprintln(\"contains 'World': \" + s.contains(\"World\"))\nprintln(\"contains 'world' (case-sensitive): \" + s.contains(\"world\"))\nprintln(\"hasindex 0: \" + s.hasindex(0))\nprintln(\"hasindex 100: \" + s.hasindex(100))\nprintln(\"startswith 'Hello': \" + s.startswith(\"Hello\"))\nprintln(\"endswith 'World!': \" + s.endswith(\"World!\"))\n\nprintln(\"slice(0,5): '\" + s.slice(0, 5) + \"'\")\nprintln(\"slice(7): '\" + s.slice(7) + \"'\")\nprintln(\"replace 'World' -> 'Squirrel': '\" + s.replace(\"World\", \"Squirrel\") + \"'\")\n\nlet parts = s.split(\", \")\nprintln(\"split: [\" + \"|\".join(parts) + \"]\")\nprintln(\"join: '\" + \" \".join([\"Hello\", \"Squirrel\", \"World\"]) + \"'\")\nprintln(\"concat: '\" + \"\".concat(\"a\", \"b\", \"c\") + \"'\")\n\nprintln(\"strip: '\" + \"  test  \".strip() + \"'\")\nprintln(\"lstrip: '\" + \"  test  \".lstrip() + \"'\")\nprintln(\"rstrip: '\" + \"  test  \".rstrip() + \"'\")\nprintln(\"escape: '\" + \"\\n\\t\\\"\\'\\\\\".escape() + \"'\")\n\nprintln(\"subst: '\" + \"Hello {0}, {1}!\".subst(\"Squirrel\", \"World\") + \"'\")\nprintln(\"format: '\" + format(\"Value: %d\", 42) + \"'\")\nprintf(\"printf test: %s %d\\n\", \"value\", 100)\n\nlet chars = \"a,b:c;d\".split_by_chars(\",;:\", false)\nprintln(\"split_by_chars: [\" + \"|\".join(chars) + \"]\")\n\nlet s2 = clone s\nprintln(\"clone equality: \" + (s == s2))\n\nprint(\"\\n=== NUMERIC METHODS TESTS ===\\n\")\n\nlet i = 42\nprintln(\"integer.tostring: '\" + i.tostring() + \"'\")\nprintln(\"integer.tointeger: \" + i.tointeger())\nprintln(\"integer.tofloat: \" + i.tofloat())\nprintln(\"integer.tochar: '\" + i.tochar() + \"'\")  // '*'\nprintln(\"integer.clone: \" + clone(i))\n\nlet f = 3.14\nprintln(\"float.tostring: '\" + f.tostring() + \"'\")\nprintln(\"float.tointeger: \" + f.tointeger())\nprintln(\"float.tofloat: \" + f.tofloat())\nprintln(\"float.clone: \" + clone(f))\n\n{\nlet b = true\nprintln(\"bool.tostring: '\" + b.tostring() + \"'\")\nprintln(\"bool.tointeger: \" + b.tointeger())\nprintln(\"bool.tofloat: \" + b.tofloat())\nprintln(\"bool.tochar: '\" + b.tochar() + \"'\")  // '\\x01'\nprintln(\"bool.clone: \" + clone(b))\n}\n\nprint(\"\\n=== CLOSURE METHODS TESTS ===\\n\")\n\nlocal free_var = \"captured\"\nlocal closure = @(x) x + \" \" + free_var\n\nprintln(\"closure.call: '\" + closure.call(this, \"test\") + \"'\")\nprintln(\"closure.pcall: \" + closure.pcall(this, \"safe\").tostring())\n\nlocal err_closure = function err_closure() { throw \"error\" }\nlocal res = \"X\"\ntry res = err_closure.pcall(this) catch (e) println(e)\nprintln(\"closure.pcall error: \" + (res.len() == 2 ? res[1] : \"success\"))\n\nlocal finfo = closure.getfuncinfos()\nprintln(\"closure.getfuncinfos keys: \" + finfo.rawin(\"name\") + \", \" + finfo.rawin(\"nclosures\"))\n\nlocal fvinfo = closure.getfreevar(0)\nprintln(\"closure.getfreevar name: '\" + fvinfo.name + \"', value: '\" + fvinfo.value + \"'\")\n\nlocal env = { prefix = \"env:\" }\nlocal bound = closure.bindenv(env)\n\nprintln(\"closure.clone type: \" + typeof(clone(closure)))\n\nprint(\"\\n=== CLASS & INSTANCE METHODS TESTS ===\\n\")\n\nclass TestClass {\n    value = null\n    constructor(x) {\n        this.value = x\n    }\n    function method() {\n        return this.value * 2\n    }\n}\n\nprintln(\"class.rawget 'method' exists: \" + TestClass.rawin(\"method\"))\nTestClass.rawset(\"dynamic\", 100)\nprintln(\"class.rawget dynamic: \" + TestClass.rawget(\"dynamic\"))\nprintln(\"class.getbase: \" + (TestClass.getbase() == null ? \"null\" : \"not null\"))\nprintln(\"class.getfuncinfos: \" + typeof(TestClass.getfuncinfos()))\nprintln(\"class.hasindex 'value': \" + TestClass.hasindex(\"value\"))\nprintln(\"class.is_frozen initially: \" + TestClass.is_frozen())\nTestClass.lock()\nprintln(\"class.is_frozen after freeze: \" + TestClass.is_frozen())\n\nlocal inst = TestClass(21)\n\nprintln(\"instance.rawget 'value': \" + inst.rawget(\"value\"))\ninst.rawset(\"value\", 42)\nprintln(\"instance.rawget after set: \" + inst.rawget(\"value\"))\nprintln(\"instance.rawin 'method': \" + inst.rawin(\"method\"))\nprintln(\"instance.getfuncinfos type: \" + typeof(inst.getfuncinfos()))\nprintln(\"instance.hasindex 0: \" + inst.hasindex(0))  // false для объекта\nprintln(\"instance.is_frozen: \" + inst.is_frozen())\n\nlocal inst2 = clone(inst)\ninst2.value = 100\nprintln(\"clone isolation (original still 42): \" + (inst.value == 42))\n\n{\nlocal t = {[1] = \"123\", [2] = \"asd\"}\nt.swap(1, 2)\nprintln(\"swap result: t[1]=\" + t[1] + \", t[2]=\" + t[2])\n}\n\nlocal meta = inst.getmetamethod(\"_add\")\nprintln(\"getmetamethod 'add': \" + (meta == null ? \"null\" : \"exists\"))\n\nprint(\"\\n=== ALL TESTS COMPLETED ===\\n\")\n"
  },
  {
    "path": "testData/exec/stdlib/delegates.out",
    "content": "=== STRING METHODS TESTS ===\nlen: 13\ntostring: 'Hello, World!'\ncannot convert the string to integer\ncannot convert the string to float\nhash: 4027599776755331851\ntolower: 'hello, world!'\ntoupper: 'HELLO, WORLD!'\ntolower partial: 'hello, World!'\ntoupper partial: 'Hello, WORLD!'\nindexof 'World': 7\nindexof 'o' from 5: 8\ncontains 'World': true\ncontains 'world' (case-sensitive): false\nhasindex 0: true\nhasindex 100: false\nstartswith 'Hello': true\nendswith 'World!': true\nslice(0,5): 'Hello'\nslice(7): 'World!'\nreplace 'World' -> 'Squirrel': 'Hello, Squirrel!'\nsplit: [Hello|World!]\njoin: 'Hello Squirrel World'\nconcat: 'abc'\nstrip: 'test'\nlstrip: 'test  '\nrstrip: '  test'\nescape: '\\x0a\\x09\\\"\\'\\\\'\nsubst: 'Hello Squirrel, World!'\nformat: 'Value: 42'\nprintf test: value 100\nsplit_by_chars: [a|b|c|d]\nclone equality: true\n\n=== NUMERIC METHODS TESTS ===\ninteger.tostring: '42'\ninteger.tointeger: 42\ninteger.tofloat: 42\ninteger.tochar: '*'\ninteger.clone: 42\nfloat.tostring: '3.14'\nfloat.tointeger: 3\nfloat.tofloat: 3.14\nfloat.clone: 3.14\nbool.tostring: 'true'\nbool.tointeger: 1\nbool.tofloat: 1\nbool.tochar: '\u0001'\nbool.clone: true\n\n=== CLOSURE METHODS TESTS ===\nclosure.call: 'test captured'\nclosure.pcall: safe captured\nerror\nclosure.pcall error: success\nclosure.getfuncinfos keys: true, false\nclosure.getfreevar name: 'free_var', value: 'captured'\nclosure.clone type: function\n\n=== CLASS & INSTANCE METHODS TESTS ===\nclass.rawget 'method' exists: true\nclass.rawget dynamic: 100\nclass.getbase: null\nclass.getfuncinfos: null\nclass.hasindex 'value': true\nclass.is_frozen initially: false\nclass.is_frozen after freeze: false\ninstance.rawget 'value': 21\ninstance.rawget after set: 42\ninstance.rawin 'method': true\ninstance.getfuncinfos type: null\ninstance.hasindex 0: false\ninstance.is_frozen: false\nclone isolation (original still 42): true\nswap result: t[1]=asd, t[2]=123\ngetmetamethod 'add': null\n\n=== ALL TESTS COMPLETED ===\n"
  },
  {
    "path": "testData/exec/stdlib/deser_oom.nut",
    "content": "let { blob } = require(\"iostream\")\n\nlocal function make_payload(type_byte) {\n    local b = blob()\n    b.writen(0xEA, 'b')       // START_MARKER\n    b.writen(type_byte, 'b')  // object type + size variant\n    b.writen(-1, 'i')         // 0xFFFFFFFF as uint32_t  (~4 GB)\n    b.seek(0, 'b')\n    return b\n}\n\nprintln(\"VARIANT 1: TP_STRING len=0xFFFFFFFF -> sq_getscratchpad(vm, ~4GB)\")\ntry { make_payload(0x43).readobject() }\ncatch(e) { println(\"  caught: \" + e) }\n\nprintln(\"VARIANT 2: TP_ARRAY size=0xFFFFFFFF -> sq_newarray(vm, ~4GB)\")\ntry { make_payload(0x52).readobject() }\ncatch(e) { println(\"  caught: \" + e) }\n\nprintln(\"VARIANT 3: TP_TABLE size=0xFFFFFFFF -> sq_newtableex(vm, ~4GB)\")\ntry { make_payload(0x62).readobject() }\ncatch(e) { println(\"  caught: \" + e) }\n\nprintln(\"done\")\n"
  },
  {
    "path": "testData/exec/stdlib/deser_oom.out",
    "content": "VARIANT 1: TP_STRING len=0xFFFFFFFF -> sq_getscratchpad(vm, ~4GB)\n  caught: String too large during deserialization\nVARIANT 2: TP_ARRAY size=0xFFFFFFFF -> sq_newarray(vm, ~4GB)\n  caught: Array too large during deserialization\nVARIANT 3: TP_TABLE size=0xFFFFFFFF -> sq_newtableex(vm, ~4GB)\n  caught: Table too large during deserialization\ndone\n"
  },
  {
    "path": "testData/exec/stdlib/docstring.nut",
    "content": "let debug = require(\"debug\")\n\nfunction empty_fn() {}\nclass EmptyClass {}\nlet empty_instance = EmptyClass()\nlet empty_table = {}\n\nclass A {\n  @@\"Class docstring\"\n  function x() { return 0; }\n}\n\nlet instance = A()\n\nfunction test() {\n  return {\n    @@\"Table docstring\"\n    x = 4\n    fn = function() {\n      @@\"Function docstring\"\n      return 1234\n    }\n  }\n}\n\nprintln(debug.doc(empty_fn))\nprintln(debug.doc(EmptyClass))\nprintln(debug.doc(empty_instance))\nprintln(debug.doc(empty_table))\nprintln(debug.doc(A))\nprintln(debug.doc(instance))\nprintln(debug.doc(test()))\nprintln(debug.doc(test().fn))\nprintln(debug.doc(debug.doc))\n"
  },
  {
    "path": "testData/exec/stdlib/docstring.out",
    "content": "null\nnull\nnull\nnull\nClass docstring\nClass docstring\nTable docstring\nFunction docstring\nReturns a documentation string for a function, class, or table\n"
  },
  {
    "path": "testData/exec/stdlib/file_io.nut",
    "content": "let io = require(\"io\")\nlet { file } = io\nlet { remove } = require(\"system\")\n\nlet f = file(\"qtest_file_io.txt\", \"wb+\")\nassert(typeof f == \"file\")\nf.close()\n\nlet f2 = file(\"qtest_file_io.txt\", \"rb\")\nassert(typeof f2 == \"file\")\nf2.close()\n\nremove(\"qtest_file_io.txt\")\n\n// userpointer branch: stdout/stdin/stderr are wrapped via sqstd_createfile\nassert(typeof io.stdout == \"file\")\nassert(typeof io.stdin == \"file\")\nassert(typeof io.stderr == \"file\")\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label}\") } catch (_) {}\n}\n\nmustThrow(\"file.ctor.path=null\",  @() file(null, \"rb\"))\nmustThrow(\"file.missing\",         @() file(\"__no_such_file_XYZ_123__.txt\", \"rb\"))\nmustThrow(\"file.str+int\",         @() file(\"qtest_any.txt\", 5))\nmustThrow(\"file.str+null\",        @() file(\"qtest_any.txt\", null))\nmustThrow(\"file.bad_mode.letter\", @() file(\"qtest_bad1.txt\", \"zzz\"))\nmustThrow(\"file.bad_mode.empty\",  @() file(\"qtest_bad2.txt\", \"\"))\nmustThrow(\"file.bad_mode.suffix\", @() file(\"qtest_bad3.txt\", \"r?\"))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/file_io.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/math_funcs.nut",
    "content": "let m = require(\"math\")\n\nassert(m.sqrt(4.0) == 2.0)\nassert(m.sqrt(9.0) == 3.0)\n\nassert(m.sin(0.0) == 0.0)\nassert(m.cos(0.0) == 1.0)\nassert(m.tan(0.0) == 0.0)\n\nassert(m.asin(0.0) == 0.0)\nassert(m.acos(1.0) == 0.0)\n\nassert(m.log(1.0) == 0.0)\nassert(m.log10(1.0) == 0.0)\nassert(m.log10(100.0) == 2.0)\n\nassert(m.atan(0.0) == 0.0)\nassert(m.atan2(0.0, 1.0) == 0.0)\n\nassert(m.pow(2.0, 3.0) == 8.0)\nassert(m.pow(10.0, 2.0) == 100.0)\n\nassert(m.floor(1.7) == 1.0)\nassert(m.ceil(1.2) == 2.0)\nassert(m.round(1.5) == 2.0)\nassert(m.round(1.4) == 1.0)\n\nassert(m.exp(0.0) == 1.0)\n\nassert(m.fabs(-3.5) == 3.5)\nassert(m.fabs(3.5) == 3.5)\n\nassert(m.abs(-7) == 7)\nassert(m.abs(7) == 7)\nassert(m.abs(-3.5) == 3.5)\n\nassert(m.asin(2.0) == m.asin(1.0))\nassert(m.acos(-2.0) == m.acos(-1.0))\n\nm.srand(12345)\nlet r1 = m.rand()\nassert(typeof r1 == \"integer\")\nassert(r1 >= 0)\nassert(r1 <= m.RAND_MAX)\n\nm.srand(12345)\nlet r1again = m.rand()\nassert(r1 == r1again)\n\nassert(m.PI > 3.14 && m.PI < 3.15)\nassert(m.RAND_MAX > 0)\nassert(m.FLT_MAX > 0.0)\nassert(m.FLT_MIN > 0.0)\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nmustThrow(\"sqrt\",   @() m.sqrt(null))\nmustThrow(\"sin\",    @() m.sin(null))\nmustThrow(\"cos\",    @() m.cos(null))\nmustThrow(\"asin\",   @() m.asin(null))\nmustThrow(\"acos\",   @() m.acos(null))\nmustThrow(\"log\",    @() m.log(null))\nmustThrow(\"log10\",  @() m.log10(null))\nmustThrow(\"tan\",    @() m.tan(null))\nmustThrow(\"atan\",   @() m.atan(null))\nmustThrow(\"atan2.1\",@() m.atan2(null, 1.0))\nmustThrow(\"atan2.2\",@() m.atan2(1.0, null))\nmustThrow(\"pow.1\",  @() m.pow(null, 2.0))\nmustThrow(\"pow.2\",  @() m.pow(2.0, null))\nmustThrow(\"floor\",  @() m.floor(null))\nmustThrow(\"ceil\",   @() m.ceil(null))\nmustThrow(\"round\",  @() m.round(null))\nmustThrow(\"exp\",    @() m.exp(null))\nmustThrow(\"srand\",  @() m.srand(null))\nmustThrow(\"fabs\",   @() m.fabs(null))\nmustThrow(\"abs\",    @() m.abs(null))\nmustThrow(\"min.1\",  @() m.min(null, 1))\nmustThrow(\"min.2\",  @() m.min(1, null))\nmustThrow(\"max.1\",  @() m.max(null, 1))\nmustThrow(\"max.2\",  @() m.max(1, null))\nmustThrow(\"clamp.1\",@() m.clamp(null, 0, 1))\nmustThrow(\"clamp.2\",@() m.clamp(0, null, 1))\nmustThrow(\"clamp.3\",@() m.clamp(0, 0, null))\nmustThrow(\"deep_hash.2\", @() m.deep_hash({}, null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/math_funcs.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/math_min_max_clamp.nut",
    "content": "\n\nlet math = require(\"math\")\n\n\nprintln($\"min(-1, 1, 2, 3, 4, 5, -1000, 6, 7): {math.min(-1, 1, 2, 3, 4, 5, -1000, 6, 7)}\")\nprintln($\"max(-1, 1, 2, 3, 4, 5, -1000, 8, 9): {math.max(-1, 1, 2, 3, 4, 5, -1000, 8, 9)}\")\nprintln($\"clamp(10, -100, 300): {math.clamp(10, -100, 300)}\")\n"
  },
  {
    "path": "testData/exec/stdlib/math_min_max_clamp.out",
    "content": "min(-1, 1, 2, 3, 4, 5, -1000, 6, 7): -1000\nmax(-1, 1, 2, 3, 4, 5, -1000, 8, 9): 9\nclamp(10, -100, 300): 10\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization.nut",
    "content": "let { blob } = require(\"iostream\")\n\nfunction deep_compare(a, b)\n{\n  if (type(a) != type(b))\n    return false\n\n  if (type(a) == \"array\") {\n    if (a.len() != b.len())\n      return false\n\n    for (local i = 0; i < a.len(); i++)\n      if (!deep_compare(a[i], b[i]))\n        return false\n\n    return true\n  }\n  else if (type(a) == \"table\") {\n    if (a.len() != b.len())\n      return false\n\n    local keys = []\n    foreach (k, _ in a)\n      keys.append(k)\n    keys.sort()\n\n    foreach (_, key in keys)\n      if (!deep_compare(a[key], b[key]))\n        return false\n\n    return true\n  }\n  else\n    return a == b\n}\n\n\nlet a = {x = 1.0, y = [{}, {z = 5.0}]}\nlet b = {y = [{}, {z = 5.0}], x = 1.0}\nprintln($\"deep_compare test1: {deep_compare(a, b)}\")\nb.y[1].z = 5\nprintln($\"deep_compare test2: {deep_compare(a, b)}\")\n\n\nfunction test(obj, obj_type) {\n  local b = blob()\n  b.writeobject(obj)\n  b.seek(0)\n  let y = b.readobject()\n  println($\"test {obj_type}: {deep_compare(obj, y)}\")\n}\n\ntest(null, \"null\")\n\ntest(true, \"bool1\")\ntest(false, \"bool2\")\n\ntest(0, \"int0\")\ntest(-1, \"int1\")\ntest(12, \"int2\")\ntest(128, \"int3\")\ntest(32767, \"int4\")\ntest(11132767, \"int5\")\n\ntest(0.0, \"float0\")\ntest(0.5, \"float1\")\ntest(10.25, \"float2\")\ntest(-1e30, \"float3\")\n\ntest(\"\", \"str0\")\ntest(\"a\", \"str1\")\ntest(\"aaaabc\", \"str2\")\ntest(\"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" +\n     \"aaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", \"str3\")\n\n\ntest([], \"array0\")\ntest([222], \"array1\")\ntest([222, 333, null, -5.0, \"www\"], \"array2\")\n\ntest([\"www\", \"www\", \"\", \"\", \"\", \"www\", null, \"www\"], \"array_str\")\n\ntest({}, \"table0\")\ntest({xx = \"xx\"}, \"table1\")\ntest({[55] = \"xx\", [0] = 444}, \"table2\")\n\ntest({x = {x = {x = {x = [1, \"222\", 3, {y = {y = {y = [4, null, \"333\", \"222\"]}}}, true, 6, false] }}}}, \"recursion\")\n\ntry {\n  local c = class {}\n  test(c, \"err1\")\n} catch (e) {\n  println(e)\n}\n\ntry {\n  local c = class {}\n  test([null, {x = c}], \"err1\")\n} catch (e) {\n  println(e)\n}\n\nfunction testx(x) {\n  try {\n    local c = blob()\n    let y = c.readobject()\n    println(y)\n  } catch (e) {\n    println(e)\n  }\n  return x + 1\n}\n\nprintln(testx(110))\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization.out",
    "content": "deep_compare test1: true\ndeep_compare test2: false\ntest null: true\ntest bool1: true\ntest bool2: true\ntest int0: true\ntest int1: true\ntest int2: true\ntest int3: true\ntest int4: true\ntest int5: true\ntest float0: true\ntest float1: true\ntest float2: true\ntest float3: true\ntest str0: true\ntest str1: true\ntest str2: true\ntest str3: true\ntest array0: true\ntest array1: true\ntest array2: true\ntest array_str: true\ntest table0: true\ntest table1: true\ntest table2: true\ntest recursion: true\nUnsupported object type for serialization\nUnsupported object type for serialization\nUnexpected end of data during deserialization\n111\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization_errors.nut",
    "content": "let { get_stack_top } = require(\"debug\")\nlet { blob } = require(\"iostream\")\n\nlet refStackTop = get_stack_top()\n\n// Test 1: Maximum serialization depth exceeded\nfunction testMaxDepth()\n{\n  local arr = []\n  local current = arr\n  for (local i = 0; i < 300; i++) {\n    current.append([])\n    current = current[0]\n  }\n\n  local b = blob()\n  try {\n    b.writeobject(arr)\n    println(\"FAIL: Max depth test should have failed\")\n  } catch (e) {\n    println(\"PASS: Max depth test - \" + e)\n  }\n}\n\n// Test 2: Unsupported class for serialization\nfunction testUnsupportedClass()\n{\n  class Unsupported {\n    x = 1\n  }\n\n  local obj = Unsupported()\n  local b = blob()\n  try {\n    b.writeobject(obj)\n    println(\"FAIL: Unsupported class test should have failed\")\n  } catch (e) {\n    println(\"PASS: Unsupported class test - \" + e)\n  }\n}\n\n// Test 3: Missing __getstate method\nfunction testMissingGetState()\n{\n  class NoGetState {\n    x = 1\n  }\n\n  local obj = NoGetState()\n  local b = blob()\n  try {\n    b.writeobject(obj, { NoGetState = NoGetState })\n    println(\"FAIL: Missing __getstate test should have failed\")\n  } catch (e) {\n    println(\"PASS: Missing __getstate test - \" + e)\n  }\n}\n\n// Test 4: Invalid __getstate method (not a closure)\nfunction testInvalidGetState()\n{\n  class InvalidGetState {\n    x = 1\n    __getstate = 123 // not a function\n  }\n\n  local obj = InvalidGetState()\n  local b = blob()\n  try {\n    b.writeobject(obj, { InvalidGetState = InvalidGetState })\n    println(\"FAIL: Invalid __getstate test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid __getstate test - \" + e)\n  }\n}\n\n// Test 5: Invalid available classes (not a table)\nfunction testInvalidAvailableClasses()\n{\n  class ValidClass {\n    x = 1\n    function __getstate() { return this.x }\n    function __setstate(s) { this.x = s }\n  }\n\n  local obj = ValidClass()\n  local b = blob()\n  try {\n    b.writeobject(obj, \"not a table\")\n    println(\"FAIL: Invalid available classes test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid available classes test - \" + e)\n  }\n}\n\n// Test 6: Class not found in available classes during deserialization\nfunction testClassNotFound()\n{\n  class ValidClass {\n    x = 1\n    function __getstate() { return this.x }\n    function __setstate(s) { this.x = s }\n  }\n\n  local obj = ValidClass()\n  local b = blob()\n  b.writeobject(obj, { ValidClass = ValidClass })\n\n  b.seek(0)\n  try {\n    b.readobject({}) // empty available classes\n    println(\"FAIL: Class not found test should have failed\")\n  } catch (e) {\n    println(\"PASS: Class not found test - \" + e)\n  }\n}\n\n// Test 7: Invalid constructor parameters\nfunction testInvalidConstructor()\n{\n  class InvalidConstructor {\n    x = 1\n    constructor(_a, _b, _c) {} // requires 3 params\n    function __getstate() { return this.x }\n    function __setstate(s) { this.x = s }\n  }\n\n  local obj = InvalidConstructor(1,2,3)\n  local b = blob()\n  try {\n    b.writeobject(obj, { InvalidConstructor = InvalidConstructor })\n    b.seek(0)\n    local x = b.readobject()\n    println(\"FAIL: Invalid constructor test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid constructor test - \" + e)\n  }\n}\n\n// Test 8: Invalid start/end markers\nfunction testInvalidMarkers()\n{\n  local b = blob()\n  b.writen(1, 'c') // invalid start marker\n\n  try {\n    b.seek(0)\n    b.readobject({})\n    println(\"FAIL: Invalid start marker test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid start marker test - \" + e)\n  }\n\n  // Test with valid start but invalid end marker\n  local b2 = blob()\n  b2.writeobject(123)\n\n  // corrupt the end\n  b2.seek(b.len() - 1)\n  b2.writen(1, 'c')\n\n  try {\n    b2.seek(0)\n    b2.readobject({})\n    println(\"FAIL: Invalid end marker test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid end marker test - \" + e)\n  }\n}\n\n// Test 9: Unexpected end of data\nfunction testUnexpectedEnd()\n{\n  local b = blob()\n  b.writeobject([1,2,3])\n  b.resize(b.len() - 2) // truncate last 2 bytes\n\n  try {\n    b.seek(0)\n    b.readobject({})\n    println(\"FAIL: Unexpected end test should have failed\")\n  } catch (e) {\n    println(\"PASS: Unexpected end test - \" + e)\n  }\n}\n\n// Run all tests\ntestMaxDepth()\ntestUnsupportedClass()\ntestMissingGetState()\ntestInvalidGetState()\ntestInvalidAvailableClasses()\ntestClassNotFound()\ntestInvalidConstructor()\ntestInvalidMarkers()\ntestUnexpectedEnd()\n\nlet stackTop = get_stack_top()\nassert(stackTop == refStackTop)\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization_errors.out",
    "content": "PASS: Max depth test - Maximum serialization depth exceeded\nPASS: Unsupported class test - Unsupported class for serialization\nPASS: Missing __getstate test - Instance must have __getstate method for serialization\nPASS: Invalid __getstate test - Instance method __getstate must be a closure\nPASS: Invalid available classes test - parameter 2 of 'writeobject' has an invalid type 'string' ; expected: 'null|table'\nPASS: Class not found test - Class not found in available classes during deserialization\nPASS: Invalid constructor test - Instance found during deserialization, but available classes not set or not a table\nPASS: Invalid start marker test - Invalid start marker during deserialization\nPASS: Invalid end marker test - Invalid start marker during deserialization\nPASS: Unexpected end test - Unexpected end of data during deserialization\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization_errors_arg.nut",
    "content": "let { get_stack_top } = require(\"debug\")\nlet { blob } = require(\"iostream\")\n\nlet refStackTop = get_stack_top()\n\nfunction testInvalidAvailableClasses()\n{\n  class ValidClass {\n    x = 1\n    function __getstate(_available_classes) { return this.x }\n    function __setstate(s, _available_classes) { this.x = s }\n  }\n\n  local obj = ValidClass()\n  local b = blob()\n  try {\n    b.writeobject(obj, \"not a table\")\n    println(\"FAIL: Invalid available classes test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid available classes test - \" + e)\n  }\n}\n\nfunction testClassNotFound()\n{\n  class ValidClass {\n    x = 1\n    function __getstate(_available_classes) { return this.x }\n    function __setstate(s, _available_classes) { this.x = s }\n  }\n\n  local obj = ValidClass()\n  local b = blob()\n  b.writeobject(obj, { ValidClass = ValidClass })\n\n  b.seek(0)\n  try {\n    b.readobject({}) // empty available classes\n    println(\"FAIL: Class not found test should have failed\")\n  } catch (e) {\n    println(\"PASS: Class not found test - \" + e)\n  }\n}\n\nfunction testInvalidConstructor()\n{\n  class InvalidConstructor {\n    x = 1\n    constructor(_a, _b, _c) {} // requires 3 params\n    function __getstate(_available_classes) { return this.x }\n    function __setstate(s, _available_classes) { this.x = s }\n  }\n\n  local obj = InvalidConstructor(1,2,3)\n  local b = blob()\n  try {\n    b.writeobject(obj, { InvalidConstructor = InvalidConstructor })\n    b.seek(0)\n    local x = b.readobject()\n    println(\"FAIL: Invalid constructor test should have failed\")\n  } catch (e) {\n    println(\"PASS: Invalid constructor test - \" + e)\n  }\n}\n\ntestInvalidAvailableClasses()\ntestClassNotFound()\ntestInvalidConstructor()\n\nlet stackTop = get_stack_top()\nassert(stackTop == refStackTop)\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization_errors_arg.out",
    "content": "PASS: Invalid available classes test - parameter 2 of 'writeobject' has an invalid type 'string' ; expected: 'null|table'\nPASS: Class not found test - Class not found in available classes during deserialization\nPASS: Invalid constructor test - Instance found during deserialization, but available classes not set or not a table\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization_valid.nut",
    "content": "let { get_stack_top } = require(\"debug\")\nlet { blob } = require(\"iostream\")\n\nfunction testValidStringIndex()\n{\n  // Create an array with multiple strings to test string table references\n  local strings = [\n    \"first string\",\n    \"second string\",\n    \"third string\"\n  ]\n\n  local b = blob()\n  b.writeobject(strings)\n\n  b.seek(0)\n  try {\n    local result = b.readobject({})\n\n    // Verify all strings were deserialized correctly\n    if (result.len() != 3) {\n      println(\"FAIL: Valid string index test - wrong array length\")\n      return\n    }\n\n    if (result[0] != \"first string\" ||\n      result[1] != \"second string\" ||\n      result[2] != \"third string\") {\n      println(\"FAIL: Valid string index test - string content mismatch\")\n      return\n    }\n\n    println(\"PASS: Valid string index test\")\n  } catch (e) {\n    println(\"FAIL: Valid string index test - unexpected error: \" + e)\n  }\n}\n\nfunction testValidClassIndex()\n{\n  class TestClassA {\n    value = null\n    constructor(v = null) { this.value = v }\n    function __getstate(_available_classes) { return this.value }\n    function __setstate(v) { this.value = v }\n  }\n  class TestClassB {\n    data = null\n    constructor(d = null) { this.data = d }\n    function __getstate() { return this.data }\n    function __setstate(d, _available_classes) { this.data = d }\n  }\n\n  // Create an array with multiple instances to test class table references\n  local objects = [\n    TestClassA(100),\n    TestClassB(\"test\"),\n    TestClassA(200),\n    TestClassB(\"data\")\n  ]\n\n  local b = blob()\n  b.writeobject(objects, { TestClassA = TestClassA, TestClassB = TestClassB })\n\n  b.seek(0)\n  try {\n    local result = b.readobject({ TestClassA = TestClassA, TestClassB = TestClassB })\n\n    // Verify all objects were deserialized correctly\n    if (result.len() != 4) {\n      println(\"FAIL: Valid class index test - wrong array length\")\n      return\n    }\n\n    if (result[0].value != 100 ||\n      result[1].data != \"test\" ||\n      result[2].value != 200 ||\n      result[3].data != \"data\") {\n      println(\"FAIL: Valid class index test - object content mismatch\")\n      return\n    }\n\n    println(\"PASS: Valid class index test\")\n  } catch (e) {\n    println(\"FAIL: Valid class index test - unexpected error: \" + e)\n  }\n}\n\nlet refStackTop = get_stack_top()\n// Run the valid tests\ntestValidStringIndex()\ntestValidStringIndex()\ntestValidClassIndex()\ntestValidClassIndex()\nlet stackTop = get_stack_top()\nassert(refStackTop == stackTop)\n"
  },
  {
    "path": "testData/exec/stdlib/obj_serialization_valid.out",
    "content": "PASS: Valid string index test\nPASS: Valid string index test\nPASS: Valid class index test\nPASS: Valid class index test\n"
  },
  {
    "path": "testData/exec/stdlib/rawdelete.nut",
    "content": "for (local size = 1; size < 17; size++) {\n    for (local iter = 0; iter < 2000; iter++) {\n        //println(\"============\")\n        local seed = size + iter * 21\n        local t = {}\n        local indices = []\n        for (local i = 0; i < size; i++) {\n            seed++\n            seed *= 198375\n            indices.append(seed)\n            t[seed] <- seed\n        }\n\n        //println($\"before delete indices.len() = {indices.len()}\")\n\n        for (local i = 0; i < iter % size; i++) {\n            if (iter & 1) {\n                t.$rawdelete(indices[0])\n                indices.remove(0)\n            }\n            else {\n                t.$rawdelete(indices[indices.len() - 1])\n                indices.remove(indices.len() - 1)\n            }\n        }\n        //println($\"after delete indices.len() = {indices.len()}\")\n        //println($\"before ins table.len = {t.len()}\")\n\n        t.x <- \"abc\"\n\n        foreach (_, v in indices)\n            assert(t?[v] != null)\n\n        //println($\"after ins table.len = {t.len()}\")\n        //println(1 + size - iter % size)\n        assert(t.len() == 1 + size - iter % size)\n\n        assert(t.x == \"abc\")\n    }\n}\n\nprintln(\"ok\")"
  },
  {
    "path": "testData/exec/stdlib/rawdelete.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/regexp.nut",
    "content": "let { regexp } = require(\"string\")\n\nlet r = regexp(@\"[a-z,A-Z]*\")\nprintln(r.match(\"AxBy\"))\nprintln(r.match(\"AB-\"))\n\nlet t = r.search(\"-AAAA----A\", 1)\nforeach (k, v in t)\n  println($\"{k}={v}\")\n\nlet f = r.capture(\"-AAAA----A\", 1)\nforeach (k, v in f[0])\n  println($\"{k}={v}\")\n\nprintln(typeof r)\n\nprintln(r.subexpcount())\n"
  },
  {
    "path": "testData/exec/stdlib/regexp.out",
    "content": "true\nfalse\nbegin=1\nend=5\nbegin=1\nend=5\nregexp\n1\n"
  },
  {
    "path": "testData/exec/stdlib/regexp_fixed_bugs.nut",
    "content": "let { regexp } = require(\"string\")\n\n// Bug 1: Empty pattern should error, not crash (heap-buffer-overflow)\ntry {\n  regexp(\"\")\n  println(\"BUG: empty pattern did not error\")\n} catch(e) {\n  println($\"empty pattern error: {e}\")\n}\n\n// Bug 2: [A-] should error \"unfinished range\" (dead range-end check)\ntry {\n  regexp(\"[A-]\")\n  println(\"BUG: [A-] did not error\")\n} catch(e) {\n  println($\"unfinished range error: {e}\")\n}\n\n// Bug 3: Large quantifier should error, not silently truncate\ntry {\n  regexp(@\"^a{70000}$\")\n  println(\"BUG: large quantifier did not error\")\n} catch(e) {\n  println($\"quantifier error: {e}\")\n}\n\n// Bug 4: Word boundary correctness at various positions\nlet wb = regexp(@\"\\bword\\b\")\nprintln(wb.match(\"word\"))\nprintln(wb.search(\"hello word bye\") != null)\nprintln(wb.match(\"wordy\"))\n\n// Bug 5: Trailing backslash in escape should error\ntry {\n  regexp(\"\\\\\")\n  println(\"BUG: trailing backslash did not error\")\n} catch(e) {\n  println($\"trailing backslash error: {e}\")\n}\n\n// Bug 6: \\m with incomplete args should error\ntry {\n  regexp(\"\\\\m\")\n  println(\"BUG: incomplete \\\\m did not error\")\n} catch(e) {\n  println($\"incomplete \\\\m error: {e}\")\n}\n\ntry {\n  regexp(\"\\\\m(\")\n  println(\"BUG: incomplete \\\\m( did not error\")\n} catch(e) {\n  println($\"incomplete \\\\m( error: {e}\")\n}\n\n// Bug 7: Unclosed [ should error\ntry {\n  regexp(\"[abc\")\n  println(\"BUG: unclosed [ did not error\")\n} catch(e) {\n  println($\"unclosed bracket error: {e}\")\n}\n\n// Bug 8: Search finds matches at non-zero positions\nlet sr = regexp(@\"ab\")\nlet res = sr.search(\"xab\")\nprintln($\"search begin={res.begin} end={res.end}\")\n\n// Bug 9: Character range matching correctness\nlet rng = regexp(\"[A-Z]\")\nprintln(rng.match(\"M\"))\nprintln(rng.match(\"a\"))\n\n// Bug 10: Range validation with escape sequences\ntry {\n  let r = regexp(\"[A-\\\\n]\")\n  // Should not reach here - A(65) > \\n(10) is an invalid range\n  println(\"BUG: [A-\\\\n] should be invalid range\")\n} catch(e) {\n  println($\"[A-\\\\n] correctly rejected: {e}\")\n}\n\nlet r_az = regexp(\"[a-\\\\z]\")\nprintln($\"[a-\\\\z] match m: {r_az.match(\"m\")}\")\n\n// Bug 11: Pattern complexity limit\ntry {\n  local longpat = \"aaaaaaaaaa\" // 10\n  for (local i = 0; i < 12; i++)\n    longpat += longpat // 10 * 2^12 = 40960\n  longpat += longpat.slice(0, 9040) // 50000\n  regexp(longpat)\n  println(\"BUG: 50000 char pattern should error\")\n} catch(e) {\n  println($\"long pattern error: {e}\")\n}\n\n// Bug 12: Nested zero-width quantifiers terminate\nlet zw = regexp(@\"\\b{0,3}word\")\nprintln($\"zero-width bounded: {zw.match(\"word\")}\")\n\n// Bug 14: {n,m} where n > m should error at compile time\ntry {\n  regexp(\"a{5,2}\")\n  println(\"BUG: a{5,2} should be invalid range\")\n} catch(e) {\n  println($\"quantifier min>max error: {e}\")\n}\n\n// Bug 15: Large quantifier packing correctness (UB fix for p0 >= 32768)\nlet lq = regexp(@\"^a{40000}$\")\nlocal s40k = \"\"\nfor (local i = 0; i < 15; i++)\n  s40k += \"aaaaaaaaaa\" // build in chunks of 10\n// s40k = 150 chars, won't match {40000} but should not crash/UB\nprintln($\"large quantifier no crash: {lq.match(s40k) == false}\")\n"
  },
  {
    "path": "testData/exec/stdlib/regexp_fixed_bugs.out",
    "content": "empty pattern error: letter expected\nunfinished range error: unfinished range\nquantifier error: quantifier value too large\ntrue\ntrue\nfalse\ntrailing backslash error: letter expected for argument of escape sequence\nincomplete \\m error: balanced chars expected\nincomplete \\m( error: balanced chars expected\nunclosed bracket error: unterminated character class\nsearch begin=1 end=3\ntrue\nfalse\n[A-\\n] correctly rejected: invalid range\n[a-\\z] match m: true\nlong pattern error: pattern exceeds maximum allowed nesting depth\nzero-width bounded: true\nquantifier min>max error: invalid quantifier range: min > max\nlarge quantifier no crash: true\n"
  },
  {
    "path": "testData/exec/stdlib/stream_methods.nut",
    "content": "let { blob } = require(\"iostream\")\n\nlet b = blob()\n\nb.writen(-5, 'c')\nb.writen(250, 'b')\nb.writen(100, 's')\nb.writen(200, 'w')\nb.writen(42, 'i')\nb.writen(256, 'l')\nb.writen(3.5, 'f')\nb.writen(2.75, 'd')\n\nlet expectedLen = 1 + 1 + 2 + 2 + 4 + 8 + 4 + 8\nassert(b.len() == expectedLen)\nassert(b.tell() == expectedLen)\n\nb.seek(0, 'b')\nassert(b.tell() == 0)\n\nb.seek(0, 'e')\nassert(b.tell() == b.len())\n\nb.seek(-4, 'c')\nassert(b.tell() == b.len() - 4)\n\nb.seek(0)\nassert(b.tell() == 0)\n\nassert(b.eos() == null)\nb.seek(0, 'e')\nassert(b.eos() != null)\n\nb.seek(0)\nassert(b.readn('c') == -5)\nassert(b.readn('b') == 250)\nassert(b.readn('s') == 100)\nassert(b.readn('w') == 200)\nassert(b.readn('i') == 42)\nassert(b.readn('l') == 256)\nlet ff = b.readn('f')\nassert(ff == 3.5)\nlet dd = b.readn('d')\nassert(dd == 2.75)\n\nlet src = blob()\nsrc.writen(0xAA, 'b')\nsrc.writen(0xBB, 'b')\nsrc.writen(0xCC, 'b')\nsrc.seek(0)\n\nlet dst = blob()\ndst.writeblob(src)\nassert(dst.len() == 3)\ndst.seek(0)\nlet rd = dst.readblob(3)\nassert(typeof rd == \"blob\")\nassert(rd.len() == 3)\nassert(rd[0] == 0xAA)\nassert(rd[1] == 0xBB)\nassert(rd[2] == 0xCC)\n\nlet sb = blob()\nsb.writestring(\"abc\")\nassert(sb.len() == 3)\nsb.seek(0)\nassert(sb.readn('b') == 97)\nassert(sb.readn('b') == 98)\nassert(sb.readn('b') == 99)\n\nb.flush()\n\nlet nb = blob()\nnb.writeobject([1, 2, 3], null)\nnb.seek(0)\nlet nres = nb.readobject(null)\nassert(nres.len() == 3 && nres[0] == 1)\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nlet z = blob()\nz.writen(1, 'b')\nz.seek(0)\n\nmustThrow(\"readblob\",    @() z.readblob(null))\nmustThrow(\"readn\",       @() z.readn(null))\nmustThrow(\"writeblob\",   @() z.writeblob(null))\nmustThrow(\"writestring\", @() z.writestring(null))\nmustThrow(\"writen.1\",    @() z.writen(null, 'b'))\nmustThrow(\"writen.2\",    @() z.writen(1, null))\nmustThrow(\"seek.1\",      @() z.seek(null))\nmustThrow(\"seek.2\",      @() z.seek(0, null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/stream_methods.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/string.nut",
    "content": "let { format, printf, split_by_chars, startswith, endswith, strip, lstrip, rstrip, escape } = require(\"string\")\n\nprint(\"   strip \".strip())\nprintln(\";\")\nprint(\"   lstrip \".lstrip())\nprintln(\";\")\nprint(\"   rstrip \".rstrip())\nprintln(\";\")\nprint(\"\")\n\nprintln(\"abcd\".endswith(\"abcd*\"))\nprintln(\"abcd\".endswith(\"cd\"))\nprintln(\"abcd\".endswith(\"a\"))\nprintln(\"abcd\".endswith(\"\"))\nprintln(\"\")\n\nprintln(\"abcd\".startswith(\"*abcd\"))\nprintln(\"abcd\".startswith(\"ab\"))\nprintln(\"abcd\".startswith(\"d\"))\nprintln(\"abcd\".startswith(\"\"))\nprintln(\"\")\n\nprintln(endswith(\"abcd\", \"d\"))\nprintln(startswith(\"abcd\", \"a\"))\nprint(strip(\"   strip \"))\nprintln(\";\")\nprint(lstrip(\"   lstrip \"))\nprintln(\";\")\nprint(rstrip(\"   rstrip \"))\nprintln(\";\")\n\nprintln(\"\")\n\nprintln(\"~\\n\\\"\\'\\\\~\".escape())\nprintln(escape(\"~\\n\\\"\\'\\\\~\"))\nprintln(format(\"str:%s; int:%d; hex:%x\", \"st\", 255, 255))\nprintf(\"str:%s; int:%d; hex:%x\\n\", \"st\", 255, 255)\n\nlet arr = split_by_chars(\":aaa,bb:c:::\", \",:\", true)\nforeach(_, v in arr) {\n  print(v)\n  print(\";\")\n}\n\nprintln(\"\")\n\nlet arr2 = \":aaa,bb:c:::\".split_by_chars(\",:\", true)\nforeach(_, v in arr2) {\n  print(v)\n  print(\";\")\n}\n"
  },
  {
    "path": "testData/exec/stdlib/string.out",
    "content": "strip;\nlstrip ;\n   rstrip;\nfalse\ntrue\nfalse\ntrue\n\nfalse\ntrue\nfalse\ntrue\n\ntrue\ntrue\nstrip;\nlstrip ;\n   rstrip;\n\n~\\x0a\\\"\\'\\\\~\n~\\x0a\\\"\\'\\\\~\nstr:st; int:255; hex:ff\nstr:st; int:255; hex:ff\naaa;bb;c;\naaa;bb;c;"
  },
  {
    "path": "testData/exec/stdlib/string_escape.nut",
    "content": "let { escape } = require(\"string\")\n\nlet bs = \"\\\\\"  // single backslash\nlet dq = \"\\\"\"  // double-quote\nlet sq = \"'\"   // single-quote\n\n// --- empty string: returned unchanged ---\nassert(escape(\"\") == \"\")\nassert(\"\".escape() == \"\")\n\n// --- both call forms produce identical results ---\nassert(\"hello\".escape() == escape(\"hello\"))\n\n// --- all-printable, no special chars: pass through unchanged ---\nassert(\"hello\".escape() == \"hello\")\nassert(\"Hello World!\".escape() == \"Hello World!\")\nassert(\"0123456789\".escape() == \"0123456789\")\nassert(\"AaBbCcZz\".escape() == \"AaBbCcZz\")\nassert(\" !#$%&()*+,-./:;<=>?@[]^_`{|}~\".escape() == \" !#$%&()*+,-./:;<=>?@[]^_`{|}~\")\n\n// --- named escape chars: backslash, double-quote, single-quote ---\nassert(bs.escape()  == bs + bs)\nassert(dq.escape()  == bs + dq)\nassert(sq.escape()  == bs + sq)\nassert((bs + dq + sq).escape() == bs + bs + bs + dq + bs + sq)\n\n// --- control chars: \\a \\b \\t \\n \\v \\f \\r all go to \\xNN path ---\n// (the named-escape switch cases for these are dead code — they live inside\n//  the sq_isprint() branch which is never entered for control chars)\nassert(\"\\x01\".escape() == \"\\\\x01\")\nassert(\"\\x06\".escape() == \"\\\\x06\")\nassert(\"\\x07\".escape() == \"\\\\x07\")  // \\a\nassert(\"\\x08\".escape() == \"\\\\x08\")  // \\b\nassert(\"\\x09\".escape() == \"\\\\x09\")  // \\t\nassert(\"\\x0a\".escape() == \"\\\\x0a\")  // \\n\nassert(\"\\x0b\".escape() == \"\\\\x0b\")  // \\v\nassert(\"\\x0c\".escape() == \"\\\\x0c\")  // \\f\nassert(\"\\x0d\".escape() == \"\\\\x0d\")  // \\r\nassert(\"\\x0e\".escape() == \"\\\\x0e\")\nassert(\"\\x1f\".escape() == \"\\\\x1f\")\n\n// --- 0x7f (DEL) ---\nassert(\"\\x7f\".escape() == \"\\\\x7f\")\n\n// --- high bytes 0x80..0xff ---\nassert(\"\\x80\".escape() == \"\\\\x80\")\nassert(\"\\xab\".escape() == \"\\\\xab\")\nassert(\"\\xff\".escape() == \"\\\\xff\")\n\n// --- mixed: printable + control + special ---\nassert(\"a\\x01b\".escape()       == \"a\\\\x01b\")\nassert(\"a\\nb\".escape()         == \"a\\\\x0ab\")\nassert((\"a\" + bs + \"b\").escape() == \"a\\\\\\\\b\")\nassert((\"a\" + dq + \"b\").escape() == \"a\\\\\\\"b\")\n\n// from existing string.nut (extended): ~ LF \" ' \\ ~\n// expected: ~\\x0a\\\"\\'\\\\~ (12 chars)\nlet mixed_escaped = (\"~\\n\" + dq + sq + bs + \"~\").escape()\nassert(mixed_escaped.len() == 12)\nassert(mixed_escaped[ 0] == '~')   // literal ~\nassert(mixed_escaped[ 1] == '\\\\')  // start of \\x0a\nassert(mixed_escaped[ 2] == 'x')\nassert(mixed_escaped[ 3] == '0')\nassert(mixed_escaped[ 4] == 'a')\nassert(mixed_escaped[ 5] == '\\\\')  // start of \\\"\nassert(mixed_escaped[ 6] == '\"')\nassert(mixed_escaped[ 7] == '\\\\')  // start of \\'\nassert(mixed_escaped[ 8] == '\\'')\nassert(mixed_escaped[ 9] == '\\\\')  // start of \\\\\nassert(mixed_escaped[10] == '\\\\')\nassert(mixed_escaped[11] == '~')   // literal ~\n\n// --- output length is always >= input length ---\nassert(\"abc\".escape().len() >= 3)\nassert(\"\\x01\\x02\\x03\".escape().len() >= 3)\n\n// --- regression: all-non-printable strings (every char -> 4-byte \\xNN) ---\n// Before the fix, scsprintf received the total buffer size (destcharsize) rather\n// than the remaining bytes, causing a 1-byte null-terminator OOB write when\n// every character in the input required hex escaping.\nassert(\"\\x01\".escape()        == \"\\\\x01\")\nassert(\"\\x01\".escape().len()  == 4)\n\nassert(\"\\x01\\x02\".escape()    == \"\\\\x01\\\\x02\")\nassert(\"\\x01\\x02\".escape().len() == 8)\n\nassert(\"\\x01\\x02\\x03\\x04\\x05\".escape().len()         == 20)\nassert(\"\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x0e\\x0f\".escape().len() == 40)\n\n// larger all-non-printable string to stress the fixed boundary\nlocal s50 = \"\"\nfor (local i = 0; i < 5; i++)\n    s50 += \"\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x0e\\x0f\"\nassert(s50.len() == 50)\nassert(s50.escape().len() == 200)\n\nlocal s100 = s50 + s50\nassert(s100.escape().len() == 400)\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/string_escape.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/string_format.nut",
    "content": "let str = require(\"string\")\nlet { format } = str\n\nassert(format(\"%d\", 42) == \"42\")\nassert(format(\"%d\", -5) == \"-5\")\nassert(format(\"%i\", 42) == \"42\")\nassert(format(\"%o\", 8) == \"10\")\nassert(format(\"%u\", 100) == \"100\")\nassert(format(\"%x\", 255) == \"ff\")\nassert(format(\"%X\", 255) == \"FF\")\nassert(format(\"%c\", 65) == \"A\")\nassert(format(\"%c\", 97) == \"a\")\nassert(format(\"%s\", \"hi\") == \"hi\")\n\nassert(format(\"%5d|\", 42) == \"   42|\")\nassert(format(\"%-5d|\", 42) == \"42   |\")\nassert(format(\"%05d\", 42) == \"00042\")\nassert(format(\"%+d\", 42) == \"+42\")\nassert(format(\"%+d\", -42) == \"-42\")\n\nassert(format(\"%f\", 1.5).indexof(\"1.5\") != null)\nassert(format(\"%.2f\", 1.5) == \"1.50\")\nassert(format(\"%g\", 1.5).indexof(\"1.5\") != null)\nassert(format(\"%G\", 1.5).indexof(\"1.5\") != null)\nassert(format(\"%e\", 1000.0).indexof(\"e\") != null)\nassert(format(\"%E\", 1000.0).indexof(\"E\") != null)\n\nassert(format(\"%%\") == \"%\")\nassert(format(\"%s=%d\", \"n\", 7) == \"n=7\")\nassert(format(\"%s-%s\", \"a\", \"b\") == \"a-b\")\n\nassert(format(\"%#x\", 255) == \"0xff\")\nassert(format(\"% d\", 42) == \" 42\")\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nmustThrow(\"format.fmt\",       @() format(null))\nmustThrow(\"printf.fmt\",       @() str.printf(null))\nmustThrow(\"strip\",            @() str.strip(null))\nmustThrow(\"lstrip\",           @() str.lstrip(null))\nmustThrow(\"rstrip\",           @() str.rstrip(null))\nmustThrow(\"escape\",           @() str.escape(null))\nmustThrow(\"startswith.1\",     @() str.startswith(null, \"a\"))\nmustThrow(\"startswith.2\",     @() str.startswith(\"abc\", null))\nmustThrow(\"endswith.1\",       @() str.endswith(null, \"a\"))\nmustThrow(\"endswith.2\",       @() str.endswith(\"abc\", null))\nmustThrow(\"split.1\",          @() str.split_by_chars(null, \",\"))\nmustThrow(\"split.2\",          @() str.split_by_chars(\"a,b\", null))\nmustThrow(\"split.3\",          @() str.split_by_chars(\"a,b\", \",\", null))\nmustThrow(\"regexp.ctor\",      @() str.regexp(null))\nlet rex = str.regexp(\"a\")\nmustThrow(\"regexp.match\",     @() rex.match(null))\nmustThrow(\"regexp.search.1\",  @() rex.search(null))\nmustThrow(\"regexp.search.2\",  @() rex.search(\"abc\", null))\nmustThrow(\"regexp.capture.1\", @() rex.capture(null))\nmustThrow(\"regexp.capture.2\", @() rex.capture(\"abc\", null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/string_format.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/stdlib/swap.nut",
    "content": "class D {\n  x = 1\n  y = 2\n}\nlocal d = D()\nlocal t = {\"1\": \"123\", \"2\": \"asd\"}\nlocal a = [123, 456, 789]\n\nd.swap(\"x\", \"y\")\na.swap(1, 2)\nt.swap(\"1\", \"2\")\n\nprintln($\"{d[\"x\"]} {d[\"y\"]}\")\nprintln($\"{t[\"1\"]} {t[\"2\"]}\")\nprintln($\"{a[1]} {a[2]}\")\n"
  },
  {
    "path": "testData/exec/stdlib/swap.out",
    "content": "2 1\nasd 123\n789 456\n"
  },
  {
    "path": "testData/exec/stdlib/swap_stack_check.nut",
    "content": "class D {\n  x = 1\n  y = 2\n}\nlocal d = D()\nlocal t = {\"1\": \"123\", \"2\": \"asd\"}\nlocal a = [123, 456, 789]\n\nfunction fn(n) {\n  d.swap(\"x\", \"y\")\n  local x = n - 1\n  t.swap(\"1\", \"2\")\n  a.swap(1, 2)\n  if (n > 0)\n    fn(x)\n  println(x)\n}\n\nfn(10)\n\nprintln($\"{d[\"x\"]} {d[\"y\"]}\")\nprintln($\"{t[\"1\"]} {t[\"2\"]}\")\nprintln($\"{a[1]} {a[2]}\")\n"
  },
  {
    "path": "testData/exec/stdlib/swap_stack_check.out",
    "content": "-1\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n2 1\nasd 123\n789 456\n"
  },
  {
    "path": "testData/exec/stdlib/system_lib.nut",
    "content": "let { getenv, setenv, system, remove, rename } = require(\"system\")\nlet { file } = require(\"io\")\n\nsetenv(\"QUIRREL_STDLIB_TEST_VAR\", \"hello42\")\nassert(getenv(\"QUIRREL_STDLIB_TEST_VAR\") == \"hello42\")\n\nsetenv(\"QUIRREL_STDLIB_TEST_VAR\", \"updated\")\nassert(getenv(\"QUIRREL_STDLIB_TEST_VAR\") == \"updated\")\n\nlet rc = system(\"cd .\")\nassert(typeof rc == \"integer\")\n\nlet f = file(\"qtest_sys_tmp.txt\", \"wb\")\nassert(typeof f == \"file\")\nf.close()\n\nrename(\"qtest_sys_tmp.txt\", \"qtest_sys_tmp2.txt\")\nremove(\"qtest_sys_tmp2.txt\")\n\nfunction mustThrow(label, fn) {\n  try { fn(); println($\"FAIL: {label} accepted null\") } catch (_) {}\n}\n\nmustThrow(\"getenv\",    @() getenv(null))\nmustThrow(\"setenv.1\",  @() setenv(null, \"v\"))\nmustThrow(\"setenv.2\",  @() setenv(\"k\", null))\nmustThrow(\"system\",    @() system(null))\nmustThrow(\"remove\",    @() remove(null))\nmustThrow(\"rename.1\",  @() rename(null, \"x\"))\nmustThrow(\"rename.2\",  @() rename(\"x\", null))\n\nprintln(\"ok\")\n"
  },
  {
    "path": "testData/exec/stdlib/system_lib.out",
    "content": "ok\n"
  },
  {
    "path": "testData/exec/string_interpolation.nut",
    "content": "let x = {y = 123}\nassert($\"\" == \"\")\nassert($\"\\{\\}\" == \"{}\")\nassert($\"{3}\" == \"3\")\nassert($\"\\\\{0}\\\\{1}\" == \"\\\\0\\\\1\")\nassert($\"{3}{4}\" == \"34\")\nassert($\"{\"3\"}{\"4\"}\" == \"34\")\nassert($\"abc{123}def\" == \"abc123def\")\nassert($\"abc{          123}def\" == \"abc123def\")\nassert($\"abc{          123  -    3         }def\" == \"abc120def\")\nassert($\"abc{x.y}\\u20\" == \"abc123 \")\nassert($\"{x[\"\\u79\"] == 123}\" == \"true\")\nassert($\"'\" == \"'\")\nassert($\"\\\\\\\\\" == \"\\\\\\\\\")\nassert($\"\\t\\n\" == \"\\t\\n\")\nassert($\"/\" == \"/\")\nassert($\"\\}{{s=\"qwe\"}[\"s\"]}\\{\" == \"}qwe{\")\n"
  },
  {
    "path": "testData/exec/string_interpolation.out",
    "content": ""
  },
  {
    "path": "testData/exec/string_interpolation_new.nut",
    "content": "\n\nfunction foo() { return \"foo\" }\nfunction bar(p) { return $\"[bar {p}]\"  }\n\nlet s = $\"x1 = {foo()}, x2 = {bar($\"qux = {foo()}\")}\"\n\nprint(\"#1: \")\nprintln(s)\n\nprint(\"#2: \")\nprintln($\"{$\"{2}\"}\");\n\nprint(\"#3: \")\nlocal gg = 123\nprintln($\"\\{ gg = {gg} \\}\")\n\nprint(\"#4: \")\nprintln($\"   foo bar \")\n\nprint(\"#5: \")\nprintln($\"{foo()}}}}}}\")\n"
  },
  {
    "path": "testData/exec/string_interpolation_new.out",
    "content": "#1: x1 = foo, x2 = [bar qux = foo]\n#2: 2\n#3: { gg = 123 }\n#4:    foo bar \n#5: foo}}}}}\n"
  },
  {
    "path": "testData/exec/string_methods.nut",
    "content": "let s = \"Hello, World!\"\nlet Exception = class{\n  e = null\n  constructor(e){\n    this.e=e\n  }\n}\nfunction test(func, expected_res, name = null){\n  let name_s = name ? $\"'{name}': \" : \"\"\n  try{\n    let res = func()\n    assert(expected_res==res, @() $\"{name_s}Expected {expected_res}, got {res}\")\n    println(res)\n  }\n  catch(e){\n    assert(expected_res instanceof Exception, $\"{name_s} expected result '{expected_res}', got Exception('{e}')}\")\n    assert(expected_res.e == null || expected_res.e==e, $\"{name_s}expected Exception value = '{expected_res.e}', got '{e}'\")\n  }\n}\ntry{\n  test(@() s.len(), 13, \"s.len()\")\n  test(@() \"123\".tointeger(), 123, \"'123'.tointeger()\")\n  test(@() \"abc\".tointeger(), Exception(\"cannot convert the string to integer\"), \"'abc'.tointeger()\")\n  test(@() \"12.34\".tofloat(), 12.34, \"'12.34'.tofloat()\")\n  test(@() s.tostring(), \"Hello, World!\", \"s.tostring()\")\n  test(@() s.hash(), s.hash(), \"s.hash()\")\n  test(@() s.slice(0,5), \"Hello\", \"s.slice(0,5)\")\n  test(@() s.indexof(\"World\"), 7, \"s.indexof('World')\")\n  test(@() s.indexof(\"xyz\"), null, \"s.indexof('xyz')\")\n  test(@() s.contains(\"lo\"), true, \"s.contains('lo')\")\n  test(@() s.contains(\"xyz\"), false, \"s.contains('xyz')\")\n  test(@() s.tolower(), \"hello, world!\", \"s.tolower()\")\n  test(@() s.toupper(), \"HELLO, WORLD!\", \"s.toupper()\")\n  test(@() \"{Hello}, World!\".subst({Hello=\"Hi\"}), \"Hi, World!\", \"s.subst({Hello='Hi'})\")\n  test(@() s.replace(\"World\", \"Quirrel\"), \"Hello, Quirrel!\", \"s.replace('World', 'Quirrel')\")\n  test(@() \"-\".join([\"a\",\"b\"]), \"a-b\", \"'-'.join(['a','b'])\")\n  test(@() \" \".concat(\"Hello, World!\", \"Test\"), \"Hello, World! Test\", \"' '.concat('Hello, World!', 'Test')\")\n  test(@() s.split(\",\")[0], \"Hello\", \"s.split(',')\")\n  test(@() \"  test  \".strip(), \"test\", \"'  test  '.strip()\")\n  test(@() \"  test\".lstrip(), \"test\", \"'  test'.lstrip()\")\n  test(@() \"test  \".rstrip(), \"test\", \"'test  '.rstrip()\")\n  test(@() \"a,b c\".split_by_chars(\", \")[2], \"c\", \"'a,b c'.split_by_chars(', ')\")\n  test(@() s.startswith(\"Hell\"), true, \"s.startswith('Hell')\")\n  test(@() s.endswith(\"ld!\"), true, \"s.endswith('ld!')\")\n  test(@() s.hasindex(0), true, \"s.hasindex(0)\")\n  test(@() \"22a\".hasindex(3), false, \"'22a'.hasindex(3)\")\n  test(@() \"222\".hasindex(-1), false, \"s.hasindex(-1)\")\n  //test(@() \"\\r\".escape(), \"\\\\x0'\", \"'\\\\r'.escape()\")\n  print(\"ok\")\n}\ncatch(e){\n  println(e)\n}"
  },
  {
    "path": "testData/exec/string_methods.out",
    "content": "13\n123\n12.34\nHello, World!\n4027599776755331851\nHello\n7\nnull\ntrue\nfalse\nhello, world!\nHELLO, WORLD!\nHi, World!\nHello, Quirrel!\na-b\nHello, World! Test\nHello\ntest\ntest\ntest\nc\ntrue\ntrue\ntrue\nfalse\nfalse\nok"
  },
  {
    "path": "testData/exec/sub_int_min.nut",
    "content": "// Test subtraction of -2147483648 (INT_MIN for 32-bit).\n//\n// The parser folds `-<integer>` into a single negative LiteralExpr.\n// The codegen optimizes `x - literal` to `_OP_ADDI x, -literal` when the\n// literal fits in 32 bits. But -(-2147483648) = +2147483648 overflows SQInt32,\n// wrapping to -2147483648. This causes `x - (-2147483648)` to be miscompiled\n// as `x + (-2147483648)` instead of `x + 2147483648`.\n//\n// Note: the unparenthesized form `x - -2147483648` is required to trigger the\n// bug, because the parser folds the unary minus into the literal directly.\n// With parens `x - (-2147483648)`, the RHS is a TO_PAREN node and the\n// optimization path is not taken.\n\nlet x = 5\n\n// Without parens: parser creates LiteralExpr(-2147483648) directly.\n// Codegen sees TO_SUB with a TO_LITERAL RHS in 32-bit range, uses _OP_ADDI.\nlet result = x - -2147483648\n\n// Expected: 5 - (-2147483648) = 5 + 2147483648 = 2147483653\nassert(result == 2147483653)\n\n// With a variable (non-optimized path for comparison):\nlocal y = -2147483648\nlet result2 = x - y\nassert(result2 == 2147483653)\n\n// Both paths must agree.\nassert(result == result2)\n"
  },
  {
    "path": "testData/exec/sub_int_min.out",
    "content": ""
  },
  {
    "path": "testData/exec/surprise_js_dev.nut",
    "content": "println(\"=== Part 1: Truthy/falsy differences ===\\n\")\n\n// In JS: \"\" is falsy, 0 is falsy, [] is truthy, {} is truthy\n// In Quirrel...\nlet truthy_tests = {\n  [\"empty string \\\"\\\"\"]  = \"\",      // JS: falsy, Quirrel: truthy\n  [\"zero 0\"]             = 0,       // falsy (same as JS)\n  [\"zero 0.0\"]           = 0.0,     // falsy (same as JS)\n  [\"empty array []\"]     = [],      // JS: truthy, Quirrel: truthy too\n  [\"empty table {}\"]     = {},      // JS: truthy, Quirrel: truthy too\n}\nforeach (name, val in truthy_tests) {\n  let verdict = val ? \"TRUTHY\" : \"FALSY\"\n  println($\"  {name} is {verdict}\")\n}\n\nprintln(\"\\n  Note: unlike JS, empty string is truthy in Quirrel.\\n\")\n\n\nprintln(\"=== Part 2: Integer division (no implicit float) ===\\n\")\n\nprintln($\"  JS:  10 / 3 = 3.333...  |  Quirrel: 10 / 3 = {10 / 3}\")\nprintln($\"  Want float? Use 10.0 / 3 = {10.0 / 3}\")\nprintln($\"  Negative modulo: -7 % 3 = {-7 % 3}  (C-style, not math-style)\\n\")\n\n\nprintln(\"=== Part 3: Cooperative multitasking with coroutines ===\\n\")\n\n// Quirrel has real coroutines with bidirectional data passing.\n// JS generators can yield, but Quirrel threads can suspend/wakeup\n// with values flowing in both directions.\n\nfunction fibonacci_server() {\n  local a = 0, b = 1\n  while (true) {\n    local request = suspend({value = a, msg = \"fib value\"})\n    if (request == \"next\") {\n      let temp = a + b; a = b; b = temp\n    } else if (request == \"reset\") {\n      a = 0; b = 1\n    }\n  }\n}\n\nlet fib = newthread(fibonacci_server)\nlocal result = fib.call()       // start the coroutine\nprint(\"  Fibonacci server: \")\nfor (local i = 0; i < 10; i++) {\n  print($\"{result.value} \")\n  result = fib.wakeup(\"next\")   // send command, receive response\n}\nfib.wakeup(\"reset\")\nlet after_reset = fib.wakeup(\"next\")\nprintln($\"\\n  After reset: {after_reset.value}\")\n\n\nprintln(\"\\n=== Part 4: Build a DSL with metamethods ===\\n\")\n\n// JS needs Proxy for this. Quirrel has _get, _set, _call, _add, _mul, _tostring...\n// Let's build a fluent SQL-like query builder using metamethods.\n\nclass Query {\n  _table = null\n  _conditions = null\n  _fields = null\n  _order = null\n  _limit_val = null\n\n  constructor(table_name = null) {\n    this._table = table_name\n    this._conditions = []\n    this._fields = [\"*\"]\n    this._order = null\n    this._limit_val = null\n  }\n\n  function select(...) {\n    let q = clone this\n    q._fields = vargv\n    return q\n  }\n\n  function from(table_name) {\n    let q = clone this\n    q._table = table_name\n    return q\n  }\n\n  function where(condition) {\n    let q = clone this\n    q._conditions = clone this._conditions\n    q._conditions.append(condition)\n    return q\n  }\n\n  function order_by(field) {\n    let q = clone this\n    q._order = field\n    return q\n  }\n\n  function limit(n) {\n    let q = clone this\n    q._limit_val = n\n    return q\n  }\n\n  // Metamethod: print the query as SQL\n  function _tostring() {\n    let fields_str = \", \".join(this._fields)\n    local sql = $\"SELECT {fields_str} FROM {this._table}\"\n    if (this._conditions.len() > 0) {\n      let cond_str = \" AND \".join(this._conditions)\n      sql = $\"{sql} WHERE {cond_str}\"\n    }\n    if (this._order)\n      sql = $\"{sql} ORDER BY {this._order}\"\n    if (this._limit_val != null)\n      sql = $\"{sql} LIMIT {this._limit_val}\"\n    return sql\n  }\n\n  // Metamethod: combine two queries with UNION\n  function _add(other) {\n    let result = this.getclass()()\n    result._table = $\"({this}) UNION ({other})\"\n    return result\n  }\n}\n\nlet q = Query()\n  .select(\"name\", \"age\", \"email\")\n  .from(\"users\")\n  .where(\"age > 18\")\n  .where(\"active = true\")\n  .order_by(\"name\")\n  .limit(10)\n\nprintln($\"  {q}\")\n\nlet admins = Query().select(\"name\").from(\"admins\").where(\"role = 'super'\")\nlet mods = Query().select(\"name\").from(\"moderators\").where(\"level > 3\")\nprintln($\"  {admins + mods}\")\n\n\nprintln(\"\\n=== Part 5: freeze - deep immutability ===\\n\")\n\n// JS Object.freeze is shallow and you can still reassign the variable.\n// Quirrel freeze is enforced at runtime - any mutation attempt throws an error.\n// The `static` keyword creates compile-time frozen literals.\n\nlet config = freeze({\n  db = freeze({\n    host = \"localhost\"\n    port = 5432\n    pool = freeze([5, 10, 20])\n  })\n  app = freeze({\n    name = \"quirrel-app\"\n    version = \"1.0\"\n  })\n})\n\nprintln($\"  config.app.name = {config.app.name}\")\nprintln($\"  config is frozen: {config.is_frozen()}\")\nprintln($\"  config.db is frozen: {config.db.is_frozen()}\")\nprintln($\"  config.db.pool is frozen: {config.db.pool.is_frozen()}\")\n\ntry {\n  config.app.name = \"hacked\"\n} catch(e) {\n  println($\"  Mutation blocked: {e}\")\n}\n\n\nprintln(\"\\n=== Part 6: delete returns the value ===\\n\")\n\n#allow-delete-operator\nlocal inventory = {sword = 100, shield = 50, potion = 25}\nlet sold_item = delete inventory.sword\nprintln($\"  Sold sword for {sold_item} gold! Remaining: {inventory.len()} items\")\n// In JS, delete returns a boolean. In Quirrel, it returns the removed value.\n\n\nprintln(\"\\n=== Part 7: The _call metamethod - objects as functions ===\\n\")\n\n// In JS you can't make an object callable without Proxy.\n// In Quirrel, _call makes any instance behave as a function.\n\nclass Validator {\n  _rules = null\n\n  constructor(...) {\n    this._rules = vargv\n  }\n\n  // env is the hidden first param - the call environment\n  function _call(env, value) {\n    foreach (rule in this._rules) {\n      let result = rule(value)\n      if (result != null)\n        return result  // return error message\n    }\n    return null  // all passed\n  }\n\n  function _add(other) {\n    // Combine validators with +\n    let combined = this.getclass()()  // can't use `Validator()` inside class!\n    combined._rules = clone this._rules\n    combined._rules.extend(other._rules)\n    return combined\n  }\n}\n\nlet not_null = Validator(@(v) v == null ? \"must not be null\" : null)\nlet is_string = Validator(@(v) typeof v != \"string\" ? \"must be a string\" : null)\nlet min_len = @(n) Validator(@(v) typeof v == \"string\" && v.len() < n\n  ? $\"must be at least {n} chars\" : null)\n\nlet username_validator = not_null + is_string + min_len(3)\n\nprintln($\"  validate(null):   {username_validator(null)}\")\nprintln($\"  validate(42):     {username_validator(42)}\")\nprintln($\"  validate(\\\"ab\\\"):   {username_validator(\"ab\")}\")\nprintln($\"  validate(\\\"john\\\"): {username_validator(\"john\") ?? \"OK\"}\")\n\n\nprintln(\"\\n=== Part 8: Coroutine pipeline ===\\n\")\n\n// Build a lazy data processing pipeline using coroutines.\n// Each stage is a coroutine that pulls from the previous one.\n\nfunction range(start, end_val) {\n  for (local i = start; i < end_val; i++)\n    yield i\n}\n\nfunction map_gen(source, fn) {\n  foreach (val in source)\n    yield fn(val)\n}\n\nfunction filter_gen(source, pred) {\n  foreach (val in source)\n    if (pred(val))\n      yield val\n}\n\nfunction take_gen(source, n) {\n  local count = 0\n  foreach (val in source) {\n    if (count >= n) return\n    yield val\n    count++\n  }\n}\n\n// Pipeline: range(1,100) |> filter(odd) |> map(square) |> take(8)\n// All lazy - only computes what's needed.\nlet pipeline = take_gen(\n  map_gen(\n    filter_gen(\n      range(1, 100),\n      @(x) x % 2 == 1\n    ),\n    @(x) x * x\n  ),\n  8\n)\n\nprint(\"  Lazy pipeline (odd squares): \")\nforeach (val in pipeline)\n  print($\"{val} \")\nprintln(\"\")\n\n\nprintln(\"\\n=== Part 9: Three-way comparison & custom sorting ===\\n\")\n\n// The <=> operator returns -1, 0, or 1. JS doesn't have this.\n\nclass Card {\n  suit = null\n  rank = null\n  static suit_order = {clubs = 0, diamonds = 1, hearts = 2, spades = 3}\n  constructor(rank, suit) { this.rank = rank; this.suit = suit }\n  function _cmp(other) {\n    let r = this.rank <=> other.rank\n    return r != 0 ? r : this.getclass().suit_order[this.suit] <=> this.getclass().suit_order[other.suit]\n  }\n  function _tostring() {\n    let symbols = {clubs = \"C\", diamonds = \"D\", hearts = \"H\", spades = \"S\"}\n    let names = {[11] = \"J\", [12] = \"Q\", [13] = \"K\", [14] = \"A\"}\n    let r = this.rank in names ? names[this.rank] : $\"{this.rank}\"\n    return $\"{r}{symbols[this.suit]}\"\n  }\n}\n\nlocal hand = [Card(14, \"spades\"), Card(7, \"hearts\"), Card(14, \"clubs\"),\n              Card(7, \"diamonds\"), Card(10, \"spades\")]\nhand.sort(@(a, b) a <=> b)\nprint(\"  Sorted hand: \")\nforeach (card in hand)\n  print($\"{card} \")\n\n\nprintln(\"\\n\\n=== Part 10: Destructuring + null safety chain ===\\n\")\n\n// Nested null-safe access - no more `obj && obj.a && obj.a.b && obj.a.b.c`\n\nlet api_response = {\n  data = {\n    user = {\n      profile = {\n        avatar = \"cat.png\"\n      }\n    }\n  }\n}\n\nlet avatar = api_response?.data?.user?.profile?.avatar ?? \"default.png\"\nlet missing = api_response?.data?.user?.settings?.theme ?? \"dark\"\nprintln($\"  Avatar: {avatar}\")\nprintln($\"  Theme (missing path): {missing}\")\n\n// Destructuring with defaults - cleaner than JS\nlet {\n  data = null\n} = api_response\nlet {\n  user = null\n} = data\nlet {\n  profile = {avatar = \"fallback.png\"}\n} = user\nprintln($\"  Destructured avatar: {profile.avatar}\")\n"
  },
  {
    "path": "testData/exec/surprise_js_dev.out",
    "content": "=== Part 1: Truthy/falsy differences ===\n\n  zero 0 is FALSY\n  empty table {} is TRUTHY\n  empty string \"\" is TRUTHY\n  empty array [] is TRUTHY\n  zero 0.0 is FALSY\n\n  Note: unlike JS, empty string is truthy in Quirrel.\n\n=== Part 2: Integer division (no implicit float) ===\n\n  JS:  10 / 3 = 3.333...  |  Quirrel: 10 / 3 = 3\n  Want float? Use 10.0 / 3 = 3.33333\n  Negative modulo: -7 % 3 = -1  (C-style, not math-style)\n\n=== Part 3: Cooperative multitasking with coroutines ===\n\n  Fibonacci server: 0 1 1 2 3 5 8 13 21 34 \n  After reset: 1\n\n=== Part 4: Build a DSL with metamethods ===\n\n  SELECT name, age, email FROM users WHERE age > 18 AND active = true ORDER BY name LIMIT 10\n  SELECT * FROM (SELECT name FROM admins WHERE role = 'super') UNION (SELECT name FROM moderators WHERE level > 3)\n\n=== Part 5: freeze - deep immutability ===\n\n  config.app.name = quirrel-app\n  config is frozen: true\n  config.db is frozen: true\n  config.db.pool is frozen: true\n  Mutation blocked: trying to modify immutable 'table'\n\n=== Part 6: delete returns the value ===\n\n  Sold sword for 100 gold! Remaining: 2 items\n\n=== Part 7: The _call metamethod - objects as functions ===\n\n  validate(null):   must not be null\n  validate(42):     must be a string\n  validate(\"ab\"):   must be at least 3 chars\n  validate(\"john\"): OK\n\n=== Part 8: Coroutine pipeline ===\n\n  Lazy pipeline (odd squares): 1 9 25 49 81 121 169 225 \n\n=== Part 9: Three-way comparison & custom sorting ===\n\n  Sorted hand: 7D 7H 10S AC AS \n\n=== Part 10: Destructuring + null safety chain ===\n\n  Avatar: cat.png\n  Theme (missing path): dark\n  Destructured avatar: cat.png\n"
  },
  {
    "path": "testData/exec/table_methods.nut",
    "content": "let t = {a=1, b=2, c=3}\nlet Exception = class{\n  e = null\n  constructor(e){\n    this.e=e\n  }\n}\nfunction test(func, expected_res, name = null){\n  let name_s = name ? $\"'{name}': \" : \"\"\n  try{\n    let res = func()\n    assert(expected_res==res, @() $\"{name_s}Expected {expected_res}, got {res}\")\n    println(res)\n  }\n  catch(e){\n    assert(expected_res instanceof Exception, $\"{name_s} expected result '{expected_res}', got Exception('{e}')}\")\n    assert(expected_res.e == null || expected_res.e==e, $\"{name_s}expected Exception value = '{expected_res.e}', got '{e}'\")\n  }\n}\ntry{\n  test(@() t.len(), 3, \"t.len()\")\n  test(@() t.rawget(\"a\"), 1, \"t.rawget('a')\")\n  test(@() t.rawget(\"x\"), Exception(\"the index doesn't exist\"), \"t.rawget('x')\")\n  test(@() t.rawset(\"d\", 4)[\"d\"], 4, \"t.rawset('d', 4)\")\n  test(@() t.rawdelete(\"d\"), 4, \"t.rawdelete('d')\")\n  test(@() t.rawin(\"b\"), true, \"t.rawin('b')\")\n  test(@() t.rawin(\"x\"), false, \"t.rawin('x')\")\n  test(@() t.map(@(v) v*2)[\"a\"], 2, \"t.map(@(v) v*2)\")\n  test(@() t.map(@(v, k) v*2+k.len())[\"a\"], 3, \"t.map(@(v,k) v*2 + k.len())\")\n  test(@() t.filter(@(v) v%2==1)[\"a\"], 1, \"t.filter(@(v) v%2==1)\")\n  test(@() t.reduce(@(acc,v,k) acc+v, 0), 6, \"t.reduce(@(acc,k,v) acc+v, 0)\")\n  test(@() t.findindex(@(v) v==2), \"b\", \"t.findindex(@(v) v==2)\")\n  test(@() t.findindex(@(v) v==5), null, \"t.findindex(@(v) v==5)\")\n  test(@() t.findvalue(@(v) v==3), 3, \"t.findvalue(@(v) v==3)\")\n  test(@() t.findvalue(@(v) v==5), null, \"t.findvalue(@(v) v==5)\")\n  test(@() t.findvalue(@(_, k) k==\"a\"), 1, \"t.findvalue(@(_,v) v==3)\")\n  test(@() t.keys().contains(\"a\"), true, \"t.keys().contains('a')\")\n  test(@() t.values().contains(2), true, \"t.values().contains(2)\")\n  test(@() t.each(@(v,k) v), null, \"t.each(@(k,v) v)\")\n  test(@() t.__update({b=20, d=4})[\"b\"], 20, \"t.__update({b=20, d=4})\")\n  test(@() t.__merge({e=5})[\"e\"], 5, \"t.__merge({e=5})\")\n  test(@() t.topairs().sort(@(a,b) a[0]<=>b[0])[0][0], \"a\", \"t.topairs()[0][0]\")\n  test(@() t.replace_with({x=10, y=20})[\"x\"], 10, \"t.replace_with({x=10, y=20})\")\n  test(@() t.hasindex(\"x\"), true, \"t.hasindex('x')\")\n  test(@() t.hasindex(\"z\"), false, \"t.hasindex('z')\")\n  test(@() t.hasvalue(10), true, \"t.hasvalue(10)\")\n  test(@() t.hasvalue(5), false, \"t.hasvalue(5)\")\n  test(@() t.swap(\"x\",\"y\")[\"x\"], 20, \"t.swap('x','z')\")\n  test(@() t.clear().len(), 0, \"t.clear().len()\")\n  print(\"ok\")\n}\ncatch(e){\n  println(e)\n}"
  },
  {
    "path": "testData/exec/table_methods.out",
    "content": "3\n1\n4\n4\ntrue\nfalse\n2\n3\n1\n6\nb\nnull\n3\nnull\n1\ntrue\ntrue\nnull\n20\n5\na\n10\ntrue\nfalse\ntrue\nfalse\n20\n0\nok"
  },
  {
    "path": "testData/exec/testNullPropagation.nut",
    "content": "class A {\n  function _get(key) {\n    println(\"begin A._get() call\")\n    throw \"I am an error!\"\n    println(\"end A._get() call\")\n  }\n}\n\nfunction testField() {\n  let a = A()\n  println($\"a.foo = {a?.foo}\")\n}\n\nfunction testIndex() {\n  let a = A()\n  println($\"a[10] = {a?[10]}\")\n}\n\ntry {\n  testField()\n  println(\"testField failed\")\n} catch (e) {\n  println(\"testField passed\")\n}\n\ntry {\n  testIndex()\n  println(\"testIndex failed\")\n} catch (e) {\n  println(\"testIndex passed\")\n}"
  },
  {
    "path": "testData/exec/testNullPropagation.out",
    "content": "begin A._get() call\ntestField passed\nbegin A._get() call\ntestIndex passed\n"
  },
  {
    "path": "testData/exec/test_class_yield_call.nut",
    "content": "// Test: calling a generator method via .call() from a constructor.\n//\n// Before fix: this crashed with access violation (or assertion\n// \"SQObjectPtr::SQObjectPtr(SQGenerator*): Assertion '_unVal.pTable' failed\")\n// because GrowCallStack() invalidated the prevci pointer in Execute(),\n// causing it to enter the main instruction loop instead of returning the\n// generator object. The VM then hit _OP_YIELD with ci->_generator==NULL,\n// reaching the \"only generator can be yielded\" error path which itself\n// crashed constructing SQObjectPtr from a NULL generator pointer.\n//\n// After fix: the generator is created and returned correctly.\n\n//--- 1. Direct .call() on yielding method from constructor ---\nclass DirectCall {\n    constructor() {\n        this.do_yield.call(0)\n    }\n    function do_yield() { yield }\n}\nDirectCall()\nprint(\"1. Direct .call() from ctor: OK\\n\")\n\n\n//--- 2. Indirect .call() via helper method (original class_yield.nut) ---\nclass IndirectCall {\n    constructor() {\n        this.call_yield()\n    }\n    function call_yield() {\n        this.do_yield.call(0)\n    }\n    function do_yield() { yield }\n}\nIndirectCall()\nprint(\"2. Indirect .call() from ctor: OK\\n\")\n\n\n//--- 3. .call() on yielding method with value passing ---\nclass YieldWithValue {\n    _result = null\n    constructor(v) {\n        this._result = v\n        let g = this.gen.call(this)\n        this._result = resume g\n    }\n    function gen() { yield this._result + 100 }\n}\nlet obj3 = YieldWithValue(5)\nassert(obj3._result == 105)\nprint(\"3. .call() with value passing: OK\\n\")\n\n\n//--- 4. Inherited yielding method called via .call() from derived ctor ---\nclass Base4 {\n    function do_yield() { yield 42 }\n}\nclass Derived4(Base4) {\n    constructor() {\n        this.do_yield.call(0)\n    }\n}\nDerived4()\nprint(\"4. Inherited yield via .call(): OK\\n\")\n\n\n//--- 5. Deep nesting that triggers multiple callstack reallocations ---\n// Initial callstack size is 4; each recursion adds a frame.\n// The generator .call() from the constructor must survive GrowCallStack().\nfunction deep(n) {\n    if (n <= 0) {\n        class Inner {\n            constructor() { this.gen.call(0) }\n            function gen() { yield }\n        }\n        Inner()\n        return 1\n    }\n    return deep(n - 1) + 1\n}\nassert(deep(30) == 31)\nprint(\"5. Deep nesting + yield .call(): OK\\n\")\n\n\n//--- 6. Generator method .call() outside constructor (control case) ---\nclass Normal6 {\n    _v = 0\n    constructor(v) { this._v = v }\n    function gen() { yield this._v; yield this._v + 1 }\n}\nlet obj6 = Normal6(10)\nlet g6 = obj6.gen.call(obj6)\nassert(resume g6 == 10)\nassert(resume g6 == 11)\nprint(\"6. Generator .call() outside ctor: OK\\n\")\n\n\n//--- 7. Multiple generators created via .call() in constructor ---\nclass Multi7 {\n    _g1 = null\n    _g2 = null\n    constructor() {\n        this._g1 = this.gen1.call(this)\n        this._g2 = this.gen2.call(this)\n    }\n    function gen1() { yield 10; yield 20 }\n    function gen2() { yield 30; yield 40 }\n}\nlet obj7 = Multi7()\nassert(resume obj7._g1 == 10)\nassert(resume obj7._g2 == 30)\nassert(resume obj7._g1 == 20)\nassert(resume obj7._g2 == 40)\nprint(\"7. Multiple generators from ctor: OK\\n\")\n\n\n//--- 8. newthread + generator function ---\nlet gen8 = function() { yield 21 }\nlet th8 = newthread(gen8)\nlet r8 = th8.call()\nassert(type(r8) == \"generator\")\nassert(resume r8 == 21)\nprint(\"8. newthread + generator: OK\\n\")\n\n\nprint(\"\\nAll tests passed.\\n\")\n"
  },
  {
    "path": "testData/exec/test_class_yield_call.out",
    "content": "1. Direct .call() from ctor: OK\n2. Indirect .call() from ctor: OK\n3. .call() with value passing: OK\n4. Inherited yield via .call(): OK\n5. Deep nesting + yield .call(): OK\n6. Generator .call() outside ctor: OK\n7. Multiple generators from ctor: OK\n8. newthread + generator: OK\n\nAll tests passed.\n"
  },
  {
    "path": "testData/exec/test_shift.nut",
    "content": "from \"string\" import *\n\nlocal INT_MAX = (-1) >>> 1\nlocal INT_MIN = -INT_MAX - 1\nlocal BITS = format(\"%x\", INT_MAX).len() * 4\nlocal MAXBIT = BITS - 1  // 63 for 64-bit, 31 for 32-bit\n\nprintln(format(\"INT_MAX = %d, INT_MIN = %d, BITS = %d\\n\", INT_MAX, INT_MIN, BITS))\n\n\nlocal total = 0\nlocal passed = 0\nlocal failed = 0\n\nfunction check_eq(got, expected, desc) {\n  total++\n  if (got == expected) {\n    passed++\n    println(format(\"  OK   %-62s == %20d\", desc, got))\n  } else {\n    failed++\n    println(format(\"  FAIL %-62s == %20d  (expected %d)\", desc, got, expected))\n  }\n}\n\n\n\n// ================================================================\n//  SECTION 1: Tests with LOCAL VARIABLES\n// ================================================================\n\nprintln(\"==============================================================\")\nprintln(\"  SECTION 1: Shifts with local variables\")\nprintln(\"==============================================================\\n\")\n\n// --- << (left shift) with local variables ---\n\nprintln(\"\\n[local <<] basic\")\n{\n  local x, y\n  x = 1;  y = 0;   check_eq(x << y,           1, \"x=1  << y=0\")\n  x = 1;  y = 1;   check_eq(x << y,           2, \"x=1  << y=1\")\n  x = 1;  y = 2;   check_eq(x << y,           4, \"x=1  << y=2\")\n  x = 1;  y = 10;  check_eq(x << y,        1024, \"x=1  << y=10\")\n  x = 3;  y = 4;   check_eq(x << y,          48, \"x=3  << y=4\")\n  x = 0xFF; y = 8; check_eq(x << y,       65280, \"x=0xFF << y=8\")\n}\n\nprintln(\"\\n[local <<] zero value\")\n{\n  local x = 0, y\n  y = 0;       check_eq(x << y, 0, \"x=0 << y=0\")\n  y = 1;       check_eq(x << y, 0, \"x=0 << y=1\")\n  y = MAXBIT;  check_eq(x << y, 0, format(\"x=0 << y=%d\", MAXBIT))\n  y = -1;      check_eq(x << y, 0, \"x=0 << y=-1\")\n}\n\nprintln(\"\\n[local <<] negative shift (direction reversal)\")\n{\n  local x, y\n  x = 8;    y = -1;  check_eq(x << y,  4, \"x=8    << y=-1\")\n  x = 8;    y = -2;  check_eq(x << y,  2, \"x=8    << y=-2\")\n  x = 8;    y = -3;  check_eq(x << y,  1, \"x=8    << y=-3\")\n  x = 1024; y = -10; check_eq(x << y,  1, \"x=1024 << y=-10\")\n  x = 16;   y = -1;  check_eq(x << y,  8, \"x=16   << y=-1\")\n}\n\nprintln(format(\"\\n[local <<] overflow (shift >= %d)\", BITS))\n{\n  local x, y\n  x = 1;  y = BITS;      check_eq(x << y, 0, format(\"x=1  << y=%d\", BITS))\n  x = 1;  y = BITS + 1;  check_eq(x << y, 0, format(\"x=1  << y=%d\", BITS + 1))\n  x = 1;  y = BITS * 3;  check_eq(x << y, 0, format(\"x=1  << y=%d\", BITS * 3))\n  x = -1; y = BITS;      check_eq(x << y, 0, format(\"x=-1 << y=%d\", BITS))\n  x = INT_MAX; y = BITS; check_eq(x << y, 0, format(\"x=INT_MAX << y=%d\", BITS))\n}\n\nprintln(\"\\n[local <<] negative value\")\n{\n  local x = -1, y\n  y = 0;       check_eq(x << y,      -1, \"x=-1 << y=0\")\n  y = 1;       check_eq(x << y,      -2, \"x=-1 << y=1\")\n  y = MAXBIT;  check_eq(x << y, INT_MIN, format(\"x=-1 << y=%d\", MAXBIT))\n}\n\nprintln(\"\\n[local <<] extreme values\")\n{\n  local x, y\n  x = INT_MAX; y = 0;     check_eq(x << y, INT_MAX, \"x=INT_MAX << y=0\")\n  x = INT_MAX; y = 1;     check_eq(x << y,      -2, \"x=INT_MAX << y=1\")\n  x = INT_MAX; y = BITS;  check_eq(x << y,       0, format(\"x=INT_MAX << y=%d\", BITS))\n  x = INT_MIN; y = 0;     check_eq(x << y, INT_MIN, \"x=INT_MIN << y=0\")\n  x = INT_MIN; y = 1;     check_eq(x << y,       0, \"x=INT_MIN << y=1\")\n  x = INT_MIN; y = BITS;  check_eq(x << y,       0, format(\"x=INT_MIN << y=%d\", BITS))\n  x = 1;  y = INT_MIN;    check_eq(x << y,       0, \"x=1  << y=INT_MIN\")\n  x = -1; y = INT_MIN;    check_eq(x << y,      -1, \"x=-1 << y=INT_MIN\")\n  x = 1;  y = INT_MAX;    check_eq(x << y,       0, \"x=1  << y=INT_MAX\")\n  x = -1; y = INT_MAX;    check_eq(x << y,       0, \"x=-1 << y=INT_MAX\")\n  x = INT_MAX; y = -1;    check_eq(x << y, INT_MAX / 2, \"x=INT_MAX << y=-1\")\n  x = INT_MIN; y = -1;    check_eq(x << y, INT_MIN / 2, \"x=INT_MIN << y=-1\")  // arithmetic >> 1 of 0x800...0\n  x = 1; y = -BITS;       check_eq(x << y, 0, format(\"x=1 << y=-%d\", BITS))\n  x = 1; y = -(BITS + 1); check_eq(x << y, 0, format(\"x=1 << y=-%d\", BITS + 1))\n  x = 1; y = -(BITS * 3); check_eq(x << y, 0, format(\"x=1 << y=-%d\", BITS * 3))\n}\n\nprintln(\"\\n[local <<] boundary 31/32/33 and 63/64/65\")\n{\n  local x, y\n  // positive shifts\n  x = 1; y = 31; check_eq(x << y,  2147483648, \"x=1  << y=31\")\n  x = 1; y = 32; check_eq(x << y,  4294967296, \"x=1  << y=32\")\n  x = 1; y = 33; check_eq(x << y,  8589934592, \"x=1  << y=33\")\n  x = 1; y = 63; check_eq(x << y,     INT_MIN, \"x=1  << y=63\")\n  x = 1; y = 64; check_eq(x << y,           0, \"x=1  << y=64\")\n  x = 1; y = 65; check_eq(x << y,           0, \"x=1  << y=65\")\n\n  x = -1; y = 31; check_eq(x << y, -2147483648, \"x=-1 << y=31\")\n  x = -1; y = 32; check_eq(x << y, -4294967296, \"x=-1 << y=32\")\n  x = -1; y = 33; check_eq(x << y, -8589934592, \"x=-1 << y=33\")\n  x = -1; y = 63; check_eq(x << y,     INT_MIN, \"x=-1 << y=63\")\n  x = -1; y = 64; check_eq(x << y,           0, \"x=-1 << y=64\")\n  x = -1; y = 65; check_eq(x << y,           0, \"x=-1 << y=65\")\n\n  // negative shifts (reverse to >>)\n  x = INT_MIN; y = -31; check_eq(x << y, -4294967296, \"x=INT_MIN << y=-31\")  // arithmetic >> 31\n  x = INT_MIN; y = -32; check_eq(x << y, -2147483648, \"x=INT_MIN << y=-32\")\n  x = INT_MIN; y = -33; check_eq(x << y, -1073741824, \"x=INT_MIN << y=-33\")\n  x = INT_MIN; y = -63; check_eq(x << y,          -1, \"x=INT_MIN << y=-63\")\n  x = INT_MIN; y = -64; check_eq(x << y,          -1, \"x=INT_MIN << y=-64\")\n  x = INT_MIN; y = -65; check_eq(x << y,          -1, \"x=INT_MIN << y=-65\")\n}\n\n\n// --- >> (arithmetic right shift) with local variables ---\n\nprintln(\"\\n[local >>] basic\")\n{\n  local x, y\n  x = 8;    y = 0;  check_eq(x >> y,   8, \"x=8    >> y=0\")\n  x = 8;    y = 1;  check_eq(x >> y,   4, \"x=8    >> y=1\")\n  x = 8;    y = 2;  check_eq(x >> y,   2, \"x=8    >> y=2\")\n  x = 8;    y = 3;  check_eq(x >> y,   1, \"x=8    >> y=3\")\n  x = 8;    y = 4;  check_eq(x >> y,   0, \"x=8    >> y=4\")\n  x = 1024; y = 10; check_eq(x >> y,   1, \"x=1024 >> y=10\")\n  x = 0xFF00; y = 8; check_eq(x >> y, 255, \"x=0xFF00 >> y=8\")\n}\n\nprintln(\"\\n[local >>] zero value\")\n{\n  local x = 0, y\n  y = 0;       check_eq(x >> y, 0, \"x=0 >> y=0\")\n  y = 1;       check_eq(x >> y, 0, \"x=0 >> y=1\")\n  y = MAXBIT;  check_eq(x >> y, 0, format(\"x=0 >> y=%d\", MAXBIT))\n  y = -1;      check_eq(x >> y, 0, \"x=0 >> y=-1\")\n}\n\nprintln(\"\\n[local >>] negative shift (direction reversal)\")\n{\n  local x, y\n  x = 1; y = -1;  check_eq(x >> y,    2, \"x=1 >> y=-1\")\n  x = 1; y = -2;  check_eq(x >> y,    4, \"x=1 >> y=-2\")\n  x = 1; y = -10; check_eq(x >> y, 1024, \"x=1 >> y=-10\")\n  x = 3; y = -4;  check_eq(x >> y,   48, \"x=3 >> y=-4\")\n}\n\nprintln(\"\\n[local >>] overflow positive\")\n{\n  local x, y\n  x = 1;       y = BITS;      check_eq(x >> y, 0, format(\"x=1       >> y=%d\", BITS))\n  x = 1;       y = BITS + 1;  check_eq(x >> y, 0, format(\"x=1       >> y=%d\", BITS + 1))\n  x = 1;       y = BITS * 3;  check_eq(x >> y, 0, format(\"x=1       >> y=%d\", BITS * 3))\n  x = INT_MAX; y = BITS;      check_eq(x >> y, 0, format(\"x=INT_MAX >> y=%d\", BITS))\n}\n\nprintln(\"\\n[local >>] overflow negative (sign fill)\")\n{\n  local x, y\n  x = -1;      y = BITS;      check_eq(x >> y, -1, format(\"x=-1      >> y=%d\", BITS))\n  x = -1;      y = BITS + 1;  check_eq(x >> y, -1, format(\"x=-1      >> y=%d\", BITS + 1))\n  x = -1;      y = BITS * 3;  check_eq(x >> y, -1, format(\"x=-1      >> y=%d\", BITS * 3))\n  x = INT_MIN; y = BITS;      check_eq(x >> y, -1, format(\"x=INT_MIN >> y=%d\", BITS))\n  x = -42;     y = BITS;      check_eq(x >> y, -1, format(\"x=-42     >> y=%d\", BITS))\n}\n\nprintln(\"\\n[local >>] negative value\")\n{\n  local x, y\n  x = -1;      y = 1; check_eq(x >> y,          -1, \"x=-1      >> y=1\")\n  x = -2;      y = 1; check_eq(x >> y,          -1, \"x=-2      >> y=1\")\n  x = INT_MIN; y = 1; check_eq(x >> y, INT_MIN / 2, \"x=INT_MIN >> y=1\")\n}\n\nprintln(\"\\n[local >>] extreme values\")\n{\n  local x, y\n  x = INT_MAX; y = 0;        check_eq(x >> y,  INT_MAX, \"x=INT_MAX >> y=0\")\n  x = INT_MIN; y = 0;        check_eq(x >> y,  INT_MIN, \"x=INT_MIN >> y=0\")\n  x = 1;       y = INT_MIN;  check_eq(x >> y,        0, \"x=1       >> y=INT_MIN\")\n  x = -1;      y = INT_MIN;  check_eq(x >> y,       -1, \"x=-1      >> y=INT_MIN\")\n  x = INT_MIN; y = INT_MIN;  check_eq(x >> y,       -1, \"x=INT_MIN >> y=INT_MIN\")\n  x = 1;       y = INT_MAX;  check_eq(x >> y,        0, \"x=1       >> y=INT_MAX\")\n  x = -1;      y = INT_MAX;  check_eq(x >> y,       -1, \"x=-1      >> y=INT_MAX\")\n  x = 1;       y = -1;       check_eq(x >> y,        2, \"x=1       >> y=-1\")\n  x = INT_MAX; y = -1;       check_eq(x >> y,       -2, \"x=INT_MAX >> y=-1\")\n  x = 1;       y = -BITS;    check_eq(x >> y,        0, format(\"x=1  >> y=-%d\", BITS))\n  x = -1;      y = -BITS;    check_eq(x >> y,       -1, format(\"x=-1 >> y=-%d\", BITS))\n  x = 1;       y = -(BITS*3);check_eq(x >> y,        0, format(\"x=1  >> y=-%d\", BITS * 3))\n}\n\nprintln(\"\\n[local >>] boundary 31/32/33 and 63/64/65\")\n{\n  local x, y\n  x = 1; y = 31; check_eq(x >> y,           0, \"x=1  >> y=31\")\n  x = 1; y = 32; check_eq(x >> y,           0, \"x=1  >> y=32\")\n  x = 1; y = 33; check_eq(x >> y,           0, \"x=1  >> y=33\")\n  x = 1; y = 63; check_eq(x >> y,           0, \"x=1  >> y=63\")\n  x = 1; y = 64; check_eq(x >> y,           0, \"x=1  >> y=64\")\n  x = 1; y = 65; check_eq(x >> y,           0, \"x=1  >> y=65\")\n\n  x = -1; y = 31; check_eq(x >> y,          -1, \"x=-1 >> y=31\")\n  x = -1; y = 32; check_eq(x >> y,          -1, \"x=-1 >> y=32\")\n  x = -1; y = 33; check_eq(x >> y,          -1, \"x=-1 >> y=33\")\n  x = -1; y = 63; check_eq(x >> y,          -1, \"x=-1 >> y=63\")\n  x = -1; y = 64; check_eq(x >> y,          -1, \"x=-1 >> y=64\")\n  x = -1; y = 65; check_eq(x >> y,          -1, \"x=-1 >> y=65\")\n\n  x = INT_MIN; y = 31; check_eq(x >> y, -4294967296, \"x=INT_MIN >> y=31\")\n  x = INT_MIN; y = 32; check_eq(x >> y, -2147483648, \"x=INT_MIN >> y=32\")\n  x = INT_MIN; y = 33; check_eq(x >> y, -1073741824, \"x=INT_MIN >> y=33\")\n  x = INT_MIN; y = 63; check_eq(x >> y,          -1, \"x=INT_MIN >> y=63\")\n  x = INT_MIN; y = 64; check_eq(x >> y,          -1, \"x=INT_MIN >> y=64\")\n  x = INT_MIN; y = 65; check_eq(x >> y,          -1, \"x=INT_MIN >> y=65\")\n\n  // negative shifts (reverse to <<)\n  x = 1; y = -31; check_eq(x >> y,  2147483648, \"x=1  >> y=-31\")\n  x = 1; y = -32; check_eq(x >> y,  4294967296, \"x=1  >> y=-32\")\n  x = 1; y = -33; check_eq(x >> y,  8589934592, \"x=1  >> y=-33\")\n  x = 1; y = -63; check_eq(x >> y,     INT_MIN, \"x=1  >> y=-63\")\n  x = 1; y = -64; check_eq(x >> y,           0, \"x=1  >> y=-64\")\n  x = 1; y = -65; check_eq(x >> y,           0, \"x=1  >> y=-65\")\n\n  x = INT_MIN; y = -31; check_eq(x >> y,   0, \"x=INT_MIN >> y=-31\")\n  x = INT_MIN; y = -32; check_eq(x >> y,   0, \"x=INT_MIN >> y=-32\")\n  x = INT_MIN; y = -33; check_eq(x >> y,   0, \"x=INT_MIN >> y=-33\")\n  x = INT_MIN; y = -63; check_eq(x >> y,   0, \"x=INT_MIN >> y=-63\")\n  x = INT_MIN; y = -64; check_eq(x >> y,  -1, \"x=INT_MIN >> y=-64\")\n  x = INT_MIN; y = -65; check_eq(x >> y,  -1, \"x=INT_MIN >> y=-65\")\n}\n\n\n// --- >>> (unsigned right shift) with local variables ---\n\nprintln(\"\\n[local >>>] basic\")\n{\n  local x, y\n  x = 8;      y = 0; check_eq(x >>> y,   8, \"x=8      >>> y=0\")\n  x = 8;      y = 1; check_eq(x >>> y,   4, \"x=8      >>> y=1\")\n  x = 8;      y = 2; check_eq(x >>> y,   2, \"x=8      >>> y=2\")\n  x = 8;      y = 3; check_eq(x >>> y,   1, \"x=8      >>> y=3\")\n  x = 8;      y = 4; check_eq(x >>> y,   0, \"x=8      >>> y=4\")\n  x = 0xFF00; y = 8; check_eq(x >>> y, 255, \"x=0xFF00 >>> y=8\")\n}\n\nprintln(\"\\n[local >>>] zero value\")\n{\n  local x = 0, y\n  y = 0;       check_eq(x >>> y, 0, \"x=0 >>> y=0\")\n  y = 1;       check_eq(x >>> y, 0, \"x=0 >>> y=1\")\n  y = MAXBIT;  check_eq(x >>> y, 0, format(\"x=0 >>> y=%d\", MAXBIT))\n  y = -1;      check_eq(x >>> y, 0, \"x=0 >>> y=-1\")\n}\n\nprintln(\"\\n[local >>>] negative shift (direction reversal)\")\n{\n  local x, y\n  x = 1; y = -1;  check_eq(x >>> y,    2, \"x=1 >>> y=-1\")\n  x = 1; y = -2;  check_eq(x >>> y,    4, \"x=1 >>> y=-2\")\n  x = 1; y = -10; check_eq(x >>> y, 1024, \"x=1 >>> y=-10\")\n}\n\nprintln(format(\"\\n[local >>>] overflow (shift >= %d)\", BITS))\n{\n  local x, y\n  x = 1;       y = BITS;     check_eq(x >>> y, 0, format(\"x=1       >>> y=%d\", BITS))\n  x = 1;       y = BITS + 1; check_eq(x >>> y, 0, format(\"x=1       >>> y=%d\", BITS + 1))\n  x = -1;      y = BITS;     check_eq(x >>> y, 0, format(\"x=-1      >>> y=%d\", BITS))\n  x = INT_MIN; y = BITS;     check_eq(x >>> y, 0, format(\"x=INT_MIN >>> y=%d\", BITS))\n  x = INT_MAX; y = BITS;     check_eq(x >>> y, 0, format(\"x=INT_MAX >>> y=%d\", BITS))\n}\n\nprintln(\"\\n[local >>>] negative value\")\n{\n  local x, y\n  x = -1;      y = 1;       check_eq(x >>> y, INT_MAX, \"x=-1      >>> y=1\")\n  x = INT_MIN; y = 1;       check_eq(x >>> y, 1 << (MAXBIT - 1), \"x=INT_MIN >>> y=1\")\n  x = -1;      y = MAXBIT;  check_eq(x >>> y, 1, format(\"x=-1 >>> y=%d\", MAXBIT))\n}\n\nprintln(\"\\n[local >>>] extreme values\")\n{\n  local x, y\n  x = INT_MAX; y = 0;         check_eq(x >>> y,  INT_MAX, \"x=INT_MAX >>> y=0\")\n  x = INT_MIN; y = 0;         check_eq(x >>> y,  INT_MIN, \"x=INT_MIN >>> y=0\")\n  x = 1;       y = INT_MIN;   check_eq(x >>> y,        0, \"x=1       >>> y=INT_MIN\")\n  x = -1;      y = INT_MIN;   check_eq(x >>> y,        0, \"x=-1      >>> y=INT_MIN\")\n  x = INT_MIN; y = INT_MIN;   check_eq(x >>> y,        0, \"x=INT_MIN >>> y=INT_MIN\")\n  x = 1;       y = INT_MAX;   check_eq(x >>> y,        0, \"x=1       >>> y=INT_MAX\")\n  x = -1;      y = INT_MAX;   check_eq(x >>> y,        0, \"x=-1      >>> y=INT_MAX\")\n  x = 1;       y = -1;        check_eq(x >>> y,        2, \"x=1       >>> y=-1\")\n  x = INT_MAX; y = -1;        check_eq(x >>> y,       -2, \"x=INT_MAX >>> y=-1\")\n  x = 1;       y = -BITS;     check_eq(x >>> y,        0, format(\"x=1  >>> y=-%d\", BITS))\n  x = -1;      y = -BITS;     check_eq(x >>> y,        0, format(\"x=-1 >>> y=-%d\", BITS))\n  x = 1;       y = -(BITS*3); check_eq(x >>> y,        0, format(\"x=1  >>> y=-%d\", BITS * 3))\n}\n\nprintln(\"\\n[local >>>] boundary 31/32/33 and 63/64/65\")\n{\n  local x, y\n  x = 1; y = 31; check_eq(x >>> y,           0, \"x=1  >>> y=31\")\n  x = 1; y = 32; check_eq(x >>> y,           0, \"x=1  >>> y=32\")\n  x = 1; y = 33; check_eq(x >>> y,           0, \"x=1  >>> y=33\")\n  x = 1; y = 63; check_eq(x >>> y,           0, \"x=1  >>> y=63\")\n  x = 1; y = 64; check_eq(x >>> y,           0, \"x=1  >>> y=64\")\n  x = 1; y = 65; check_eq(x >>> y,           0, \"x=1  >>> y=65\")\n\n  x = -1; y = 31; check_eq(x >>> y,  8589934591, \"x=-1 >>> y=31\")\n  x = -1; y = 32; check_eq(x >>> y,  4294967295, \"x=-1 >>> y=32\")\n  x = -1; y = 33; check_eq(x >>> y,  2147483647, \"x=-1 >>> y=33\")\n  x = -1; y = 63; check_eq(x >>> y,           1, \"x=-1 >>> y=63\")\n  x = -1; y = 64; check_eq(x >>> y,           0, \"x=-1 >>> y=64\")\n  x = -1; y = 65; check_eq(x >>> y,           0, \"x=-1 >>> y=65\")\n\n  x = INT_MIN; y = 31; check_eq(x >>> y,  4294967296, \"x=INT_MIN >>> y=31\")\n  x = INT_MIN; y = 32; check_eq(x >>> y,  2147483648, \"x=INT_MIN >>> y=32\")\n  x = INT_MIN; y = 33; check_eq(x >>> y,  1073741824, \"x=INT_MIN >>> y=33\")\n  x = INT_MIN; y = 63; check_eq(x >>> y,           1, \"x=INT_MIN >>> y=63\")\n  x = INT_MIN; y = 64; check_eq(x >>> y,           0, \"x=INT_MIN >>> y=64\")\n  x = INT_MIN; y = 65; check_eq(x >>> y,           0, \"x=INT_MIN >>> y=65\")\n\n  // negative shifts (reverse to <<)\n  x = 1; y = -31; check_eq(x >>> y,  2147483648, \"x=1  >>> y=-31\")\n  x = 1; y = -32; check_eq(x >>> y,  4294967296, \"x=1  >>> y=-32\")\n  x = 1; y = -33; check_eq(x >>> y,  8589934592, \"x=1  >>> y=-33\")\n  x = 1; y = -63; check_eq(x >>> y,     INT_MIN, \"x=1  >>> y=-63\")\n  x = 1; y = -64; check_eq(x >>> y,           0, \"x=1  >>> y=-64\")\n  x = 1; y = -65; check_eq(x >>> y,           0, \"x=1  >>> y=-65\")\n\n  x = INT_MIN; y = -31; check_eq(x >>> y,  0, \"x=INT_MIN >>> y=-31\")\n  x = INT_MIN; y = -32; check_eq(x >>> y,  0, \"x=INT_MIN >>> y=-32\")\n  x = INT_MIN; y = -33; check_eq(x >>> y,  0, \"x=INT_MIN >>> y=-33\")\n  x = INT_MIN; y = -63; check_eq(x >>> y,  0, \"x=INT_MIN >>> y=-63\")\n  x = INT_MIN; y = -64; check_eq(x >>> y,  0, \"x=INT_MIN >>> y=-64\")\n  x = INT_MIN; y = -65; check_eq(x >>> y,  0, \"x=INT_MIN >>> y=-65\")\n}\n\n// --- cross-function with local variables ---\n\nprintln(\"\\n[local cross] left/right inverse\")\n{\n  local x, y\n  x = 1;  y = 10; check_eq((x << y) >> y,   1, \"(x=1  << y=10) >> y=10\")\n  x = 42; y = 5;  check_eq((x << y) >> y,  42, \"(x=42 << y=5)  >> y=5\")\n}\n\nprintln(format(\"\\n[local cross] shift by %d (boundary)\", MAXBIT))\n{\n  local x, y\n  x = 1;       y = MAXBIT; check_eq(x << y,   INT_MIN, format(\"x=1       << y=%d\", MAXBIT))\n  x = INT_MIN; y = MAXBIT; check_eq(x >> y,        -1, format(\"x=INT_MIN >> y=%d\", MAXBIT))\n  x = INT_MIN; y = MAXBIT; check_eq(x >>> y,        1, format(\"x=INT_MIN >>> y=%d\", MAXBIT))\n  x = -1;      y = MAXBIT; check_eq(x >> y,        -1, format(\"x=-1      >> y=%d\", MAXBIT))\n  x = -1;      y = MAXBIT; check_eq(x >>> y,        1, format(\"x=-1      >>> y=%d\", MAXBIT))\n}\n\n\n// ================================================================\n//  SECTION 2: Tests with NUMERIC CONSTANTS (literal expressions)\n// ================================================================\n\nprintln(\"\\n==============================================================\")\nprintln(\"  SECTION 2: Shifts with numeric constants\")\nprintln(\"==============================================================\\n\")\n\n// --- << with constants ---\n\nprintln(\"\\n[const expr <<] basic\")\ncheck_eq(1 << 0,           1, \"1 << 0\")\ncheck_eq(1 << 1,           2, \"1 << 1\")\ncheck_eq(1 << 2,           4, \"1 << 2\")\ncheck_eq(1 << 10,       1024, \"1 << 10\")\ncheck_eq(3 << 4,          48, \"3 << 4\")\ncheck_eq(0xFF << 8,    65280, \"0xFF << 8\")\n\nprintln(\"\\n[const expr <<] zero value\")\ncheck_eq(0 << 0,  0, \"0 << 0\")\ncheck_eq(0 << 1,  0, \"0 << 1\")\ncheck_eq(0 << -1, 0, \"0 << -1\")\n\nprintln(\"\\n[const expr <<] negative shift\")\ncheck_eq(8 << -1,      4, \"8 << -1\")\ncheck_eq(8 << -2,      2, \"8 << -2\")\ncheck_eq(8 << -3,      1, \"8 << -3\")\ncheck_eq(1024 << -10,  1, \"1024 << -10\")\ncheck_eq(16 << -1,     8, \"16 << -1\")\n\nprintln(\"\\n[const expr <<] negative value\")\ncheck_eq(-1 << 0,  -1, \"-1 << 0\")\ncheck_eq(-1 << 1,  -2, \"-1 << 1\")\n\nprintln(\"\\n[const expr <<] 32-bit range\")\n// These are valid (non-overflow) shifts in 64-bit\ncheck_eq(1 << 31,   2147483648,    \"1 << 31\")\ncheck_eq(1 << 32,   4294967296,    \"1 << 32\")\ncheck_eq(-1 << 31, -2147483648,    \"-1 << 31\")\ncheck_eq(-1 << 32, -4294967296,    \"-1 << 32\")\n\nprintln(\"\\n[const expr <<] overflow (shift >= BITS)\")\n{\n  local x\n  x = 1;  check_eq(x << BITS,       0, format(\"1 << %d\", BITS))\n  x = -1; check_eq(x << BITS,       0, format(\"-1 << %d\", BITS))\n  x = 1;  check_eq(x << (BITS + 1), 0, format(\"1 << %d\", BITS + 1))\n}\n\nprintln(\"\\n[const expr <<] extreme\")\ncheck_eq(1 << -32,   0, \"1 << -32\")\ncheck_eq(1 << -33,   0, \"1 << -33\")\ncheck_eq(1 << -100,  0, \"1 << -100\")\n{\n  local x\n  x = INT_MAX; check_eq(x << 0,  INT_MAX, \"INT_MAX << 0\")\n  x = INT_MAX; check_eq(x << 1,       -2, \"INT_MAX << 1\")\n  x = INT_MIN; check_eq(x << 0,  INT_MIN, \"INT_MIN << 0\")\n  x = INT_MIN; check_eq(x << 1,        0, \"INT_MIN << 1\")\n}\n\nprintln(\"\\n[const expr <<] boundary 31/32/33 and 63/64/65\")\ncheck_eq(1 << 33,   8589934592,  \"1 << 33\")\ncheck_eq(1 << 63,   INT_MIN,     \"1 << 63\")\ncheck_eq(1 << 64,   0,           \"1 << 64\")\ncheck_eq(1 << 65,   0,           \"1 << 65\")\ncheck_eq(-1 << 33, -8589934592,  \"-1 << 33\")\ncheck_eq(-1 << 63,  INT_MIN,     \"-1 << 63\")\ncheck_eq(-1 << 64,  0,           \"-1 << 64\")\ncheck_eq(-1 << 65,  0,           \"-1 << 65\")\n{\n  local x\n  x = INT_MIN; check_eq(x << -31, -4294967296, \"INT_MIN << -31\")\n  x = INT_MIN; check_eq(x << -32, -2147483648, \"INT_MIN << -32\")\n  x = INT_MIN; check_eq(x << -33, -1073741824, \"INT_MIN << -33\")\n  x = INT_MIN; check_eq(x << -63,          -1, \"INT_MIN << -63\")\n  x = INT_MIN; check_eq(x << -64,          -1, \"INT_MIN << -64\")\n  x = INT_MIN; check_eq(x << -65,          -1, \"INT_MIN << -65\")\n}\n\n// --- >> with constants ---\n\nprintln(\"\\n[const expr >>] basic\")\ncheck_eq(8 >> 0,       8, \"8 >> 0\")\ncheck_eq(8 >> 1,       4, \"8 >> 1\")\ncheck_eq(8 >> 2,       2, \"8 >> 2\")\ncheck_eq(8 >> 3,       1, \"8 >> 3\")\ncheck_eq(8 >> 4,       0, \"8 >> 4\")\ncheck_eq(1024 >> 10,   1, \"1024 >> 10\")\ncheck_eq(0xFF00 >> 8, 255, \"0xFF00 >> 8\")\n\nprintln(\"\\n[const expr >>] zero value\")\ncheck_eq(0 >> 0,  0, \"0 >> 0\")\ncheck_eq(0 >> 1,  0, \"0 >> 1\")\ncheck_eq(0 >> -1, 0, \"0 >> -1\")\n\nprintln(\"\\n[const expr >>] negative shift\")\ncheck_eq(1 >> -1,     2, \"1 >> -1\")\ncheck_eq(1 >> -2,     4, \"1 >> -2\")\ncheck_eq(1 >> -10, 1024, \"1 >> -10\")\ncheck_eq(3 >> -4,    48, \"3 >> -4\")\n\nprintln(\"\\n[const expr >>] overflow\")\n{\n  local x\n  x = 1;       check_eq(x >> BITS,       0, format(\"1       >> %d\", BITS))\n  x = 1;       check_eq(x >> (BITS + 1), 0, format(\"1       >> %d\", BITS + 1))\n  x = INT_MAX; check_eq(x >> BITS,       0, format(\"INT_MAX >> %d\", BITS))\n  x = -1;      check_eq(x >> BITS,      -1, format(\"-1      >> %d\", BITS))\n  x = -1;      check_eq(x >> (BITS + 1),-1, format(\"-1      >> %d\", BITS + 1))\n  x = INT_MIN; check_eq(x >> BITS,      -1, format(\"INT_MIN >> %d\", BITS))\n  x = -42;     check_eq(x >> BITS,      -1, format(\"-42     >> %d\", BITS))\n}\n\nprintln(\"\\n[const expr >>] negative value\")\n{\n  local x\n  x = -1;      check_eq(x >> 1,          -1, \"-1      >> 1\")\n  x = -2;      check_eq(x >> 1,          -1, \"-2      >> 1\")\n  x = INT_MIN; check_eq(x >> 1, INT_MIN / 2, \"INT_MIN >> 1\")\n}\n\nprintln(\"\\n[const expr >>] extreme\")\ncheck_eq(1 >> -32,  4294967296, \"1 >> -32\")   // reverses to 1 << 32, valid in 64-bit\ncheck_eq(1 >> -100,          0, \"1 >> -100\")  // reverses to 1 << 100, overflow\n{\n  local x\n  x = INT_MAX; check_eq(x >> 0, INT_MAX, \"INT_MAX >> 0\")\n  x = INT_MIN; check_eq(x >> 0, INT_MIN, \"INT_MIN >> 0\")\n}\n\nprintln(\"\\n[const expr >>] boundary 31/32/33 and 63/64/65\")\n{\n  local x\n  // x=-1 positive shifts\n  x = -1; check_eq(x >> 31,          -1, \"-1 >> 31\")\n  x = -1; check_eq(x >> 32,          -1, \"-1 >> 32\")\n  x = -1; check_eq(x >> 33,          -1, \"-1 >> 33\")\n  x = -1; check_eq(x >> 63,          -1, \"-1 >> 63\")\n  x = -1; check_eq(x >> 64,          -1, \"-1 >> 64\")\n  x = -1; check_eq(x >> 65,          -1, \"-1 >> 65\")\n\n  x = INT_MIN; check_eq(x >> 31, -4294967296, \"INT_MIN >> 31\")\n  x = INT_MIN; check_eq(x >> 32, -2147483648, \"INT_MIN >> 32\")\n  x = INT_MIN; check_eq(x >> 33, -1073741824, \"INT_MIN >> 33\")\n  x = INT_MIN; check_eq(x >> 63,          -1, \"INT_MIN >> 63\")\n  x = INT_MIN; check_eq(x >> 64,          -1, \"INT_MIN >> 64\")\n  x = INT_MIN; check_eq(x >> 65,          -1, \"INT_MIN >> 65\")\n\n  // negative shifts (reverse to <<)\n  x = 1; check_eq(x >> -31,  2147483648, \"1 >> -31\")\n  x = 1; check_eq(x >> -33,  8589934592, \"1 >> -33\")\n  x = 1; check_eq(x >> -63,     INT_MIN, \"1 >> -63\")\n  x = 1; check_eq(x >> -64,           0, \"1 >> -64\")\n  x = 1; check_eq(x >> -65,           0, \"1 >> -65\")\n\n  x = INT_MIN; check_eq(x >> -31,  0, \"INT_MIN >> -31\")\n  x = INT_MIN; check_eq(x >> -32,  0, \"INT_MIN >> -32\")\n  x = INT_MIN; check_eq(x >> -33,  0, \"INT_MIN >> -33\")\n  x = INT_MIN; check_eq(x >> -63,  0, \"INT_MIN >> -63\")\n  x = INT_MIN; check_eq(x >> -64, -1, \"INT_MIN >> -64\")\n  x = INT_MIN; check_eq(x >> -65, -1, \"INT_MIN >> -65\")\n}\n\n// --- >>> with constants ---\n\nprintln(\"\\n[const expr >>>] basic\")\ncheck_eq(8 >>> 0,       8, \"8 >>> 0\")\ncheck_eq(8 >>> 1,       4, \"8 >>> 1\")\ncheck_eq(8 >>> 2,       2, \"8 >>> 2\")\ncheck_eq(8 >>> 3,       1, \"8 >>> 3\")\ncheck_eq(8 >>> 4,       0, \"8 >>> 4\")\ncheck_eq(0xFF00 >>> 8, 255, \"0xFF00 >>> 8\")\n\nprintln(\"\\n[const expr >>>] zero value\")\ncheck_eq(0 >>> 0,  0, \"0 >>> 0\")\ncheck_eq(0 >>> 1,  0, \"0 >>> 1\")\ncheck_eq(0 >>> -1, 0, \"0 >>> -1\")\n\nprintln(\"\\n[const expr >>>] negative shift\")\ncheck_eq(1 >>> -1,     2, \"1 >>> -1\")\ncheck_eq(1 >>> -2,     4, \"1 >>> -2\")\ncheck_eq(1 >>> -10, 1024, \"1 >>> -10\")\n\nprintln(\"\\n[const expr >>>] overflow\")\n{\n  local x\n  x = 1;       check_eq(x >>> BITS,       0, format(\"1       >>> %d\", BITS))\n  x = 1;       check_eq(x >>> (BITS + 1), 0, format(\"1       >>> %d\", BITS + 1))\n  x = -1;      check_eq(x >>> BITS,       0, format(\"-1      >>> %d\", BITS))\n  x = INT_MIN; check_eq(x >>> BITS,       0, format(\"INT_MIN >>> %d\", BITS))\n  x = INT_MAX; check_eq(x >>> BITS,       0, format(\"INT_MAX >>> %d\", BITS))\n}\n\nprintln(\"\\n[const expr >>>] negative value\")\n{\n  local x\n  x = -1;      check_eq(x >>> 1,       INT_MAX, \"-1      >>> 1\")\n  x = INT_MIN; check_eq(x >>> 1,       1 << (MAXBIT - 1), \"INT_MIN >>> 1\")\n  x = -1;      check_eq(x >>> MAXBIT,  1, format(\"-1 >>> %d\", MAXBIT))\n}\n\nprintln(\"\\n[const expr >>>] extreme\")\ncheck_eq(1 >>> -32,  4294967296, \"1 >>> -32\")   // reverses to 1 << 32, valid in 64-bit\ncheck_eq(1 >>> -100,          0, \"1 >>> -100\")  // reverses to 1 << 100, overflow\n{\n  local x\n  x = INT_MAX; check_eq(x >>> 0, INT_MAX, \"INT_MAX >>> 0\")\n  x = INT_MIN; check_eq(x >>> 0, INT_MIN, \"INT_MIN >>> 0\")\n}\n\nprintln(\"\\n[const expr >>>] boundary 31/32/33 and 63/64/65\")\n{\n  local x\n  x = -1; check_eq(x >>> 31,  8589934591, \"-1 >>> 31\")\n  x = -1; check_eq(x >>> 32,  4294967295, \"-1 >>> 32\")\n  x = -1; check_eq(x >>> 33,  2147483647, \"-1 >>> 33\")\n  x = -1; check_eq(x >>> 63,           1, \"-1 >>> 63\")\n  x = -1; check_eq(x >>> 64,           0, \"-1 >>> 64\")\n  x = -1; check_eq(x >>> 65,           0, \"-1 >>> 65\")\n\n  x = INT_MIN; check_eq(x >>> 31,  4294967296, \"INT_MIN >>> 31\")\n  x = INT_MIN; check_eq(x >>> 32,  2147483648, \"INT_MIN >>> 32\")\n  x = INT_MIN; check_eq(x >>> 33,  1073741824, \"INT_MIN >>> 33\")\n  x = INT_MIN; check_eq(x >>> 63,           1, \"INT_MIN >>> 63\")\n  x = INT_MIN; check_eq(x >>> 64,           0, \"INT_MIN >>> 64\")\n  x = INT_MIN; check_eq(x >>> 65,           0, \"INT_MIN >>> 65\")\n\n  // negative shifts (reverse to <<)\n  x = 1; check_eq(x >>> -31,  2147483648, \"1 >>> -31\")\n  x = 1; check_eq(x >>> -33,  8589934592, \"1 >>> -33\")\n  x = 1; check_eq(x >>> -63,     INT_MIN, \"1 >>> -63\")\n  x = 1; check_eq(x >>> -64,           0, \"1 >>> -64\")\n  x = 1; check_eq(x >>> -65,           0, \"1 >>> -65\")\n\n  x = INT_MIN; check_eq(x >>> -31,  0, \"INT_MIN >>> -31\")\n  x = INT_MIN; check_eq(x >>> -32,  0, \"INT_MIN >>> -32\")\n  x = INT_MIN; check_eq(x >>> -33,  0, \"INT_MIN >>> -33\")\n  x = INT_MIN; check_eq(x >>> -63,  0, \"INT_MIN >>> -63\")\n  x = INT_MIN; check_eq(x >>> -64,  0, \"INT_MIN >>> -64\")\n  x = INT_MIN; check_eq(x >>> -65,  0, \"INT_MIN >>> -65\")\n}\n\n// --- cross with constants ---\n\nprintln(format(\"\\n[const expr cross] shift by %d\", MAXBIT))\n{\n  local x\n  x = 1;       check_eq(x << MAXBIT,   INT_MIN, format(\"1       << %d\", MAXBIT))\n  x = INT_MIN; check_eq(x >> MAXBIT,        -1, format(\"INT_MIN >> %d\", MAXBIT))\n  x = INT_MIN; check_eq(x >>> MAXBIT,        1, format(\"INT_MIN >>> %d\", MAXBIT))\n  x = -1;      check_eq(x >> MAXBIT,        -1, format(\"-1      >> %d\", MAXBIT))\n  x = -1;      check_eq(x >>> MAXBIT,        1, format(\"-1      >>> %d\", MAXBIT))\n}\n\n\n// ================================================================\n//  SECTION 3: Compile-time CONST assignments (const X = literal op literal)\n// ================================================================\n\nprintln(\"\\n==============================================================\")\nprintln(\"  SECTION 3: Shifts assigned to const (compile-time folding)\")\nprintln(\"==============================================================\\n\")\n\n// --- << assigned to const ---\n\nprintln(\"\\n[const <<] basic\")\nconst SHL_1_0    = 1 << 0\nconst SHL_1_1    = 1 << 1\nconst SHL_1_2    = 1 << 2\nconst SHL_1_10   = 1 << 10\nconst SHL_3_4    = 3 << 4\nconst SHL_FF_8   = 0xFF << 8\ncheck_eq(SHL_1_0,       1, \"const = 1 << 0\")\ncheck_eq(SHL_1_1,       2, \"const = 1 << 1\")\ncheck_eq(SHL_1_2,       4, \"const = 1 << 2\")\ncheck_eq(SHL_1_10,   1024, \"const = 1 << 10\")\ncheck_eq(SHL_3_4,      48, \"const = 3 << 4\")\ncheck_eq(SHL_FF_8,  65280, \"const = 0xFF << 8\")\n\nprintln(\"\\n[const <<] zero value\")\nconst SHL_0_0  = 0 << 0\nconst SHL_0_1  = 0 << 1\nconst SHL_0_N1 = 0 << -1\ncheck_eq(SHL_0_0,  0, \"const = 0 << 0\")\ncheck_eq(SHL_0_1,  0, \"const = 0 << 1\")\ncheck_eq(SHL_0_N1, 0, \"const = 0 << -1\")\n\nprintln(\"\\n[const <<] negative shift\")\nconst SHL_8_N1     = 8 << -1\nconst SHL_8_N2     = 8 << -2\nconst SHL_8_N3     = 8 << -3\nconst SHL_1024_N10 = 1024 << -10\nconst SHL_16_N1    = 16 << -1\ncheck_eq(SHL_8_N1,     4, \"const = 8 << -1\")\ncheck_eq(SHL_8_N2,     2, \"const = 8 << -2\")\ncheck_eq(SHL_8_N3,     1, \"const = 8 << -3\")\ncheck_eq(SHL_1024_N10, 1, \"const = 1024 << -10\")\ncheck_eq(SHL_16_N1,    8, \"const = 16 << -1\")\n\nprintln(\"\\n[const <<] negative value\")\nconst SHL_N1_0  = -1 << 0\nconst SHL_N1_1  = -1 << 1\ncheck_eq(SHL_N1_0,  -1, \"const = -1 << 0\")\ncheck_eq(SHL_N1_1,  -2, \"const = -1 << 1\")\n\nprintln(\"\\n[const <<] 32-bit range (valid in 64-bit)\")\nconst SHL_1_31    = 1 << 31\nconst SHL_1_32    = 1 << 32\nconst SHL_N1_31   = -1 << 31\nconst SHL_N1_32   = -1 << 32\ncheck_eq(SHL_1_31,   2147483648,  \"const = 1 << 31\")\ncheck_eq(SHL_1_32,   4294967296,  \"const = 1 << 32\")\ncheck_eq(SHL_N1_31, -2147483648,  \"const = -1 << 31\")\ncheck_eq(SHL_N1_32, -4294967296,  \"const = -1 << 32\")\n\nprintln(\"\\n[const <<] overflow\")\nconst SHL_1_N32   = 1 << -32\nconst SHL_1_N33   = 1 << -33\nconst SHL_1_N100  = 1 << -100\ncheck_eq(SHL_1_N32,  0, \"const = 1 << -32\")\ncheck_eq(SHL_1_N33,  0, \"const = 1 << -33\")\ncheck_eq(SHL_1_N100, 0, \"const = 1 << -100\")\n\nprintln(\"\\n[const <<] boundary 33/63/64/65\")\nconst SHL_1_33    = 1 << 33\nconst SHL_1_63    = 1 << 63\nconst SHL_1_64    = 1 << 64\nconst SHL_1_65    = 1 << 65\nconst SHL_N1_33   = -1 << 33\nconst SHL_N1_63   = -1 << 63\nconst SHL_N1_64   = -1 << 64\nconst SHL_N1_65   = -1 << 65\ncheck_eq(SHL_1_33,   8589934592,  \"const = 1 << 33\")\ncheck_eq(SHL_1_63,   INT_MIN,     \"const = 1 << 63\")\ncheck_eq(SHL_1_64,   0,           \"const = 1 << 64\")\ncheck_eq(SHL_1_65,   0,           \"const = 1 << 65\")\ncheck_eq(SHL_N1_33, -8589934592,  \"const = -1 << 33\")\ncheck_eq(SHL_N1_63,  INT_MIN,     \"const = -1 << 63\")\ncheck_eq(SHL_N1_64,  0,           \"const = -1 << 64\")\ncheck_eq(SHL_N1_65,  0,           \"const = -1 << 65\")\n\nconst SHL_1_N31   = 1 << -31\nconst SHL_1_N63   = 1 << -63\nconst SHL_1_N64   = 1 << -64\nconst SHL_1_N65   = 1 << -65\ncheck_eq(SHL_1_N31,  0, \"const = 1 << -31\")\ncheck_eq(SHL_1_N63,  0, \"const = 1 << -63\")\ncheck_eq(SHL_1_N64,  0, \"const = 1 << -64\")\ncheck_eq(SHL_1_N65,  0, \"const = 1 << -65\")\n\n// --- >> assigned to const ---\n\nprintln(\"\\n[const >>] basic\")\nconst SHR_8_0      = 8 >> 0\nconst SHR_8_1      = 8 >> 1\nconst SHR_8_2      = 8 >> 2\nconst SHR_8_3      = 8 >> 3\nconst SHR_8_4      = 8 >> 4\nconst SHR_1024_10  = 1024 >> 10\nconst SHR_FF00_8   = 0xFF00 >> 8\ncheck_eq(SHR_8_0,       8, \"const = 8 >> 0\")\ncheck_eq(SHR_8_1,       4, \"const = 8 >> 1\")\ncheck_eq(SHR_8_2,       2, \"const = 8 >> 2\")\ncheck_eq(SHR_8_3,       1, \"const = 8 >> 3\")\ncheck_eq(SHR_8_4,       0, \"const = 8 >> 4\")\ncheck_eq(SHR_1024_10,   1, \"const = 1024 >> 10\")\ncheck_eq(SHR_FF00_8,  255, \"const = 0xFF00 >> 8\")\n\nprintln(\"\\n[const >>] zero value\")\nconst SHR_0_0  = 0 >> 0\nconst SHR_0_1  = 0 >> 1\nconst SHR_0_N1 = 0 >> -1\ncheck_eq(SHR_0_0,  0, \"const = 0 >> 0\")\ncheck_eq(SHR_0_1,  0, \"const = 0 >> 1\")\ncheck_eq(SHR_0_N1, 0, \"const = 0 >> -1\")\n\nprintln(\"\\n[const >>] negative shift\")\nconst SHR_1_N1  = 1 >> -1\nconst SHR_1_N2  = 1 >> -2\nconst SHR_1_N10 = 1 >> -10\nconst SHR_3_N4  = 3 >> -4\ncheck_eq(SHR_1_N1,     2, \"const = 1 >> -1\")\ncheck_eq(SHR_1_N2,     4, \"const = 1 >> -2\")\ncheck_eq(SHR_1_N10, 1024, \"const = 1 >> -10\")\ncheck_eq(SHR_3_N4,    48, \"const = 3 >> -4\")\n\nprintln(\"\\n[const >>] negative shift (large)\")\nconst SHR_1_N32   = 1 >> -32   // reverses to 1 << 32, valid in 64-bit\nconst SHR_1_N100  = 1 >> -100  // reverses to 1 << 100, overflow in 64-bit\ncheck_eq(SHR_1_N32,  4294967296, \"const = 1 >> -32\")\ncheck_eq(SHR_1_N100,          0, \"const = 1 >> -100\")\n\nprintln(\"\\n[const >>] 32-bit range (valid in 64-bit)\")\nconst SHR_BIG_31 = 4294967296 >> 31   // 2^32 >> 31 = 2\nconst SHR_BIG_32 = 4294967296 >> 32   // 2^32 >> 32 = 1\ncheck_eq(SHR_BIG_31,  2, \"const = 4294967296 >> 31\")\ncheck_eq(SHR_BIG_32,  1, \"const = 4294967296 >> 32\")\n\nprintln(\"\\n[const >>] boundary 33/63/64/65\")\nconst SHR_BIG_33  = 4294967296 >> 33   // 2^32 >> 33 = 0 (shifted past)\nconst SHR_BIG2_31 = 8589934592 >> 31   // 2^33 >> 31 = 4\nconst SHR_BIG2_32 = 8589934592 >> 32   // 2^33 >> 32 = 2\nconst SHR_BIG2_33 = 8589934592 >> 33   // 2^33 >> 33 = 1\ncheck_eq(SHR_BIG_33,   0, \"const = 4294967296 >> 33\")\ncheck_eq(SHR_BIG2_31,  4, \"const = 8589934592 >> 31\")\ncheck_eq(SHR_BIG2_32,  2, \"const = 8589934592 >> 32\")\ncheck_eq(SHR_BIG2_33,  1, \"const = 8589934592 >> 33\")\n\nconst SHR_N1_31   = -1 >> 31\nconst SHR_N1_32   = -1 >> 32\nconst SHR_N1_33   = -1 >> 33\nconst SHR_N1_63   = -1 >> 63\nconst SHR_N1_64   = -1 >> 64\nconst SHR_N1_65   = -1 >> 65\ncheck_eq(SHR_N1_31,          -1, \"const = -1 >> 31\")\ncheck_eq(SHR_N1_32,          -1, \"const = -1 >> 32\")\ncheck_eq(SHR_N1_33,          -1, \"const = -1 >> 33\")\ncheck_eq(SHR_N1_63,          -1, \"const = -1 >> 63\")\ncheck_eq(SHR_N1_64,          -1, \"const = -1 >> 64\")\ncheck_eq(SHR_N1_65,          -1, \"const = -1 >> 65\")\n\nconst SHR_1_N31   = 1 >> -31\nconst SHR_1_N33   = 1 >> -33\nconst SHR_1_N63   = 1 >> -63\nconst SHR_1_N64   = 1 >> -64\nconst SHR_1_N65   = 1 >> -65\ncheck_eq(SHR_1_N31,  2147483648, \"const = 1 >> -31\")\ncheck_eq(SHR_1_N33,  8589934592, \"const = 1 >> -33\")\ncheck_eq(SHR_1_N63,     INT_MIN, \"const = 1 >> -63\")\ncheck_eq(SHR_1_N64,           0, \"const = 1 >> -64\")\ncheck_eq(SHR_1_N65,           0, \"const = 1 >> -65\")\n\n// --- >>> assigned to const ---\n\nprintln(\"\\n[const >>>] basic\")\nconst USHR_8_0     = 8 >>> 0\nconst USHR_8_1     = 8 >>> 1\nconst USHR_8_2     = 8 >>> 2\nconst USHR_8_3     = 8 >>> 3\nconst USHR_8_4     = 8 >>> 4\nconst USHR_FF00_8  = 0xFF00 >>> 8\ncheck_eq(USHR_8_0,       8, \"const = 8 >>> 0\")\ncheck_eq(USHR_8_1,       4, \"const = 8 >>> 1\")\ncheck_eq(USHR_8_2,       2, \"const = 8 >>> 2\")\ncheck_eq(USHR_8_3,       1, \"const = 8 >>> 3\")\ncheck_eq(USHR_8_4,       0, \"const = 8 >>> 4\")\ncheck_eq(USHR_FF00_8,  255, \"const = 0xFF00 >>> 8\")\n\nprintln(\"\\n[const >>>] zero value\")\nconst USHR_0_0  = 0 >>> 0\nconst USHR_0_1  = 0 >>> 1\nconst USHR_0_N1 = 0 >>> -1\ncheck_eq(USHR_0_0,  0, \"const = 0 >>> 0\")\ncheck_eq(USHR_0_1,  0, \"const = 0 >>> 1\")\ncheck_eq(USHR_0_N1, 0, \"const = 0 >>> -1\")\n\nprintln(\"\\n[const >>>] negative shift\")\nconst USHR_1_N1  = 1 >>> -1\nconst USHR_1_N2  = 1 >>> -2\nconst USHR_1_N10 = 1 >>> -10\ncheck_eq(USHR_1_N1,     2, \"const = 1 >>> -1\")\ncheck_eq(USHR_1_N2,     4, \"const = 1 >>> -2\")\ncheck_eq(USHR_1_N10, 1024, \"const = 1 >>> -10\")\n\nprintln(\"\\n[const >>>] negative shift (large)\")\nconst USHR_1_N32   = 1 >>> -32   // reverses to 1 << 32, valid in 64-bit\nconst USHR_1_N100  = 1 >>> -100  // reverses to 1 << 100, overflow in 64-bit\ncheck_eq(USHR_1_N32,  4294967296, \"const = 1 >>> -32\")\ncheck_eq(USHR_1_N100,          0, \"const = 1 >>> -100\")\n\nprintln(\"\\n[const >>>] 32-bit range (valid in 64-bit)\")\nconst USHR_BIG_31 = 4294967296 >>> 31   // 2^32 >>> 31 = 2\nconst USHR_BIG_32 = 4294967296 >>> 32   // 2^32 >>> 32 = 1\nconst USHR_N1_1   = -1 >>> 1\ncheck_eq(USHR_BIG_31, 2, \"const = 4294967296 >>> 31\")\ncheck_eq(USHR_BIG_32, 1, \"const = 4294967296 >>> 32\")\ncheck_eq(USHR_N1_1, INT_MAX, \"const = -1 >>> 1\")\n\nprintln(\"\\n[const >>>] boundary 33/63/64/65\")\nconst USHR_BIG_33  = 4294967296 >>> 33   // 2^32 >>> 33 = 0\nconst USHR_BIG2_31 = 8589934592 >>> 31   // 2^33 >>> 31 = 4\nconst USHR_BIG2_32 = 8589934592 >>> 32   // 2^33 >>> 32 = 2\nconst USHR_BIG2_33 = 8589934592 >>> 33   // 2^33 >>> 33 = 1\ncheck_eq(USHR_BIG_33,   0, \"const = 4294967296 >>> 33\")\ncheck_eq(USHR_BIG2_31,  4, \"const = 8589934592 >>> 31\")\ncheck_eq(USHR_BIG2_32,  2, \"const = 8589934592 >>> 32\")\ncheck_eq(USHR_BIG2_33,  1, \"const = 8589934592 >>> 33\")\n\nconst USHR_N1_31   = -1 >>> 31\nconst USHR_N1_32   = -1 >>> 32\nconst USHR_N1_33   = -1 >>> 33\nconst USHR_N1_63   = -1 >>> 63\nconst USHR_N1_64   = -1 >>> 64\nconst USHR_N1_65   = -1 >>> 65\ncheck_eq(USHR_N1_31,  8589934591, \"const = -1 >>> 31\")\ncheck_eq(USHR_N1_32,  4294967295, \"const = -1 >>> 32\")\ncheck_eq(USHR_N1_33,  2147483647, \"const = -1 >>> 33\")\ncheck_eq(USHR_N1_63,           1, \"const = -1 >>> 63\")\ncheck_eq(USHR_N1_64,           0, \"const = -1 >>> 64\")\ncheck_eq(USHR_N1_65,           0, \"const = -1 >>> 65\")\n\nconst USHR_1_N31   = 1 >>> -31\nconst USHR_1_N33   = 1 >>> -33\nconst USHR_1_N63   = 1 >>> -63\nconst USHR_1_N64   = 1 >>> -64\nconst USHR_1_N65   = 1 >>> -65\ncheck_eq(USHR_1_N31,  2147483648, \"const = 1 >>> -31\")\ncheck_eq(USHR_1_N33,  8589934592, \"const = 1 >>> -33\")\ncheck_eq(USHR_1_N63,     INT_MIN, \"const = 1 >>> -63\")\ncheck_eq(USHR_1_N64,           0, \"const = 1 >>> -64\")\ncheck_eq(USHR_1_N65,           0, \"const = 1 >>> -65\")\n\n// --- const cross ---\n\nprintln(\"\\n[const cross] basic identities\")\nconst CROSS_INV_A = (1 << 10) >> 10\nconst CROSS_INV_B = (42 << 5) >> 5\ncheck_eq(CROSS_INV_A,  1, \"const = (1 << 10) >> 10\")\ncheck_eq(CROSS_INV_B, 42, \"const = (42 << 5) >> 5\")\n\n\n// ================================================================\n//  Summary\n// ================================================================\n\nprintln(format(\"\\n=== Results: %d/%d passed\", passed, total))\nif (failed > 0)\n  print(format(\", %d FAILED\", failed))\nprintln(\" ===\")\n\nif (failed > 0)\n  throw format(\"%d test(s) failed\", failed)\n"
  },
  {
    "path": "testData/exec/test_shift.out",
    "content": "INT_MAX = 9223372036854775807, INT_MIN = -9223372036854775808, BITS = 64\n\n==============================================================\n  SECTION 1: Shifts with local variables\n==============================================================\n\n\n[local <<] basic\n  OK   x=1  << y=0                                                    ==                    1\n  OK   x=1  << y=1                                                    ==                    2\n  OK   x=1  << y=2                                                    ==                    4\n  OK   x=1  << y=10                                                   ==                 1024\n  OK   x=3  << y=4                                                    ==                   48\n  OK   x=0xFF << y=8                                                  ==                65280\n\n[local <<] zero value\n  OK   x=0 << y=0                                                     ==                    0\n  OK   x=0 << y=1                                                     ==                    0\n  OK   x=0 << y=63                                                    ==                    0\n  OK   x=0 << y=-1                                                    ==                    0\n\n[local <<] negative shift (direction reversal)\n  OK   x=8    << y=-1                                                 ==                    4\n  OK   x=8    << y=-2                                                 ==                    2\n  OK   x=8    << y=-3                                                 ==                    1\n  OK   x=1024 << y=-10                                                ==                    1\n  OK   x=16   << y=-1                                                 ==                    8\n\n[local <<] overflow (shift >= 64)\n  OK   x=1  << y=64                                                   ==                    0\n  OK   x=1  << y=65                                                   ==                    0\n  OK   x=1  << y=192                                                  ==                    0\n  OK   x=-1 << y=64                                                   ==                    0\n  OK   x=INT_MAX << y=64                                              ==                    0\n\n[local <<] negative value\n  OK   x=-1 << y=0                                                    ==                   -1\n  OK   x=-1 << y=1                                                    ==                   -2\n  OK   x=-1 << y=63                                                   == -9223372036854775808\n\n[local <<] extreme values\n  OK   x=INT_MAX << y=0                                               ==  9223372036854775807\n  OK   x=INT_MAX << y=1                                               ==                   -2\n  OK   x=INT_MAX << y=64                                              ==                    0\n  OK   x=INT_MIN << y=0                                               == -9223372036854775808\n  OK   x=INT_MIN << y=1                                               ==                    0\n  OK   x=INT_MIN << y=64                                              ==                    0\n  OK   x=1  << y=INT_MIN                                              ==                    0\n  OK   x=-1 << y=INT_MIN                                              ==                   -1\n  OK   x=1  << y=INT_MAX                                              ==                    0\n  OK   x=-1 << y=INT_MAX                                              ==                    0\n  OK   x=INT_MAX << y=-1                                              ==  4611686018427387903\n  OK   x=INT_MIN << y=-1                                              == -4611686018427387904\n  OK   x=1 << y=-64                                                   ==                    0\n  OK   x=1 << y=-65                                                   ==                    0\n  OK   x=1 << y=-192                                                  ==                    0\n\n[local <<] boundary 31/32/33 and 63/64/65\n  OK   x=1  << y=31                                                   ==           2147483648\n  OK   x=1  << y=32                                                   ==           4294967296\n  OK   x=1  << y=33                                                   ==           8589934592\n  OK   x=1  << y=63                                                   == -9223372036854775808\n  OK   x=1  << y=64                                                   ==                    0\n  OK   x=1  << y=65                                                   ==                    0\n  OK   x=-1 << y=31                                                   ==          -2147483648\n  OK   x=-1 << y=32                                                   ==          -4294967296\n  OK   x=-1 << y=33                                                   ==          -8589934592\n  OK   x=-1 << y=63                                                   == -9223372036854775808\n  OK   x=-1 << y=64                                                   ==                    0\n  OK   x=-1 << y=65                                                   ==                    0\n  OK   x=INT_MIN << y=-31                                             ==          -4294967296\n  OK   x=INT_MIN << y=-32                                             ==          -2147483648\n  OK   x=INT_MIN << y=-33                                             ==          -1073741824\n  OK   x=INT_MIN << y=-63                                             ==                   -1\n  OK   x=INT_MIN << y=-64                                             ==                   -1\n  OK   x=INT_MIN << y=-65                                             ==                   -1\n\n[local >>] basic\n  OK   x=8    >> y=0                                                  ==                    8\n  OK   x=8    >> y=1                                                  ==                    4\n  OK   x=8    >> y=2                                                  ==                    2\n  OK   x=8    >> y=3                                                  ==                    1\n  OK   x=8    >> y=4                                                  ==                    0\n  OK   x=1024 >> y=10                                                 ==                    1\n  OK   x=0xFF00 >> y=8                                                ==                  255\n\n[local >>] zero value\n  OK   x=0 >> y=0                                                     ==                    0\n  OK   x=0 >> y=1                                                     ==                    0\n  OK   x=0 >> y=63                                                    ==                    0\n  OK   x=0 >> y=-1                                                    ==                    0\n\n[local >>] negative shift (direction reversal)\n  OK   x=1 >> y=-1                                                    ==                    2\n  OK   x=1 >> y=-2                                                    ==                    4\n  OK   x=1 >> y=-10                                                   ==                 1024\n  OK   x=3 >> y=-4                                                    ==                   48\n\n[local >>] overflow positive\n  OK   x=1       >> y=64                                              ==                    0\n  OK   x=1       >> y=65                                              ==                    0\n  OK   x=1       >> y=192                                             ==                    0\n  OK   x=INT_MAX >> y=64                                              ==                    0\n\n[local >>] overflow negative (sign fill)\n  OK   x=-1      >> y=64                                              ==                   -1\n  OK   x=-1      >> y=65                                              ==                   -1\n  OK   x=-1      >> y=192                                             ==                   -1\n  OK   x=INT_MIN >> y=64                                              ==                   -1\n  OK   x=-42     >> y=64                                              ==                   -1\n\n[local >>] negative value\n  OK   x=-1      >> y=1                                               ==                   -1\n  OK   x=-2      >> y=1                                               ==                   -1\n  OK   x=INT_MIN >> y=1                                               == -4611686018427387904\n\n[local >>] extreme values\n  OK   x=INT_MAX >> y=0                                               ==  9223372036854775807\n  OK   x=INT_MIN >> y=0                                               == -9223372036854775808\n  OK   x=1       >> y=INT_MIN                                         ==                    0\n  OK   x=-1      >> y=INT_MIN                                         ==                   -1\n  OK   x=INT_MIN >> y=INT_MIN                                         ==                   -1\n  OK   x=1       >> y=INT_MAX                                         ==                    0\n  OK   x=-1      >> y=INT_MAX                                         ==                   -1\n  OK   x=1       >> y=-1                                              ==                    2\n  OK   x=INT_MAX >> y=-1                                              ==                   -2\n  OK   x=1  >> y=-64                                                  ==                    0\n  OK   x=-1 >> y=-64                                                  ==                   -1\n  OK   x=1  >> y=-192                                                 ==                    0\n\n[local >>] boundary 31/32/33 and 63/64/65\n  OK   x=1  >> y=31                                                   ==                    0\n  OK   x=1  >> y=32                                                   ==                    0\n  OK   x=1  >> y=33                                                   ==                    0\n  OK   x=1  >> y=63                                                   ==                    0\n  OK   x=1  >> y=64                                                   ==                    0\n  OK   x=1  >> y=65                                                   ==                    0\n  OK   x=-1 >> y=31                                                   ==                   -1\n  OK   x=-1 >> y=32                                                   ==                   -1\n  OK   x=-1 >> y=33                                                   ==                   -1\n  OK   x=-1 >> y=63                                                   ==                   -1\n  OK   x=-1 >> y=64                                                   ==                   -1\n  OK   x=-1 >> y=65                                                   ==                   -1\n  OK   x=INT_MIN >> y=31                                              ==          -4294967296\n  OK   x=INT_MIN >> y=32                                              ==          -2147483648\n  OK   x=INT_MIN >> y=33                                              ==          -1073741824\n  OK   x=INT_MIN >> y=63                                              ==                   -1\n  OK   x=INT_MIN >> y=64                                              ==                   -1\n  OK   x=INT_MIN >> y=65                                              ==                   -1\n  OK   x=1  >> y=-31                                                  ==           2147483648\n  OK   x=1  >> y=-32                                                  ==           4294967296\n  OK   x=1  >> y=-33                                                  ==           8589934592\n  OK   x=1  >> y=-63                                                  == -9223372036854775808\n  OK   x=1  >> y=-64                                                  ==                    0\n  OK   x=1  >> y=-65                                                  ==                    0\n  OK   x=INT_MIN >> y=-31                                             ==                    0\n  OK   x=INT_MIN >> y=-32                                             ==                    0\n  OK   x=INT_MIN >> y=-33                                             ==                    0\n  OK   x=INT_MIN >> y=-63                                             ==                    0\n  OK   x=INT_MIN >> y=-64                                             ==                   -1\n  OK   x=INT_MIN >> y=-65                                             ==                   -1\n\n[local >>>] basic\n  OK   x=8      >>> y=0                                               ==                    8\n  OK   x=8      >>> y=1                                               ==                    4\n  OK   x=8      >>> y=2                                               ==                    2\n  OK   x=8      >>> y=3                                               ==                    1\n  OK   x=8      >>> y=4                                               ==                    0\n  OK   x=0xFF00 >>> y=8                                               ==                  255\n\n[local >>>] zero value\n  OK   x=0 >>> y=0                                                    ==                    0\n  OK   x=0 >>> y=1                                                    ==                    0\n  OK   x=0 >>> y=63                                                   ==                    0\n  OK   x=0 >>> y=-1                                                   ==                    0\n\n[local >>>] negative shift (direction reversal)\n  OK   x=1 >>> y=-1                                                   ==                    2\n  OK   x=1 >>> y=-2                                                   ==                    4\n  OK   x=1 >>> y=-10                                                  ==                 1024\n\n[local >>>] overflow (shift >= 64)\n  OK   x=1       >>> y=64                                             ==                    0\n  OK   x=1       >>> y=65                                             ==                    0\n  OK   x=-1      >>> y=64                                             ==                    0\n  OK   x=INT_MIN >>> y=64                                             ==                    0\n  OK   x=INT_MAX >>> y=64                                             ==                    0\n\n[local >>>] negative value\n  OK   x=-1      >>> y=1                                              ==  9223372036854775807\n  OK   x=INT_MIN >>> y=1                                              ==  4611686018427387904\n  OK   x=-1 >>> y=63                                                  ==                    1\n\n[local >>>] extreme values\n  OK   x=INT_MAX >>> y=0                                              ==  9223372036854775807\n  OK   x=INT_MIN >>> y=0                                              == -9223372036854775808\n  OK   x=1       >>> y=INT_MIN                                        ==                    0\n  OK   x=-1      >>> y=INT_MIN                                        ==                    0\n  OK   x=INT_MIN >>> y=INT_MIN                                        ==                    0\n  OK   x=1       >>> y=INT_MAX                                        ==                    0\n  OK   x=-1      >>> y=INT_MAX                                        ==                    0\n  OK   x=1       >>> y=-1                                             ==                    2\n  OK   x=INT_MAX >>> y=-1                                             ==                   -2\n  OK   x=1  >>> y=-64                                                 ==                    0\n  OK   x=-1 >>> y=-64                                                 ==                    0\n  OK   x=1  >>> y=-192                                                ==                    0\n\n[local >>>] boundary 31/32/33 and 63/64/65\n  OK   x=1  >>> y=31                                                  ==                    0\n  OK   x=1  >>> y=32                                                  ==                    0\n  OK   x=1  >>> y=33                                                  ==                    0\n  OK   x=1  >>> y=63                                                  ==                    0\n  OK   x=1  >>> y=64                                                  ==                    0\n  OK   x=1  >>> y=65                                                  ==                    0\n  OK   x=-1 >>> y=31                                                  ==           8589934591\n  OK   x=-1 >>> y=32                                                  ==           4294967295\n  OK   x=-1 >>> y=33                                                  ==           2147483647\n  OK   x=-1 >>> y=63                                                  ==                    1\n  OK   x=-1 >>> y=64                                                  ==                    0\n  OK   x=-1 >>> y=65                                                  ==                    0\n  OK   x=INT_MIN >>> y=31                                             ==           4294967296\n  OK   x=INT_MIN >>> y=32                                             ==           2147483648\n  OK   x=INT_MIN >>> y=33                                             ==           1073741824\n  OK   x=INT_MIN >>> y=63                                             ==                    1\n  OK   x=INT_MIN >>> y=64                                             ==                    0\n  OK   x=INT_MIN >>> y=65                                             ==                    0\n  OK   x=1  >>> y=-31                                                 ==           2147483648\n  OK   x=1  >>> y=-32                                                 ==           4294967296\n  OK   x=1  >>> y=-33                                                 ==           8589934592\n  OK   x=1  >>> y=-63                                                 == -9223372036854775808\n  OK   x=1  >>> y=-64                                                 ==                    0\n  OK   x=1  >>> y=-65                                                 ==                    0\n  OK   x=INT_MIN >>> y=-31                                            ==                    0\n  OK   x=INT_MIN >>> y=-32                                            ==                    0\n  OK   x=INT_MIN >>> y=-33                                            ==                    0\n  OK   x=INT_MIN >>> y=-63                                            ==                    0\n  OK   x=INT_MIN >>> y=-64                                            ==                    0\n  OK   x=INT_MIN >>> y=-65                                            ==                    0\n\n[local cross] left/right inverse\n  OK   (x=1  << y=10) >> y=10                                         ==                    1\n  OK   (x=42 << y=5)  >> y=5                                          ==                   42\n\n[local cross] shift by 63 (boundary)\n  OK   x=1       << y=63                                              == -9223372036854775808\n  OK   x=INT_MIN >> y=63                                              ==                   -1\n  OK   x=INT_MIN >>> y=63                                             ==                    1\n  OK   x=-1      >> y=63                                              ==                   -1\n  OK   x=-1      >>> y=63                                             ==                    1\n\n==============================================================\n  SECTION 2: Shifts with numeric constants\n==============================================================\n\n\n[const expr <<] basic\n  OK   1 << 0                                                         ==                    1\n  OK   1 << 1                                                         ==                    2\n  OK   1 << 2                                                         ==                    4\n  OK   1 << 10                                                        ==                 1024\n  OK   3 << 4                                                         ==                   48\n  OK   0xFF << 8                                                      ==                65280\n\n[const expr <<] zero value\n  OK   0 << 0                                                         ==                    0\n  OK   0 << 1                                                         ==                    0\n  OK   0 << -1                                                        ==                    0\n\n[const expr <<] negative shift\n  OK   8 << -1                                                        ==                    4\n  OK   8 << -2                                                        ==                    2\n  OK   8 << -3                                                        ==                    1\n  OK   1024 << -10                                                    ==                    1\n  OK   16 << -1                                                       ==                    8\n\n[const expr <<] negative value\n  OK   -1 << 0                                                        ==                   -1\n  OK   -1 << 1                                                        ==                   -2\n\n[const expr <<] 32-bit range\n  OK   1 << 31                                                        ==           2147483648\n  OK   1 << 32                                                        ==           4294967296\n  OK   -1 << 31                                                       ==          -2147483648\n  OK   -1 << 32                                                       ==          -4294967296\n\n[const expr <<] overflow (shift >= BITS)\n  OK   1 << 64                                                        ==                    0\n  OK   -1 << 64                                                       ==                    0\n  OK   1 << 65                                                        ==                    0\n\n[const expr <<] extreme\n  OK   1 << -32                                                       ==                    0\n  OK   1 << -33                                                       ==                    0\n  OK   1 << -100                                                      ==                    0\n  OK   INT_MAX << 0                                                   ==  9223372036854775807\n  OK   INT_MAX << 1                                                   ==                   -2\n  OK   INT_MIN << 0                                                   == -9223372036854775808\n  OK   INT_MIN << 1                                                   ==                    0\n\n[const expr <<] boundary 31/32/33 and 63/64/65\n  OK   1 << 33                                                        ==           8589934592\n  OK   1 << 63                                                        == -9223372036854775808\n  OK   1 << 64                                                        ==                    0\n  OK   1 << 65                                                        ==                    0\n  OK   -1 << 33                                                       ==          -8589934592\n  OK   -1 << 63                                                       == -9223372036854775808\n  OK   -1 << 64                                                       ==                    0\n  OK   -1 << 65                                                       ==                    0\n  OK   INT_MIN << -31                                                 ==          -4294967296\n  OK   INT_MIN << -32                                                 ==          -2147483648\n  OK   INT_MIN << -33                                                 ==          -1073741824\n  OK   INT_MIN << -63                                                 ==                   -1\n  OK   INT_MIN << -64                                                 ==                   -1\n  OK   INT_MIN << -65                                                 ==                   -1\n\n[const expr >>] basic\n  OK   8 >> 0                                                         ==                    8\n  OK   8 >> 1                                                         ==                    4\n  OK   8 >> 2                                                         ==                    2\n  OK   8 >> 3                                                         ==                    1\n  OK   8 >> 4                                                         ==                    0\n  OK   1024 >> 10                                                     ==                    1\n  OK   0xFF00 >> 8                                                    ==                  255\n\n[const expr >>] zero value\n  OK   0 >> 0                                                         ==                    0\n  OK   0 >> 1                                                         ==                    0\n  OK   0 >> -1                                                        ==                    0\n\n[const expr >>] negative shift\n  OK   1 >> -1                                                        ==                    2\n  OK   1 >> -2                                                        ==                    4\n  OK   1 >> -10                                                       ==                 1024\n  OK   3 >> -4                                                        ==                   48\n\n[const expr >>] overflow\n  OK   1       >> 64                                                  ==                    0\n  OK   1       >> 65                                                  ==                    0\n  OK   INT_MAX >> 64                                                  ==                    0\n  OK   -1      >> 64                                                  ==                   -1\n  OK   -1      >> 65                                                  ==                   -1\n  OK   INT_MIN >> 64                                                  ==                   -1\n  OK   -42     >> 64                                                  ==                   -1\n\n[const expr >>] negative value\n  OK   -1      >> 1                                                   ==                   -1\n  OK   -2      >> 1                                                   ==                   -1\n  OK   INT_MIN >> 1                                                   == -4611686018427387904\n\n[const expr >>] extreme\n  OK   1 >> -32                                                       ==           4294967296\n  OK   1 >> -100                                                      ==                    0\n  OK   INT_MAX >> 0                                                   ==  9223372036854775807\n  OK   INT_MIN >> 0                                                   == -9223372036854775808\n\n[const expr >>] boundary 31/32/33 and 63/64/65\n  OK   -1 >> 31                                                       ==                   -1\n  OK   -1 >> 32                                                       ==                   -1\n  OK   -1 >> 33                                                       ==                   -1\n  OK   -1 >> 63                                                       ==                   -1\n  OK   -1 >> 64                                                       ==                   -1\n  OK   -1 >> 65                                                       ==                   -1\n  OK   INT_MIN >> 31                                                  ==          -4294967296\n  OK   INT_MIN >> 32                                                  ==          -2147483648\n  OK   INT_MIN >> 33                                                  ==          -1073741824\n  OK   INT_MIN >> 63                                                  ==                   -1\n  OK   INT_MIN >> 64                                                  ==                   -1\n  OK   INT_MIN >> 65                                                  ==                   -1\n  OK   1 >> -31                                                       ==           2147483648\n  OK   1 >> -33                                                       ==           8589934592\n  OK   1 >> -63                                                       == -9223372036854775808\n  OK   1 >> -64                                                       ==                    0\n  OK   1 >> -65                                                       ==                    0\n  OK   INT_MIN >> -31                                                 ==                    0\n  OK   INT_MIN >> -32                                                 ==                    0\n  OK   INT_MIN >> -33                                                 ==                    0\n  OK   INT_MIN >> -63                                                 ==                    0\n  OK   INT_MIN >> -64                                                 ==                   -1\n  OK   INT_MIN >> -65                                                 ==                   -1\n\n[const expr >>>] basic\n  OK   8 >>> 0                                                        ==                    8\n  OK   8 >>> 1                                                        ==                    4\n  OK   8 >>> 2                                                        ==                    2\n  OK   8 >>> 3                                                        ==                    1\n  OK   8 >>> 4                                                        ==                    0\n  OK   0xFF00 >>> 8                                                   ==                  255\n\n[const expr >>>] zero value\n  OK   0 >>> 0                                                        ==                    0\n  OK   0 >>> 1                                                        ==                    0\n  OK   0 >>> -1                                                       ==                    0\n\n[const expr >>>] negative shift\n  OK   1 >>> -1                                                       ==                    2\n  OK   1 >>> -2                                                       ==                    4\n  OK   1 >>> -10                                                      ==                 1024\n\n[const expr >>>] overflow\n  OK   1       >>> 64                                                 ==                    0\n  OK   1       >>> 65                                                 ==                    0\n  OK   -1      >>> 64                                                 ==                    0\n  OK   INT_MIN >>> 64                                                 ==                    0\n  OK   INT_MAX >>> 64                                                 ==                    0\n\n[const expr >>>] negative value\n  OK   -1      >>> 1                                                  ==  9223372036854775807\n  OK   INT_MIN >>> 1                                                  ==  4611686018427387904\n  OK   -1 >>> 63                                                      ==                    1\n\n[const expr >>>] extreme\n  OK   1 >>> -32                                                      ==           4294967296\n  OK   1 >>> -100                                                     ==                    0\n  OK   INT_MAX >>> 0                                                  ==  9223372036854775807\n  OK   INT_MIN >>> 0                                                  == -9223372036854775808\n\n[const expr >>>] boundary 31/32/33 and 63/64/65\n  OK   -1 >>> 31                                                      ==           8589934591\n  OK   -1 >>> 32                                                      ==           4294967295\n  OK   -1 >>> 33                                                      ==           2147483647\n  OK   -1 >>> 63                                                      ==                    1\n  OK   -1 >>> 64                                                      ==                    0\n  OK   -1 >>> 65                                                      ==                    0\n  OK   INT_MIN >>> 31                                                 ==           4294967296\n  OK   INT_MIN >>> 32                                                 ==           2147483648\n  OK   INT_MIN >>> 33                                                 ==           1073741824\n  OK   INT_MIN >>> 63                                                 ==                    1\n  OK   INT_MIN >>> 64                                                 ==                    0\n  OK   INT_MIN >>> 65                                                 ==                    0\n  OK   1 >>> -31                                                      ==           2147483648\n  OK   1 >>> -33                                                      ==           8589934592\n  OK   1 >>> -63                                                      == -9223372036854775808\n  OK   1 >>> -64                                                      ==                    0\n  OK   1 >>> -65                                                      ==                    0\n  OK   INT_MIN >>> -31                                                ==                    0\n  OK   INT_MIN >>> -32                                                ==                    0\n  OK   INT_MIN >>> -33                                                ==                    0\n  OK   INT_MIN >>> -63                                                ==                    0\n  OK   INT_MIN >>> -64                                                ==                    0\n  OK   INT_MIN >>> -65                                                ==                    0\n\n[const expr cross] shift by 63\n  OK   1       << 63                                                  == -9223372036854775808\n  OK   INT_MIN >> 63                                                  ==                   -1\n  OK   INT_MIN >>> 63                                                 ==                    1\n  OK   -1      >> 63                                                  ==                   -1\n  OK   -1      >>> 63                                                 ==                    1\n\n==============================================================\n  SECTION 3: Shifts assigned to const (compile-time folding)\n==============================================================\n\n\n[const <<] basic\n  OK   const = 1 << 0                                                 ==                    1\n  OK   const = 1 << 1                                                 ==                    2\n  OK   const = 1 << 2                                                 ==                    4\n  OK   const = 1 << 10                                                ==                 1024\n  OK   const = 3 << 4                                                 ==                   48\n  OK   const = 0xFF << 8                                              ==                65280\n\n[const <<] zero value\n  OK   const = 0 << 0                                                 ==                    0\n  OK   const = 0 << 1                                                 ==                    0\n  OK   const = 0 << -1                                                ==                    0\n\n[const <<] negative shift\n  OK   const = 8 << -1                                                ==                    4\n  OK   const = 8 << -2                                                ==                    2\n  OK   const = 8 << -3                                                ==                    1\n  OK   const = 1024 << -10                                            ==                    1\n  OK   const = 16 << -1                                               ==                    8\n\n[const <<] negative value\n  OK   const = -1 << 0                                                ==                   -1\n  OK   const = -1 << 1                                                ==                   -2\n\n[const <<] 32-bit range (valid in 64-bit)\n  OK   const = 1 << 31                                                ==           2147483648\n  OK   const = 1 << 32                                                ==           4294967296\n  OK   const = -1 << 31                                               ==          -2147483648\n  OK   const = -1 << 32                                               ==          -4294967296\n\n[const <<] overflow\n  OK   const = 1 << -32                                               ==                    0\n  OK   const = 1 << -33                                               ==                    0\n  OK   const = 1 << -100                                              ==                    0\n\n[const <<] boundary 33/63/64/65\n  OK   const = 1 << 33                                                ==           8589934592\n  OK   const = 1 << 63                                                == -9223372036854775808\n  OK   const = 1 << 64                                                ==                    0\n  OK   const = 1 << 65                                                ==                    0\n  OK   const = -1 << 33                                               ==          -8589934592\n  OK   const = -1 << 63                                               == -9223372036854775808\n  OK   const = -1 << 64                                               ==                    0\n  OK   const = -1 << 65                                               ==                    0\n  OK   const = 1 << -31                                               ==                    0\n  OK   const = 1 << -63                                               ==                    0\n  OK   const = 1 << -64                                               ==                    0\n  OK   const = 1 << -65                                               ==                    0\n\n[const >>] basic\n  OK   const = 8 >> 0                                                 ==                    8\n  OK   const = 8 >> 1                                                 ==                    4\n  OK   const = 8 >> 2                                                 ==                    2\n  OK   const = 8 >> 3                                                 ==                    1\n  OK   const = 8 >> 4                                                 ==                    0\n  OK   const = 1024 >> 10                                             ==                    1\n  OK   const = 0xFF00 >> 8                                            ==                  255\n\n[const >>] zero value\n  OK   const = 0 >> 0                                                 ==                    0\n  OK   const = 0 >> 1                                                 ==                    0\n  OK   const = 0 >> -1                                                ==                    0\n\n[const >>] negative shift\n  OK   const = 1 >> -1                                                ==                    2\n  OK   const = 1 >> -2                                                ==                    4\n  OK   const = 1 >> -10                                               ==                 1024\n  OK   const = 3 >> -4                                                ==                   48\n\n[const >>] negative shift (large)\n  OK   const = 1 >> -32                                               ==           4294967296\n  OK   const = 1 >> -100                                              ==                    0\n\n[const >>] 32-bit range (valid in 64-bit)\n  OK   const = 4294967296 >> 31                                       ==                    2\n  OK   const = 4294967296 >> 32                                       ==                    1\n\n[const >>] boundary 33/63/64/65\n  OK   const = 4294967296 >> 33                                       ==                    0\n  OK   const = 8589934592 >> 31                                       ==                    4\n  OK   const = 8589934592 >> 32                                       ==                    2\n  OK   const = 8589934592 >> 33                                       ==                    1\n  OK   const = -1 >> 31                                               ==                   -1\n  OK   const = -1 >> 32                                               ==                   -1\n  OK   const = -1 >> 33                                               ==                   -1\n  OK   const = -1 >> 63                                               ==                   -1\n  OK   const = -1 >> 64                                               ==                   -1\n  OK   const = -1 >> 65                                               ==                   -1\n  OK   const = 1 >> -31                                               ==           2147483648\n  OK   const = 1 >> -33                                               ==           8589934592\n  OK   const = 1 >> -63                                               == -9223372036854775808\n  OK   const = 1 >> -64                                               ==                    0\n  OK   const = 1 >> -65                                               ==                    0\n\n[const >>>] basic\n  OK   const = 8 >>> 0                                                ==                    8\n  OK   const = 8 >>> 1                                                ==                    4\n  OK   const = 8 >>> 2                                                ==                    2\n  OK   const = 8 >>> 3                                                ==                    1\n  OK   const = 8 >>> 4                                                ==                    0\n  OK   const = 0xFF00 >>> 8                                           ==                  255\n\n[const >>>] zero value\n  OK   const = 0 >>> 0                                                ==                    0\n  OK   const = 0 >>> 1                                                ==                    0\n  OK   const = 0 >>> -1                                               ==                    0\n\n[const >>>] negative shift\n  OK   const = 1 >>> -1                                               ==                    2\n  OK   const = 1 >>> -2                                               ==                    4\n  OK   const = 1 >>> -10                                              ==                 1024\n\n[const >>>] negative shift (large)\n  OK   const = 1 >>> -32                                              ==           4294967296\n  OK   const = 1 >>> -100                                             ==                    0\n\n[const >>>] 32-bit range (valid in 64-bit)\n  OK   const = 4294967296 >>> 31                                      ==                    2\n  OK   const = 4294967296 >>> 32                                      ==                    1\n  OK   const = -1 >>> 1                                               ==  9223372036854775807\n\n[const >>>] boundary 33/63/64/65\n  OK   const = 4294967296 >>> 33                                      ==                    0\n  OK   const = 8589934592 >>> 31                                      ==                    4\n  OK   const = 8589934592 >>> 32                                      ==                    2\n  OK   const = 8589934592 >>> 33                                      ==                    1\n  OK   const = -1 >>> 31                                              ==           8589934591\n  OK   const = -1 >>> 32                                              ==           4294967295\n  OK   const = -1 >>> 33                                              ==           2147483647\n  OK   const = -1 >>> 63                                              ==                    1\n  OK   const = -1 >>> 64                                              ==                    0\n  OK   const = -1 >>> 65                                              ==                    0\n  OK   const = 1 >>> -31                                              ==           2147483648\n  OK   const = 1 >>> -33                                              ==           8589934592\n  OK   const = 1 >>> -63                                              == -9223372036854775808\n  OK   const = 1 >>> -64                                              ==                    0\n  OK   const = 1 >>> -65                                              ==                    0\n\n[const cross] basic identities\n  OK   const = (1 << 10) >> 10                                        ==                    1\n  OK   const = (42 << 5) >> 5                                         ==                   42\n\n=== Results: 444/444 passed\n ===\n"
  },
  {
    "path": "testData/exec/test_stale_stkbase.nut",
    "content": "// Test: stack reallocation during native constructor leaves stale _stkbase\n// Bug: In _OP_CALL for OT_CLASS with native constructor (OT_NATIVECLOSURE),\n// CallNative -> EnterFrame may resize the stack, but there is no RELOAD_STK\n// after CallNative returns. Subsequent instructions use stale _stkbase pointer.\n//\n// Location: sqvm.cpp, _OP_CALL, case OT_CLASS, case OT_NATIVECLOSURE (~line 1110-1116)\n\nlet {regexp} = require(\"string\")\n\n// Recursive function that creates regexp instances at each depth.\n// At some depth, the regexp constructor's CallNative->EnterFrame triggers\n// a stack reallocation. The missing RELOAD_STK means the next instruction\n// after _OP_CALL uses a stale _stkbase (use-after-free).\nfunction test(n) {\n  if (n <= 0)\n    return 0\n\n  // _OP_CALL for regexp(\".\") goes through:\n  //   OT_CLASS -> CreateClassInstance -> CallNative(ctor) -> EnterFrame -> resize!\n  //   break  (NO RELOAD_STK!)\n  // Next instruction reads from stale _stkbase\n  local r = regexp(\".\")\n  local v = test(n - 1)\n  return v\n}\n\ntest(500)\nprint(\"done\\n\")\n"
  },
  {
    "path": "testData/exec/test_stale_stkbase.out",
    "content": "done\n"
  },
  {
    "path": "testData/exec/tostring_recursion.nut",
    "content": "// Demonstrates SQVM::ToString -> CallMetaMethod -> Call recursion (1.6)\n//\n// ToString() checks for MT_TOSTRING metamethod on instance's class.\n// If found, it calls CallMetaMethod() -> Call() -> Execute().\n// If the _tostring body does string concatenation on 'this',\n// StringCat calls ToString(this) again -> infinite recursion.\n//\n// Call chain:\n//   \"\" + obj\n//   -> StringCat(str, obj)\n//     -> ToString(obj)\n//       -> GetMetaMethod(MT_TOSTRING) -> found _tostring\n//       -> CallMetaMethod(_tostring, 1, res)\n//         -> Call(_tostring closure)\n//           -> Execute()\n//             -> \"obj\" + this   (inside _tostring body)\n//             -> StringCat(\"obj\", this)\n//               -> ToString(this)   <-- re-enters!\n//                 -> CallMetaMethod again -> ...\n\nlocal depth = 0\n\nclass Recursive {\n  function _tostring() {\n    depth++\n    // This concatenation calls StringCat -> ToString(this) -> _tostring again\n    return \"obj\" + this\n  }\n}\n\nlocal obj = Recursive()\n\ntry {\n  let s = \"\" + obj\n  print(s)\n} catch(e) {\n  println($\"Caught after depth={depth}: {e}\")\n}\n"
  },
  {
    "path": "testData/exec/tostring_recursion.out",
    "content": "Caught after depth=99: Native stack overflow\n"
  },
  {
    "path": "testData/exec/type_classes/test_builtin_constructors.nut",
    "content": "from \"types\" import *\n\nfunction format_array(arr) {\n  let s = \", \".join(arr)\n  return $\"[{s}]\"\n}\n\nfunction format_table(tbl) {\n  let s = \", \".join(tbl.topairs().map(@(e) $\"[{e[0]}]={e[1]}\"))\n  return $\"\\{{s}\\}\"\n}\n\nprintln(\"Integer():\", Integer())\nprintln(\"Integer(42):\", Integer(42))\nprintln(\"Integer(3.14):\", Integer(3.14))\nprintln(\"Integer(\\\"100\\\"):\", Integer(\"100\"))\nprintln(\"Integer(true):\", Integer(true))\n\nprintln()\n\nprintln(\"Float():\", Float())\nprintln(\"Float(42):\", Float(42))\nprintln(\"Float(3.14):\", Float(3.14))\nprintln(\"Float(\\\"3.14\\\"):\", Float(\"3.14\"))\nprintln(\"Float(true):\", Float(true))\n\nprintln()\n\nprintln(\"Bool():\", Bool())\nprintln(\"Bool(0):\", Bool(0))\nprintln(\"Bool(1):\", Bool(1))\nprintln(\"Bool(3.14):\", Bool(3.14))\nprintln(\"Bool(null):\", Bool(null))\nprintln(\"Bool(\\\"hello\\\"):\", Bool(\"hello\"))\nprintln(\"Bool(\\\"\\\"):\", Bool(\"\"))\n\nprintln()\n\nprintln(\"String(42):\", String(42))\nprintln(\"String(3.14):\", String(3.14))\nprintln(\"String(true):\", String(true))\nprintln(\"String(null):\", String(null))\n\nprintln()\n\nlet arr1 = Array(0)\nprintln(\"Array(0):\", format_array(arr1))\nlet arr2 = Array(5)\nprintln(\"Array(5):\", format_array(arr2))\nlet arr3 = Array(3, \"hello\")\nprintln(\"Array(3, \\\"hello\\\"):\", format_array(arr3))\n\nprintln()\nlet tbl = Table()\nprintln(\"Table():\", format_table(tbl))\ntbl.x <- 10\ntbl.y <- 20\nprintln(\"After adding keys:\", format_table(tbl))\n\nprintln()\nprintln(\"Null():\", Null())\n\nprintln()\nlet obj = {foo = \"bar\"}\nlet wr = WeakRef(obj)\nprintln(\"type(WeakRef(obj)):\", type(wr))\nprintln(\"wr.ref():\", format_table(wr.ref()))\n\nprintln()\nlet x = Integer(\"42\")\nprintln(\"x = Integer(\\\"42\\\"):\", x, \"type:\", typeof(x))\nprintln(\"x instanceof Integer:\", x instanceof Integer)\n"
  },
  {
    "path": "testData/exec/type_classes/test_builtin_constructors.out",
    "content": "Integer(): 0\nInteger(42): 42\nInteger(3.14): 3\nInteger(\"100\"): 100\nInteger(true): 1\n\nFloat(): 0\nFloat(42): 42\nFloat(3.14): 3.14\nFloat(\"3.14\"): 3.14\nFloat(true): 1\n\nBool(): false\nBool(0): false\nBool(1): true\nBool(3.14): true\nBool(null): false\nBool(\"hello\"): true\nBool(\"\"): true\n\nString(42): 42\nString(3.14): 3.14\nString(true): true\nString(null): null\n\nArray(0): []\nArray(5): [null, null, null, null, null]\nArray(3, \"hello\"): [hello, hello, hello]\n\nTable(): {}\nAfter adding keys: {[y]=20, [x]=10}\n\nNull(): null\n\ntype(WeakRef(obj)): weakref\nwr.ref(): {[foo]=bar}\n\nx = Integer(\"42\"): 42 type: integer\nx instanceof Integer: true\n"
  },
  {
    "path": "testData/exec/type_classes/test_inheritance_error.nut",
    "content": "from \"types\" import *\n\ntry {\n    class MyInt(Integer) {\n        constructor() {}\n    }\n}\ncatch(e) {\n    println(e)\n}\n"
  },
  {
    "path": "testData/exec/type_classes/test_inheritance_error.out",
    "content": "Cannot inherit from built-in type 'integer'\n"
  },
  {
    "path": "testData/exec/type_classes/test_unified_types.nut",
    "content": "from \"types\" import *\n\nprintln(\"\\nTest: instanceof with built-in types\")\nprintln(\"  5 instanceof Integer:\", 5 instanceof Integer)\nprintln(\"  3.14 instanceof Float:\", 3.14 instanceof Float)\nprintln(\"  true instanceof Bool:\", true instanceof Bool)\nprintln(\"  \\\"hello\\\" instanceof String:\", \"hello\" instanceof String)\nprintln(\"  [1,2,3] instanceof Array:\", [1,2,3] instanceof Array)\nprintln(\"  {a=1} instanceof Table:\", {a=1} instanceof Table)\nprintln(\"  null instanceof Null:\", null instanceof Null)\n\nprintln(\"\\nTest: Cross-type checks (should be false)\")\nprintln(\"  5 instanceof String:\", 5 instanceof String)\nprintln(\"  \\\"hello\\\" instanceof Integer:\", \"hello\" instanceof Integer)\n\nprintln(\"\\nTest: classof() function\")\nprintln(\"  classof(5)==Integer:\", classof(5)==Integer)\nprintln(\"  classof(\\\"hi\\\")==String:\", classof(\"hi\")==String)\nprintln(\"  classof(true)==Bool:\", classof(true)==Bool)\nprintln(\"  classof([])==Array:\", classof([])==Array)\n\nprintln(\"\\nTest: Type methods still work\")\nprintln(\"  \\\"hello\\\".len():\", \"hello\".len())\nprintln(\"  [1,2,3].len():\", [1,2,3].len())\n\n"
  },
  {
    "path": "testData/exec/type_classes/test_unified_types.out",
    "content": "\nTest: instanceof with built-in types\n  5 instanceof Integer: true\n  3.14 instanceof Float: true\n  true instanceof Bool: true\n  \"hello\" instanceof String: true\n  [1,2,3] instanceof Array: true\n  {a=1} instanceof Table: true\n  null instanceof Null: true\n\nTest: Cross-type checks (should be false)\n  5 instanceof String: false\n  \"hello\" instanceof Integer: false\n\nTest: classof() function\n  classof(5)==Integer: true\n  classof(\"hi\")==String: true\n  classof(true)==Bool: true\n  classof([])==Array: true\n\nTest: Type methods still work\n  \"hello\".len(): 5\n  [1,2,3].len(): 3\n"
  },
  {
    "path": "testData/exec/type_hints/function_types.nut",
    "content": "function fn_def(x: int, y: float = -100.0): float {\n  return x * y\n}\n\n\nfunction fn(x: int, y: float): float {\n  return x + y\n}\n\nfunction apply(func: function|null, x: int, y: float): float|null {\n  return fn?(x, y)\n}\n\nfunction va(x: bool, ...: string|null) {\n  println(x, vargv[0])\n}\n\nprintln(fn_def(10))\nprintln(apply(fn, 5, 10.25))\nva(true, \"abc\", \"\", null, \"342\")"
  },
  {
    "path": "testData/exec/type_hints/function_types.out",
    "content": "-1000\n15.25\ntrue abc\n"
  },
  {
    "path": "testData/exec/type_hints/var_decl.nut",
    "content": "\nlet i: int = 5\nlet t: table = {a = [1, null], b = \"abc\"}\nlet { a: array|null, b: string|null = \"\" } = t\nlet [v0: int|null = -999, v1: int|null] = a\n\nprintln(i)\nprintln(type(a), b)\nprintln(v0, v1)\n"
  },
  {
    "path": "testData/exec/type_hints/var_decl.out",
    "content": "5\narray abc\n1 null\n"
  },
  {
    "path": "testData/exec/type_inference/test_arithmetic_ok.nut",
    "content": "// EXPECTED: no error - arithmetic on ints produces int\nlocal a: int = 10\nlocal b: int = 20\nlocal c: int = a + b\nlocal d: int = a * b\nlocal e: int = a - b\nlocal f: int = a / b\nlocal g: int = a % b\nreturn [c, d, e, f, g]\n"
  },
  {
    "path": "testData/exec/type_inference/test_arithmetic_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_array_literal_ok.nut",
    "content": "// EXPECTED: no error - array literal assigned to array variable\nlocal x: array = [1, 2, 3]\nlocal y: array|null = null\nlocal z: array|null = [\"a\", \"b\"]\nreturn [x, y, z]\n"
  },
  {
    "path": "testData/exec/type_inference/test_array_literal_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_assignment_chain_ok.nut",
    "content": "let x: int = 234\nlet y = x + 4\nlet z = 120.0 * y\nlet w = z\nlet f: float = w\n"
  },
  {
    "path": "testData/exec/type_inference/test_assignment_chain_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_call_result_ok.nut",
    "content": "// EXPECTED: no error - function return type matches variable type\nfunction sqri(x: int): int {\n    return x * x\n}\nlocal y: int = sqri(5)\nlocal z: int|null = sqri(5)\nlocal w: int|string = sqri(5)\nreturn [y, z, w]\n"
  },
  {
    "path": "testData/exec/type_inference/test_call_result_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_call_union_return_ok.nut",
    "content": "// EXPECTED: no error - fn returns string|int, var accepts string|int|null\nfunction fn(val): string|int {\n    return val ? 42 : \"hello\"\n}\nlocal x: string|int = fn(1)\nlocal y: string|int|null = fn(1)\nreturn [x, y]\n"
  },
  {
    "path": "testData/exec/type_inference/test_call_union_return_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_class_literal_ok.nut",
    "content": "// EXPECTED: no error - class literal assigned to class variable\nlocal x: class = class {\n    a = 1\n    b = 2\n}\nlocal y: class|null = null\nreturn [x, y]\n"
  },
  {
    "path": "testData/exec/type_inference/test_class_literal_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_comparison_ok.nut",
    "content": "// EXPECTED: no error - comparisons produce bool\nlocal a: int = 10\nlocal b: int = 20\nlocal c: bool = a > b\nlocal d: bool = a < b\nlocal e: bool = a == b\nlocal f: bool = a != b\nlocal g: bool = a >= b\nlocal h: bool = a <= b\nlocal MyClass = class { x = 0 }\nlocal obj = MyClass()\nlocal i: bool = obj instanceof MyClass\nlocal j: bool = !c\nreturn [c, d, e, f, g, h, i, j]\n"
  },
  {
    "path": "testData/exec/type_inference/test_comparison_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_assign_ok.nut",
    "content": "// EXPECTED: no error\n// Variable with type annotation reassigned with correct type\nlocal x: int = 42\nx = 100\nx = 1 + 2 * 3\nreturn null\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_assign_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_bitwise_ok.nut",
    "content": "// EXPECTED: no error\n// Bitwise operations always produce int\nlocal a: int = 0xFF\nlocal b: int = 0x0F\nlocal c: int = 0xAA\nlocal d: int = 0x55\nlocal result: int = (a & b) | (c ^ d) << 2\nlocal neg: int = ~a\nlocal shr: int = a >>> 4\nreturn [result, neg, shr]\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_bitwise_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_call_chain_ok.nut",
    "content": "// EXPECTED: no error - chained function calls, final result is float, assigned to float\nfunction to_float(x: int): float {\n    return x.tofloat()\n}\nfunction double_it(x: float): float {\n    return x * 2.0\n}\nlocal result: float = double_it(to_float(42))\nreturn result\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_call_chain_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_deep_nesting_ok.nut",
    "content": "// EXPECTED: no error\n// Deeply nested expression where types work out\n// ((((1 + 2) * 3) > 5) ? \"big\" : \"small\") => string (both branches are string)\nlocal a: int = 1\nlocal b: int = 2\nlocal c: int = 3\nlocal deep_result: string = (((a + b) * c) > 5) ? \"big\" : \"small\"\nreturn deep_result\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_deep_nesting_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_logical_ok.nut",
    "content": "// EXPECTED: no error\n// Logical operators: || returns one of the operands\n// true || false => bool|bool = bool\nlocal x: bool = true || false\nlocal y: int|string = 42 || \"hello\"\nreturn [x, y]\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_logical_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_mixed_arithmetic_ok.nut",
    "content": "// EXPECTED: no error\n// (1 + 2) * 3 => int, typeof \"x\" => string => ternary is int|string\nfunction get_flag(): bool { return true }\nlocal n: int = 10\nlocal x: int|string = get_flag() ? ((1 + 2) * 3 + n) : typeof \"x\"\nreturn null\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_mixed_arithmetic_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_nested_ternary_ok.nut",
    "content": "// EXPECTED: no error - nested ternaries produce int|float|string which fits the declared type\nlocal flag1 = true\nlocal flag2 = false\nlocal x: int|float|string = flag1 ? (flag2 ? 42 : 3.14) : \"hello\"\nreturn x\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_nested_ternary_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_nullcoalesce_ok.nut",
    "content": "// EXPECTED: no error\n// null-coalescing: lhs is int|null, rhs is int\n// result type: int (non-null part of lhs) | int (rhs) = int\nfunction maybe_int(): int|null { return 42 }\nlocal x: int = maybe_int() ?? 0\nreturn null\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_nullcoalesce_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_pure_chain_ok.nut",
    "content": "// EXPECTED: no error\n// Pure function results used correctly\nconst function [pure] sqri(x: int): int {\n    return x * x\n}\nconst function [pure] sqrf(x: float): float {\n    return x * x\n}\nfunction fn(val): string|int {\n    return val ? sqri(val) : \"error\"\n}\n\nlocal a: int = sqri(5)\nlocal b: float = sqrf(3.14)\nlocal c: string|int = fn(42)\nlocal d: string|int|null|function = fn(100)\nreturn [a, b, c, d]\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_pure_chain_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_return_expr_ok.nut",
    "content": "// EXPECTED: no error\n// Complex return expression: all branches produce int\nfunction compute(flag: bool, x: int, y: int): int {\n    return flag ? x * y + 1 : x - y\n}\nreturn compute\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_return_expr_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_complex_table_ternary_ok.nut",
    "content": "// EXPECTED: no error\n// Ternary produces table|array, declared as table|array\nfunction get_data(flag: bool): table|array {\n    return flag ? { x = 1 } : [1, 2, 3]\n}\nreturn get_data\n"
  },
  {
    "path": "testData/exec/type_inference/test_complex_table_ternary_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_const_array4_ok.nut",
    "content": "const ARR1 = [1, null]\nconst ARR2 = [4, 3]\n\nfunction fn(x: table|array|int = true ? ARR1 : {}): null {}\n\nreturn fn({})"
  },
  {
    "path": "testData/exec/type_inference/test_const_array4_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_const_array_ok.nut",
    "content": "const ARR1 = [1, null]\nconst ARR2 = [4, 3]\nlet x: array = true ? ARR1 : ARR2\nreturn x"
  },
  {
    "path": "testData/exec/type_inference/test_const_array_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_const_function_ok.nut",
    "content": "const function fn1() {}\nconst function fn2() {}\nlet x: function = true ? fn1 : fn2\nreturn x"
  },
  {
    "path": "testData/exec/type_inference/test_const_function_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_const_inline_ok.nut",
    "content": "// EXPECTED: no error - const values match declared types\nconst MY_INT = 42\nconst MY_STR = \"hello\"\nconst MY_FLOAT = 3.14\nconst MY_BOOL = true\n\nlocal a: int = MY_INT\nlocal b: string = MY_STR\nlocal c: float = MY_FLOAT\nlocal d: bool = MY_BOOL\nlocal e: int|string = MY_INT\nlocal f: int|string = MY_STR\nreturn [a, b, c, d, e, f]\n"
  },
  {
    "path": "testData/exec/type_inference/test_const_inline_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_const_table_ok.nut",
    "content": "const TAB1 = {}\nconst TAB2 = {x = 4}\nlet x: table = true ? TAB1 : TAB2\nreturn x"
  },
  {
    "path": "testData/exec/type_inference/test_const_table_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_destructure_array_default_ok.nut",
    "content": "// EXPECTED: no error - default values match declared types\nlet [a: int = 10, b: string = \"default\", c: bool = true] = [1, \"actual\", false]\nreturn [a, b, c]\n"
  },
  {
    "path": "testData/exec/type_inference/test_destructure_array_default_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_destructure_array_ok.nut",
    "content": "// EXPECTED: no error - destructured values with defaults match declared types\nlet [x: int = 4, y: float = 6.0] = [100, 200.4]\nreturn [x, y]\n"
  },
  {
    "path": "testData/exec/type_inference/test_destructure_array_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_destructure_from_function_ok.nut",
    "content": "// EXPECTED: no error - destructuring from function result (runtime check only)\nfunction make_pair(): table {\n    return {x = 10, y = 20}\n}\nlet {x: int, y: int} = make_pair()\nreturn [x, y]\n"
  },
  {
    "path": "testData/exec/type_inference/test_destructure_from_function_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_destructure_nested_ok.nut",
    "content": "// EXPECTED: no error - nested destructuring with types\nlet {config} = {config = {width = 800, height = 600}}\nlet {width: int, height: int} = config\nreturn [width, height]\n"
  },
  {
    "path": "testData/exec/type_inference/test_destructure_nested_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_destructure_table_ok.nut",
    "content": "// EXPECTED: no error - destructured values match declared types\nlet {x: int, y: string} = {x = 42, y = \"hello\"}\nlet {a: int|null, b: float} = {a = null, b = 3.14}\nreturn [x, y, a, b]\n"
  },
  {
    "path": "testData/exec/type_inference/test_destructure_table_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_freeze_ok.nut",
    "content": "// EXPECTED: no error - freeze() preserves type of its argument\nlocal a: table = freeze({x = 1})\nlocal b: array = freeze([1, 2, 3])\nreturn [a, b]\n"
  },
  {
    "path": "testData/exec/type_inference/test_freeze_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_function_literal_ok.nut",
    "content": "// EXPECTED: no error - lambda assigned to function variable\nlocal x: function = @() 42\nlocal y: function|null = null\nlocal z: function|null = @(a, b) a + b\nreturn [x, y, z]\n"
  },
  {
    "path": "testData/exec/type_inference/test_function_literal_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_instance_from_class_ok.nut",
    "content": "// EXPECTED: no error - class() produces instance, assigned to instance\n// Note: calling a class produces an instance, but inferring this\n// requires knowing the callee is a class, which may be ~0u (unknown)\n// in early implementation. This test documents the desired behavior.\nlocal MyClass = class {\n    x = 0\n    constructor() {}\n}\nlocal obj: instance = MyClass()\nlocal obj2: instance|null = null\nreturn [obj, obj2]\n"
  },
  {
    "path": "testData/exec/type_inference/test_instance_from_class_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_literal_ok.nut",
    "content": "// EXPECTED: no error - all types match\nlocal a: int = 42\nlocal b: float = 3.14\nlocal c: string = \"hello\"\nlocal d: bool = true\nlocal e: int|null = null\nlocal f: int|string = 42\nlocal g: int|string = \"world\"\nlocal h: null = null\nreturn [a, b, c, d, e, f, g, h]\n"
  },
  {
    "path": "testData/exec/type_inference/test_literal_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_return_literal_ok.nut",
    "content": "// EXPECTED: no error - return type matches\nfunction fn(): int {\n    return 42\n}\nfunction fn2(): string {\n    return \"hello\"\n}\nfunction fn3(): int|string {\n    return 42\n}\nfunction fn4(): int|string {\n    return \"hello\"\n}\nreturn [fn(), fn2(), fn3(), fn4()]\n"
  },
  {
    "path": "testData/exec/type_inference/test_return_literal_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_string_concat_ok.nut",
    "content": "// EXPECTED: no error - string + anything produces string\nlocal s: string = \"hello\"\nlocal n: int = 42\nlocal result: string = s + n\nlocal result2: string = s + \" world\"\nreturn [result, result2]\n"
  },
  {
    "path": "testData/exec/type_inference/test_string_concat_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_table_literal_ok.nut",
    "content": "// EXPECTED: no error - table literal assigned to table variable\nlocal x: table = { a = 1, b = 2, c = \"hello\" }\nlocal y: table|null = null\nlocal z: table|null = { key = \"value\" }\nreturn [x, y, z]\n"
  },
  {
    "path": "testData/exec/type_inference/test_table_literal_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_table_return_ok.nut",
    "content": "// EXPECTED: no error\nfunction make_table(): table {\n    return { a = 1, b = 2 }\n}\nfunction make_array(): array {\n    return [1, 2, 3]\n}\nfunction make_either(flag: bool): table|array {\n    return flag ? { a = 1 } : [1, 2]\n}\nreturn [make_table(), make_array(), make_either(true)]\n"
  },
  {
    "path": "testData/exec/type_inference/test_table_return_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_ternary_ok.nut",
    "content": "// EXPECTED: no error - ternary produces int|int = int\nlocal flag = true\nlocal x: int = flag ? 42 : 100\nreturn null\n"
  },
  {
    "path": "testData/exec/type_inference/test_ternary_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/type_inference/test_typeof_ok.nut",
    "content": "// EXPECTED: no error - typeof always returns string\nlocal x: string = typeof 42\nlocal y: string = typeof \"hello\"\nlocal z: string = typeof null\nreturn [x, y, z]\n"
  },
  {
    "path": "testData/exec/type_inference/test_typeof_ok.out",
    "content": ""
  },
  {
    "path": "testData/exec/valid_syntax/arrays.nut",
    "content": "// Valid syntax: Arrays\n\n// Empty array\nlet empty = []\nassert(empty.len() == 0)\n\n// Array with values\nlet arr = [1, 2, 3, 4, 5]\nassert(arr.len() == 5)\nassert(arr[0] == 1)\nassert(arr[4] == 5)\n\n// Mixed types\nlet mixed = [1, \"hello\", 3.14, null, true, [1, 2], {a = 1}]\nassert(mixed.len() == 7)\nassert(typeof mixed[0] == \"integer\")\nassert(typeof mixed[1] == \"string\")\nassert(typeof mixed[5] == \"array\")\nassert(typeof mixed[6] == \"table\")\n\n// Nested arrays\nlet nested = [[1, 2], [3, 4], [5, 6]]\nassert(nested[0][0] == 1)\nassert(nested[2][1] == 6)\n\n// Array methods - append\nlocal a = [1, 2, 3]\na.append(4)\nassert(a.len() == 4)\nassert(a[3] == 4)\n\n// Multiple append\na.append(5, 6)\nassert(a.len() == 6)\n\n// extend\nlocal b = [1, 2]\nb.extend([3, 4])\nassert(b.len() == 4)\n\n// pop\nlet popped = b.pop()\nassert(popped == 4)\nassert(b.len() == 3)\n\n// top\nassert(b.top() == 3)\n\n// insert\nb.insert(0, 99)\nassert(b[0] == 99)\n\n// remove\nlet removed = b.remove(0)\nassert(removed == 99)\n\n// resize\nlocal resizable = [1, 2, 3]\nresizable.resize(5, 0)\nassert(resizable.len() == 5)\nassert(resizable[3] == 0)\n\n// sort\nlocal sortable = [3, 1, 4, 1, 5, 9, 2, 6]\nsortable.sort()\nassert(sortable[0] == 1)\nassert(sortable[sortable.len() - 1] == 9)\n\n// sort with custom comparator\nlocal desc = [3, 1, 4, 1, 5]\ndesc.sort(@(a, b) b <=> a)\nassert(desc[0] == 5)\nassert(desc[desc.len() - 1] == 1)\n\n// reverse\nlocal rev = [1, 2, 3]\nrev.reverse()\nassert(rev[0] == 3)\nassert(rev[2] == 1)\n\n// slice\nlet sliced = [1, 2, 3, 4, 5].slice(1, 4)\nassert(sliced.len() == 3)\nassert(sliced[0] == 2)\nassert(sliced[2] == 4)\n\n// slice with default end\nlet sliced2 = [1, 2, 3, 4, 5].slice(2)\nassert(sliced2.len() == 3)\nassert(sliced2[0] == 3)\n\n// filter\nlet evens = [1, 2, 3, 4, 5, 6].filter(@(v) v % 2 == 0)\nassert(evens.len() == 3)\nassert(evens[0] == 2)\n\n// map\nlet doubled = [1, 2, 3].map(@(v) v * 2)\nassert(doubled[0] == 2)\nassert(doubled[1] == 4)\nassert(doubled[2] == 6)\n\n// reduce\nlet sum = [1, 2, 3, 4, 5].reduce(@(acc, v) acc + v, 0)\nassert(sum == 15)\n\n// each\nlocal each_sum = 0\nlet _ = [1, 2, 3].each(@(v) each_sum += v)\nassert(each_sum == 6)\n\n// findindex\nlet found = [10, 20, 30, 40].findindex(@(v) v > 25)\nassert(found == 2)\n\n// findvalue\nlet fval = [10, 20, 30, 40].findvalue(@(v) v > 25)\nassert(fval == 30)\n\n// indexof\nlet idx = [10, 20, 30].indexof(20)\nassert(idx == 1)\n\n// contains\nassert([1, 2, 3].contains(2))\nassert(![1, 2, 3].contains(4))\n\n// clone\nlet orig = [1, 2, 3]\nlet copy = clone orig\ncopy[0] = 99\nassert(orig[0] == 1)\n\n// clear\nlocal clearable = [1, 2, 3]\nclearable.clear()\nassert(clearable.len() == 0)\n\n// swap\nlocal swappable = [1, 2, 3]\nswappable.swap(0, 2)\nassert(swappable[0] == 3)\nassert(swappable[2] == 1)\n\n// hasindex\nassert([1, 2, 3].hasindex(0))\nassert([1, 2, 3].hasindex(2))\nassert(![1, 2, 3].hasindex(3))\n\n// apply (modify in-place)\nlocal applyable = [1, 2, 3]\napplyable.apply(@(v) v * 10)\nassert(applyable[0] == 10)\nassert(applyable[1] == 20)\n\n// Iteration\nlocal iter_sum = 0\nforeach (v in [10, 20, 30]) {\n    iter_sum += v\n}\nassert(iter_sum == 60)\n\n// Iteration with index\nlocal indices = []\nforeach (i, v in [\"a\", \"b\", \"c\"]) {\n    indices.append(i)\n}\nassert(indices[0] == 0)\nassert(indices[2] == 2)\n\nprint(\"arrays: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/arrays.out",
    "content": "arrays: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/classes.nut",
    "content": "// Valid syntax: Classes and inheritance\n\n// Basic class\nclass Point {\n    x = 0\n    y = 0\n}\n\nlet p = Point()\nassert(p.x == 0)\nassert(p.y == 0)\np.x = 10\np.y = 20\nassert(p.x == 10)\n\n// Class with constructor\nclass Point2 {\n    x = 0\n    y = 0\n    constructor(x, y) {\n        this.x = x\n        this.y = y\n    }\n}\n\nlet p2 = Point2(3, 4)\nassert(p2.x == 3)\nassert(p2.y == 4)\n\n// Class with methods\nclass Circle {\n    r = 0\n    constructor(r) { this.r = r }\n    function area() {\n        return 3.14159 * this.r * this.r\n    }\n    function perimeter() {\n        return 2.0 * 3.14159 * this.r\n    }\n}\n\nlet c = Circle(5)\nassert(c.r == 5)\n\n// Class with static members\nclass Config {\n    static VERSION = \"1.0\"\n    static COUNT = 0\n}\nassert(Config.VERSION == \"1.0\")\n\n// Inheritance using parenthesis syntax\nclass Shape {\n    function area() { return 0 }\n    function name() { return \"shape\" }\n}\n\nclass Rect(Shape) {\n    w = 0\n    h = 0\n    constructor(w, h) {\n        this.w = w\n        this.h = h\n    }\n    function area() {\n        return this.w * this.h\n    }\n    function name() { return \"rect\" }\n}\n\nlet r = Rect(3, 4)\nassert(r.area() == 12)\nassert(r.name() == \"rect\")\nassert(r instanceof Rect)\nassert(r instanceof Shape)\n\n// Inheritance with base call\nclass Base {\n    value = 0\n    constructor(v = 0) { this.value = v }\n    function get() { return this.value }\n}\n\nclass Derived(Base) {\n    extra = 0\n    constructor(v, e) {\n        base.constructor(v)\n        this.extra = e\n    }\n    function get() {\n        return base.get() + this.extra\n    }\n}\n\nlet d = Derived(10, 5)\nassert(d.get() == 15)\nassert(d.value == 10)\nassert(d.extra == 5)\n\n// getclass and getbase\nassert(d.getclass() == Derived)\nassert(Derived.getbase() == Base)\n\n// Class as expression\nlet MyClass = class {\n    value = 42\n    function get() { return this.value }\n}\nlet mc = MyClass()\nassert(mc.get() == 42)\n\n// Class with metamethods - use getclass() for self-reference\nclass Vector {\n    x = 0\n    y = 0\n    constructor(x, y) {\n        this.x = x\n        this.y = y\n    }\n    function _add(other) {\n        return this.getclass()(this.x + other.x, this.y + other.y)\n    }\n    function _sub(other) {\n        return this.getclass()(this.x - other.x, this.y - other.y)\n    }\n    function _cmp(other) {\n        let d1 = this.x * this.x + this.y * this.y\n        let d2 = other.x * other.x + other.y * other.y\n        if (d1 < d2) return -1\n        if (d1 > d2) return 1\n        return 0\n    }\n    function _tostring() {\n        return $\"Vector({this.x}, {this.y})\"\n    }\n    function _typeof() {\n        return \"Vector\"\n    }\n}\n\nlet v1 = Vector(1, 2)\nlet v2 = Vector(3, 4)\nlet v3 = v1 + v2\nassert(v3.x == 4)\nassert(v3.y == 6)\n\nlet v4 = v2 - v1\nassert(v4.x == 2)\nassert(v4.y == 2)\n\nassert(typeof v1 == \"Vector\")\nassert(v1 < v2)\nassert(!(v2 < v1))\n\n// Class modification before instantiation\nclass Modifiable {\n    x = 1\n}\nModifiable.y <- 2\nlet mod_inst = Modifiable()\nassert(mod_inst.x == 1)\nassert(mod_inst.y == 2)\n\n// Constructor with default params\nclass WithDefaults {\n    x = 0\n    y = 0\n    constructor(x = 10, y = 20) {\n        this.x = x\n        this.y = y\n    }\n}\nlet wd1 = WithDefaults()\nassert(wd1.x == 10)\nassert(wd1.y == 20)\nlet wd2 = WithDefaults(1, 2)\nassert(wd2.x == 1)\nassert(wd2.y == 2)\n\n// Multiple inheritance levels\nclass A { function who() { return \"A\" } }\nclass B(A) { function who() { return \"B\" } }\nclass C(B) { function who() { return \"C\" } }\n\nlet obj_c = C()\nassert(obj_c.who() == \"C\")\nassert(obj_c instanceof A)\nassert(obj_c instanceof B)\nassert(obj_c instanceof C)\n\n// rawin/rawget/rawset on instances\nlet inst = Point2(1, 2)\nassert(inst.rawin(\"x\"))\nassert(inst.rawget(\"x\") == 1)\ninst.rawset(\"x\", 99)\nassert(inst.x == 99)\n\nprint(\"classes: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/classes.out",
    "content": "classes: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/closures_scope.nut",
    "content": "// Valid syntax: Closures and scoping\n\n// Basic closure\nlocal outer_val = 10\nlet closure = function() {\n    return outer_val\n}\nassert(closure() == 10)\n\n// Closure captures by reference\nouter_val = 20\nassert(closure() == 20)\n\n// Nested closures\nfunction make_multiplier(factor) {\n    return function(x) {\n        return x * factor\n    }\n}\nlet double_fn = make_multiplier(2)\nlet triple_fn = make_multiplier(3)\nassert(double_fn(5) == 10)\nassert(triple_fn(5) == 15)\n\n// Closure over loop variable\nlocal fns = []\nfor (local i = 0; i < 5; i++) {\n    let captured_i = i // capture by value\n    fns.append(@() captured_i)\n}\nassert(fns[0]() == 0)\nassert(fns[4]() == 4)\n\n// Nested function accessing outer scope\nfunction outer() {\n    local x = 100\n    function inner() {\n        return x + 1\n    }\n    return inner()\n}\nassert(outer() == 101)\n\n// Deep nesting\nfunction level1() {\n    local a_val = 1\n    function level2() {\n        local b_val = 2\n        function level3() {\n            return a_val + b_val\n        }\n        return level3()\n    }\n    return level2()\n}\nassert(level1() == 3)\n\n// Function returning table of closures\nfunction make_stack() {\n    local data = []\n    return {\n        function push(v) { data.append(v) }\n        function pop() { return data.pop() }\n        function size() { return data.len() }\n        function peek() { return data.top() }\n    }\n}\n\nlet stack = make_stack()\nstack.push(1)\nstack.push(2)\nstack.push(3)\nassert(stack.size() == 3)\nassert(stack.peek() == 3)\nassert(stack.pop() == 3)\nassert(stack.size() == 2)\n\n// IIFE (Immediately Invoked Function Expression)\nlet iife_result = (function() {\n    return 42\n})()\nassert(iife_result == 42)\n\n// Lambda IIFE\nlet lambda_iife = (@() 99)()\nassert(lambda_iife == 99)\n\n// Block scope isolation\n{\n    local scoped = 42\n    assert(scoped == 42)\n}\n\n// Multiple blocks\n{\n    local a_block = 1\n    {\n        local b_block = 2\n        assert(a_block == 1)\n        assert(b_block == 2)\n    }\n}\n\nprint(\"closures_scope: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/closures_scope.out",
    "content": "closures_scope: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/control_flow.nut",
    "content": "// Valid syntax: Control flow statements\n\n// if/else\nlocal result = null\nif (true)\n    result = \"yes\"\nassert(result == \"yes\")\n\nif (false)\n    result = \"no\"\nelse\n    result = \"else\"\nassert(result == \"else\")\n\n// if/else if/else chain\nlocal val = 2\nif (val == 1)\n    result = \"one\"\nelse if (val == 2)\n    result = \"two\"\nelse if (val == 3)\n    result = \"three\"\nelse\n    result = \"other\"\nassert(result == \"two\")\n\n// if with block\nif (true) {\n    result = \"block\"\n}\nassert(result == \"block\")\n\n// if with local declaration in condition\nif (local cond_val = 42) {\n    assert(cond_val == 42)\n}\n\n// while loop\nlocal count = 0\nwhile (count < 5) {\n    count++\n}\nassert(count == 5)\n\n// do/while loop\nlocal dw_count = 0\ndo {\n    dw_count++\n} while (dw_count < 3)\nassert(dw_count == 3)\n\n// do/while executes at least once\nlocal dw_once = 0\ndo {\n    dw_once++\n} while (false)\nassert(dw_once == 1)\n\n// for loop\nlocal sum = 0\nfor (local i = 0; i < 5; i++) {\n    sum += i\n}\nassert(sum == 10)\n\n// for loop with empty parts\nlocal inf_count = 0\nfor (;;) {\n    inf_count++\n    if (inf_count >= 3) break\n}\nassert(inf_count == 3)\n\n// foreach with array\nlet arr = [10, 20, 30]\nlocal arr_sum = 0\nforeach (v in arr) {\n    arr_sum += v\n}\nassert(arr_sum == 60)\n\n// foreach with index and value\nlocal idx_sum = 0\nforeach (i, v in arr) {\n    idx_sum += i\n}\nassert(idx_sum == 3) // 0+1+2\n\n// foreach with table\nlet tbl = {a = 1, b = 2, c = 3}\nlocal tbl_sum = 0\nforeach (k, v in tbl) {\n    tbl_sum += v\n}\nassert(tbl_sum == 6)\n\n// foreach with string\nlocal char_count = 0\nforeach (ch in \"hello\") {\n    char_count++\n}\nassert(char_count == 5)\n\n// break in loop\nlocal break_val = 0\nfor (local i = 0; i < 100; i++) {\n    if (i == 5) break\n    break_val = i\n}\nassert(break_val == 4)\n\n// continue in loop\nlocal cont_sum = 0\nfor (local i = 0; i < 10; i++) {\n    if (i % 2 == 0) continue\n    cont_sum += i\n}\nassert(cont_sum == 25) // 1+3+5+7+9\n\n// break in while\nlocal bw = 0\nwhile (true) {\n    bw++\n    if (bw >= 3) break\n}\nassert(bw == 3)\n\n// continue in while\nlocal cw = 0\nlocal cw_sum = 0\nwhile (cw < 10) {\n    cw++\n    if (cw % 2 == 0) continue\n    cw_sum += cw\n}\nassert(cw_sum == 25)\n\n// break in foreach\nlocal bf_last = 0\nforeach (i, v in [10, 20, 30, 40, 50]) {\n    if (v == 30) break\n    bf_last = v\n}\nassert(bf_last == 20)\n\n// Nested loops with break\nlocal nested_count = 0\nfor (local i = 0; i < 5; i++) {\n    for (local j = 0; j < 5; j++) {\n        if (j == 2) break\n        nested_count++\n    }\n}\nassert(nested_count == 10)\n\n// switch statement\n#allow-switch-statement\nlocal sw_val = 2\nlocal sw_result = null\nswitch (sw_val) {\n    case 1:\n        sw_result = \"one\"\n        break\n    case 2:\n        sw_result = \"two\"\n        break\n    case 3:\n        sw_result = \"three\"\n        break\n    default:\n        sw_result = \"default\"\n        break\n}\nassert(sw_result == \"two\")\n\n// switch with default\nsw_val = 99\nswitch (sw_val) {\n    case 1:\n        sw_result = \"one\"\n        break\n    default:\n        sw_result = \"default\"\n        break\n}\nassert(sw_result == \"default\")\n\nprint(\"control_flow: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/control_flow.out",
    "content": "control_flow: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/destructuring.nut",
    "content": "// Valid syntax: Destructuring\n\n// Array destructuring\nlet [a, b, c] = [10, 20, 30]\nassert(a == 10)\nassert(b == 20)\nassert(c == 30)\n\n// Table/object destructuring\nlet {x, y} = {x = 100, y = 200}\nassert(x == 100)\nassert(y == 200)\n\n// Destructuring with default values\nlet {p = 1, q = 2} = {p = 10}\nassert(p == 10)\nassert(q == 2)\n\n// Destructuring in function parameters - table\nfunction process_point({x, y}) {\n    return x + y\n}\nassert(process_point({x = 3, y = 4}) == 7)\n\n// Destructuring in function parameters - array\nfunction process_pair([a, b]) {\n    return a * b\n}\nassert(process_pair([3, 4]) == 12)\n\n// Destructuring with type annotations\nlet {m: int, n: int} = {m = 5, n = 10}\nassert(m == 5)\nassert(n == 10)\n\n// Function parameter destructuring with defaults\nfunction with_defaults({name = \"default\", value = 0}) {\n    return $\"{name}={value}\"\n}\nassert(with_defaults({name = \"test\", value = 42}) == \"test=42\")\nassert(with_defaults({}) == \"default=0\")\n\n// Multiple destructurings\nlet {r} = {r = 99}\nassert(r == 99)\n\n// Partial array destructuring\nlet [first, second] = [1, 2, 3, 4, 5]\nassert(first == 1)\nassert(second == 2)\n\n// Table destructuring with multiple fields\nlet {name, age, active} = {name = \"John\", age = 30, active = true}\nassert(name == \"John\")\nassert(age == 30)\nassert(active == true)\n\nprint(\"destructuring: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/destructuring.out",
    "content": "destructuring: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/enums_consts.nut",
    "content": "// Valid syntax: Enums and constants\n\n// Basic enum\nenum Color {\n    RED,\n    GREEN,\n    BLUE\n}\nassert(Color.RED == 0)\nassert(Color.GREEN == 1)\nassert(Color.BLUE == 2)\n\n// Enum with explicit values\nenum HttpCode {\n    OK = 200,\n    NOT_FOUND = 404,\n    ERROR = 500\n}\nassert(HttpCode.OK == 200)\nassert(HttpCode.NOT_FOUND == 404)\n\n// Enum with mixed auto and explicit values\n// Note: auto-increment always starts from 0 for each member without explicit value\nenum Mixed {\n    A,        // 0\n    B = 10,\n    C,        // 1 (resets from 0-based counter)\n    D = 20\n}\nassert(Mixed.A == 0)\nassert(Mixed.B == 10)\nassert(Mixed.C == 1)\nassert(Mixed.D == 20)\n\n// Enum with string values\nenum Names {\n    FIRST = \"first\",\n    SECOND = \"second\"\n}\nassert(Names.FIRST == \"first\")\n\n// Enum with float values\nenum Precision {\n    LOW = 0.1,\n    MEDIUM = 0.01,\n    HIGH = 0.001\n}\n\n// const declaration\nconst MAX_SIZE = 100\nconst PI_APPROX = 3.14159\nconst GREETING = \"hello\"\n\nassert(MAX_SIZE == 100)\nassert(PI_APPROX == 3.14159)\nassert(GREETING == \"hello\")\n\n// Computed const\nconst DOUBLE_MAX = MAX_SIZE * 2\nassert(DOUBLE_MAX == 200)\n\n// global const\nglobal const GLOBAL_VAL = 42\n\n// global enum\nglobal enum Direction {\n    NORTH,\n    SOUTH,\n    EAST,\n    WEST\n}\nassert(Direction.NORTH == 0)\nassert(Direction.WEST == 3)\n\n// Using enum values in expressions\nlet color = Color.RED\nif (color == Color.RED) {\n    assert(true)\n}\n\n// Enum in switch\n#allow-switch-statement\nlocal result = \"\"\nlet status = HttpCode.NOT_FOUND\nswitch (status) {\n    case HttpCode.OK:\n        result = \"ok\"\n        break\n    case HttpCode.NOT_FOUND:\n        result = \"not found\"\n        break\n    case HttpCode.ERROR:\n        result = \"error\"\n        break\n}\nassert(result == \"not found\")\n\nprint(\"enums_consts: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/enums_consts.out",
    "content": "enums_consts: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/error_handling.nut",
    "content": "// Valid syntax: Error handling (try/catch/throw)\n\n// Basic try/catch\nlocal caught = null\ntry {\n    throw \"test error\"\n} catch (e) {\n    caught = e\n}\nassert(caught == \"test error\")\n\n// Catching runtime errors\nlocal rt_caught = false\ntry {\n    let t = {}\n    let _ = t.nonexistent_method()\n} catch (e) {\n    rt_caught = true\n}\nassert(rt_caught)\n\n// Throw integer\nlocal int_err = null\ntry {\n    throw 42\n} catch (e) {\n    int_err = e\n}\nassert(int_err == 42)\n\n// Throw null\nlocal null_err = \"not null\"\ntry {\n    throw null\n} catch (e) {\n    null_err = e\n}\nassert(null_err == null)\n\n// Throw table\nlocal tbl_err = null\ntry {\n    throw {code = 404, message = \"Not found\"}\n} catch (e) {\n    tbl_err = e\n}\nassert(tbl_err.code == 404)\n\n// Nested try/catch\nlocal outer_caught = null\nlocal inner_caught = null\ntry {\n    try {\n        throw \"inner\"\n    } catch (e) {\n        inner_caught = e\n        throw \"outer\"\n    }\n} catch (e) {\n    outer_caught = e\n}\nassert(inner_caught == \"inner\")\nassert(outer_caught == \"outer\")\n\n// Try/catch with no exception\nlocal no_err = true\ntry {\n    let x = 42\n} catch (e) {\n    no_err = false\n}\nassert(no_err)\n\n// Function that may throw\nfunction divide(a, b) {\n    if (b == 0) throw \"division by zero\"\n    return a / b\n}\n\nassert(divide(10, 2) == 5)\n\nlocal div_err = null\ntry {\n    divide(10, 0)\n} catch (e) {\n    div_err = e\n}\nassert(div_err == \"division by zero\")\n\n// Try/catch in loop\nlocal errors_caught = 0\nfor (local i = 0; i < 5; i++) {\n    try {\n        if (i % 2 == 0) throw \"even error\"\n    } catch (e) {\n        errors_caught++\n    }\n}\nassert(errors_caught == 3) // 0, 2, 4\n\n// Rethrow\nlocal rethrown = null\ntry {\n    try {\n        throw \"original\"\n    } catch (e) {\n        throw e // rethrow\n    }\n} catch (e) {\n    rethrown = e\n}\nassert(rethrown == \"original\")\n\nprint(\"error_handling: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/error_handling.out",
    "content": "error_handling: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/functions.nut",
    "content": "// Valid syntax: Functions\n\n// Basic function declaration\nfunction add(a, b) {\n    return a + b\n}\nassert(add(2, 3) == 5)\n\n// local function\nlocal function subtract(a, b) {\n    return a - b\n}\nassert(subtract(10, 3) == 7)\n\n// let function\nlet multiply = function(a, b) {\n    return a * b\n}\nassert(multiply(3, 4) == 12)\n\n// Named function expression\nlet factorial = function factorial(n) {\n    if (n <= 1) return 1\n    return n * factorial(n - 1)\n}\nassert(factorial(5) == 120)\n\n// Lambda expressions\nlet square = @(x) x * x\nassert(square(5) == 25)\n\nlet add_lambda = @(a, b) a + b\nassert(add_lambda(2, 3) == 5)\n\n// Lambda with function wrapper for multi-statement\nlet complex_fn = function(x) {\n    local result = x * 2\n    return result + 1\n}\nassert(complex_fn(5) == 11)\n\n// Default parameters\nfunction greet(name = \"World\") {\n    return \"Hello \" + name\n}\nassert(greet() == \"Hello World\")\nassert(greet(\"Quirrel\") == \"Hello Quirrel\")\n\n// Multiple default parameters\nfunction multi_def(a, b = 10, c = 20) {\n    return a + b + c\n}\nassert(multi_def(1) == 31)\nassert(multi_def(1, 2) == 23)\nassert(multi_def(1, 2, 3) == 6)\n\n// Variable arguments\nfunction sum_all(...) {\n    local total = 0\n    foreach (v in vargv)\n        total += v\n    return total\n}\nassert(sum_all(1, 2, 3, 4, 5) == 15)\nassert(sum_all() == 0)\n\n// Varargs with regular params\nfunction first_and_rest(first, ...) {\n    local rest_sum = 0\n    foreach (v in vargv)\n        rest_sum += v\n    return [first, rest_sum]\n}\nlet far = first_and_rest(10, 20, 30)\nassert(far[0] == 10)\nassert(far[1] == 50)\n\n// Function returning function (closure)\nfunction make_adder(n) {\n    return @(x) x + n\n}\nlet add5 = make_adder(5)\nassert(add5(10) == 15)\nassert(add5(20) == 25)\n\n// Closures capture by reference\nfunction make_counter() {\n    local count = 0\n    return {\n        function inc() { count++ }\n        function get() { return count }\n    }\n}\nlet counter = make_counter()\ncounter.inc()\ncounter.inc()\ncounter.inc()\nassert(counter.get() == 3)\n\n// Return without value\nfunction no_return() {\n    local x = 42\n}\nassert(no_return() == null)\n\n// Explicit return null\nfunction return_null() {\n    return null\n}\nassert(return_null() == null)\n\n// Function as value\nlet fn_array = [\n    @(x) x + 1,\n    @(x) x * 2,\n    @(x) x - 3\n]\nassert(fn_array[0](5) == 6)\nassert(fn_array[1](5) == 10)\nassert(fn_array[2](5) == 2)\n\n// Recursive function\nfunction fib(n) {\n    if (n <= 1) return n\n    return fib(n - 1) + fib(n - 2)\n}\nassert(fib(10) == 55)\n\n// Tail recursion\nfunction tail_sum(n, acc = 0) {\n    if (n <= 0) return acc\n    return tail_sum(n - 1, acc + n)\n}\nassert(tail_sum(100) == 5050)\n\n// Function with type annotations\nfunction typed_add(x: int, y: int): int {\n    return x + y\n}\nassert(typed_add(2, 3) == 5)\n\n// Function with union type annotations\nfunction nullable_fn(x: int|null = null) {\n    return x ?? 0\n}\nassert(nullable_fn() == 0)\nassert(nullable_fn(42) == 42)\n\n// Lambda with default\nlet def_lambda = @(x = 10) x * 2\nassert(def_lambda() == 20)\nassert(def_lambda(5) == 10)\n\n// callee()\nlet self_ref = function() {\n    return callee()\n}\nassert(typeof self_ref() == \"function\")\n\n// Function call/acall\nfunction test_fn(a, b) { return a + b }\nassert(test_fn.call(null, 3, 4) == 7)\nassert(test_fn.acall([null, 3, 4]) == 7)\n\n// bindenv\nlet obj = {name = \"test\"}\nlet bound = function() { return this.name }.bindenv(obj)\nassert(bound() == \"test\")\n\nprint(\"functions: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/functions.out",
    "content": "functions: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/generators.nut",
    "content": "// Valid syntax: Generators and yield\n\n// Basic generator\nfunction count_to(n) {\n    for (local i = 1; i <= n; i++)\n        yield i\n}\n\n// Using resume\nlet gen = count_to(3)\nassert(resume gen == 1)\nassert(resume gen == 2)\nassert(resume gen == 3)\nassert(resume gen == null)\n\n// Generator with foreach\nlocal sum = 0\nforeach (v in count_to(5)) {\n    sum += v\n}\nassert(sum == 15) // 1+2+3+4+5\n\n// Fibonacci generator\nfunction fib_gen(n) {\n    local a = 0, b = 1\n    for (local i = 0; i < n; i++) {\n        yield a\n        let temp = a + b\n        a = b\n        b = temp\n    }\n}\n\nlet fibs = []\nforeach (f in fib_gen(8)) {\n    fibs.append(f)\n}\nassert(fibs[0] == 0)\nassert(fibs[1] == 1)\nassert(fibs[7] == 13)\n\n// Generator yielding different types\nfunction mixed_gen() {\n    yield 42\n    yield \"hello\"\n    yield [1, 2, 3]\n    yield {a = 1}\n}\n\nlet mg = mixed_gen()\nassert(resume mg == 42)\nassert(resume mg == \"hello\")\nlet arr = resume mg\nassert(arr.len() == 3)\nlet tbl = resume mg\nassert(tbl.a == 1)\n\n// Empty generator (no yields)\nfunction empty_gen() {\n    return null\n}\n\nlet eg = empty_gen()\n// Not really a generator, just a function\n\n// Generator with yield and no value\nfunction void_gen(n) {\n    for (local i = 0; i < n; i++)\n        yield\n}\n\nlet vg = void_gen(3)\nassert(resume vg == null)\nassert(resume vg == null)\nassert(resume vg == null)\n\n// Infinite generator (controlled with break)\nfunction naturals() {\n    local n = 1\n    while (true) {\n        yield n\n        n++\n    }\n}\n\nlet nat = naturals()\nlocal first_five = []\nfor (local i = 0; i < 5; i++) {\n    first_five.append(resume nat)\n}\nassert(first_five[0] == 1)\nassert(first_five[4] == 5)\n\n// Range generator\nfunction range(start, stop, step = 1) {\n    for (local i = start; i < stop; i += step)\n        yield i\n}\n\nlocal range_vals = []\nforeach (v in range(0, 10, 2)) {\n    range_vals.append(v)\n}\nassert(range_vals.len() == 5)\nassert(range_vals[0] == 0)\nassert(range_vals[4] == 8)\n\nprint(\"generators: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/generators.out",
    "content": "generators: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/literals.nut",
    "content": "// Valid syntax: All literal types\n\n// Integer literals\nlet int_dec = 42\nlet int_neg = -123\nlet int_zero = 0\nlet int_hex = 0xFF00A120\nlet int_hex_lower = 0xff\nlet int_char = 'w'\nlet int_char2 = 'A'\nlet int_sep = 123_456\nlet int_hex_sep = 0xAB_CD_01_23\n\n// Float literals\nlet f1 = 1.52\nlet f2 = 1.0\nlet f3 = 0.234\nlet f4 = 6.5e-11\nlet f5 = 1.e2\nlet f6 = 12.345_67e+2\nlet f7 = 3.14159\nlet f8 = 1e10\nlet f9 = 2.5E3\nlet f10 = 0.0\n\n// String literals\nlet s1 = \"regular string\"\nlet s2 = \"escape sequences: \\t \\n \\r \\\\ \\\" \\' \\0\"\nlet s3 = \"hex escape: \\x41\\x42\"\nlet s4 = \"unicode: \\u0041\\u0042\"\nlet s5 = @\"verbatim string with no escapes \\n \\t\"\nlet s6 = @\"verbatim\nmultiline\nstring\"\nlet s7 = @\"verbatim with \"\"doubled\"\" quotes\"\nlet s8 = \"\"\nlet s9 = @\"\"\n\n// String interpolation\nlet x = 42\nlet interp1 = $\"value is {x}\"\nlet interp2 = $\"calc: {x + 1}\"\nlet interp3 = $\"nested: {$\"inner {x}\"}\"\n\n// Boolean literals\nlet b_true = true\nlet b_false = false\n\n// Null literal\nlet n = null\n\n// Verify types\nassert(typeof int_dec == \"integer\")\nassert(typeof f1 == \"float\")\nassert(typeof s1 == \"string\")\nassert(typeof b_true == \"bool\")\nassert(typeof n == \"null\")\n\nprint(\"literals: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/literals.out",
    "content": "literals: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/metamethods.nut",
    "content": "// Valid syntax: Metamethods\n\n// _add and _sub - use getclass() for self-reference\nclass Money {\n    amount = 0\n    constructor(a) { this.amount = a }\n    function _add(other) { return this.getclass()(this.amount + other.amount) }\n    function _sub(other) { return this.getclass()(this.amount - other.amount) }\n    function _mul(factor) { return this.getclass()(this.amount * factor) }\n    function _div(divisor) { return this.getclass()(this.amount / divisor) }\n    function _modulo(m) { return this.getclass()(this.amount % m) }\n    function _unm() { return this.getclass()(-this.amount) }\n    function _cmp(other) {\n        if (this.amount < other.amount) return -1\n        if (this.amount > other.amount) return 1\n        return 0\n    }\n    function _tostring() { return $\"${this.amount}\" }\n    function _typeof() { return \"Money\" }\n}\n\nlet a = Money(100)\nlet b = Money(50)\n\nlet sum = a + b\nassert(sum.amount == 150)\n\nlet diff = a - b\nassert(diff.amount == 50)\n\nlet product = a * 3\nassert(product.amount == 300)\n\nlet neg = -a\nassert(neg.amount == -100)\n\nassert(a > b)\nassert(b < a)\n\nassert(typeof a == \"Money\")\n\n// _get and _set\nclass FlexTable {\n    _data = null\n    constructor() { this._data = {} }\n    function _get(key) {\n        if (key in this._data)\n            return this._data[key]\n        return null\n    }\n    function _set(key, val) {\n        this._data[key] <- val\n    }\n}\n\nlet ft = FlexTable()\nft.name = \"test\"\nft.value = 42\nassert(ft.name == \"test\")\nassert(ft.value == 42)\nassert(ft.missing == null)\n\n// _nexti for iteration\nclass Range {\n    _start = 0\n    _end = 0\n    constructor(s, e) { this._start = s; this._end = e }\n    function _nexti(prev) {\n        if (prev == null) return this._start\n        if (prev + 1 >= this._end) return null\n        return prev + 1\n    }\n    function _get(idx) { return idx }\n}\n\nlocal range_sum = 0\nforeach (v in Range(0, 5)) {\n    range_sum += v\n}\nassert(range_sum == 10) // 0+1+2+3+4\n\n// _call metamethod\nclass Callable {\n    _value = 0\n    constructor(v) { this._value = v }\n    function _call(env, arg) {\n        return this._value + arg\n    }\n}\n\nlet callable = Callable(10)\nassert(callable(5) == 15)\nassert(callable(20) == 30)\n\n// _cloned metamethod\nclass Tracked {\n    id = 0\n    cloned_from = null\n    constructor(id) { this.id = id }\n    function _cloned(orig) {\n        this.cloned_from = orig.id\n    }\n}\n\nlet original = Tracked(1)\nlet cloned = clone original\nassert(cloned.cloned_from == 1)\n\nprint(\"metamethods: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/metamethods.out",
    "content": "metamethods: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/misc.nut",
    "content": "// Valid syntax: Miscellaneous language features\n#allow-delete-operator\n\n// Comments\n// Single line comment\n/* Block comment */\n/* Multi\n   line\n   comment */\n\n// __LINE__ and __FILE__\nlet line = __LINE__\nassert(typeof line == \"integer\")\nlet file = __FILE__\nassert(typeof file == \"string\")\n\n// Semicolons (optional)\nlet a = 1; let b = 2; let c = 3;\nassert(a + b + c == 6)\n\n// Semicolons can be omitted\nlet d_val = 4\nlet e_val = 5\nassert(d_val + e_val == 9)\n\n// Empty blocks\nif (true) {}\nwhile (false) {}\nfor (;;) { break }\n\n// Nested expressions\nlet complex = ((1 + 2) * (3 + 4)) / (5 - 2)\nassert(complex == 7)\n\n// Expression precedence\nassert(2 + 3 * 4 == 14)\nassert((2 + 3) * 4 == 20)\n\n// Type conversion methods (use variables to avoid parse issues)\nlocal iv = 42\nassert(iv.tofloat() == 42.0)\nlocal fv = 3.14\nassert(fv.tointeger() == 3)\nassert(iv.tostring() == \"42\")\nassert(65 .tochar() == \"A\")\n\n// assert with message\nassert(true, \"this should pass\")\n\n// assert with lazy message\nassert(true, @() \"lazy message\")\n\n// Weakref\nlet obj = {value = 42}\nlet weak = obj.weakref()\nassert(typeof weak == \"weakref\")\nassert(weak.ref().value == 42)\n\n// Truthiness rules\nassert(1)          // non-zero int is truthy\nassert(\"hello\")    // non-empty string is truthy\nassert([])         // empty array is truthy\nassert({})         // empty table is truthy\nassert(!null)      // null is falsy\nassert(!false)     // false is falsy\n\n// Chained method calls\nlet result = [3, 1, 4, 1, 5].sort().reverse()\nassert(result[0] == 5)\n\n// Multiline expressions\nlet multi = 1 +\n    2 +\n    3\nassert(multi == 6)\n\n// Table as namespace\nlet Math = {\n    function abs(x) { return x >= 0 ? x : -x }\n    function max(a, b) { return a > b ? a : b }\n    function min(a, b) { return a < b ? a : b }\n}\nassert(Math.abs(-5) == 5)\nassert(Math.max(3, 7) == 7)\nassert(Math.min(3, 7) == 3)\n\n// Newthread\nfunction thread_fn() {\n    return 42\n}\nlet t = newthread(thread_fn)\nassert(typeof t == \"thread\")\n\n// compilestring\nlet compiled = compilestring(\"return 42\")\nassert(compiled() == 42)\n\n// Type method access with .$\nlet override_tbl = {len = @() 0}\nassert(override_tbl.len() == 0)           // calls override\nassert(override_tbl.$len() == 1)          // calls type method\n\n// delete expression returns deleted value\nlocal del_tbl = {a = 42, b = 99}\nlet deleted_val = delete del_tbl.a\nassert(deleted_val == 42)\nassert(!(\"a\" in del_tbl))\n\nprint(\"misc: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/misc.out",
    "content": "misc: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/null_safety.nut",
    "content": "// Valid syntax: Null safety operators\n\n// Null-conditional member access\nlet obj = {name = \"test\", nested = {value = 42}}\nassert(obj?.name == \"test\")\nassert(obj?.nested?.value == 42)\n\nlet null_obj = null\nassert(null_obj?.name == null)\nassert(null_obj?.nested?.value == null)\n\n// Null-conditional indexing\nlet arr = [1, 2, 3]\nassert(arr?[0] == 1)\nassert(arr?[2] == 3)\n\nlet null_arr = null\nassert(null_arr?[0] == null)\n\n// Null-conditional with table bracket\nlet tbl = {a = 1, b = 2}\nassert(tbl?[\"a\"] == 1)\nlet null_tbl = null\nassert(null_tbl?[\"a\"] == null)\n\n// Null-coalescing operator\nassert((null ?? \"default\") == \"default\")\nassert((\"value\" ?? \"default\") == \"value\")\nassert((0 ?? \"default\") == 0) // 0 is not null\nassert((false ?? \"default\") == false) // false is not null\nassert((\"\" ?? \"default\") == \"\")  // empty string is not null\n\n// Chained null-coalescing\nassert((null ?? null ?? \"last\") == \"last\")\nassert((null ?? \"middle\" ?? \"last\") == \"middle\")\n\n// Null-safe function call\nfunction greet(name) { return \"Hello \" + name }\nlet fn = greet\nassert(fn?(\"World\") == \"Hello World\")\n\nlet null_fn = null\nassert(null_fn?(\"World\") == null)\n\n// Null propagation through chain\nlet deep = {level1 = {level2 = {level3 = \"found\"}}}\nassert(deep?.level1?.level2?.level3 == \"found\")\nassert(deep?.missing?.level2?.level3 == null)\n\n// Null-safe type method access\nlet s = \"hello\"\nassert(s?.$len() == 5)\nlet null_s = null\nassert(null_s?.$len() == null)\n\n// Practical patterns\nfunction safe_get(tbl, key, default_val = null) {\n    return tbl?[key] ?? default_val\n}\nassert(safe_get({a = 1}, \"a\") == 1)\nassert(safe_get({a = 1}, \"b\", 0) == 0)\nassert(safe_get(null, \"a\", 0) == 0)\n\n// Null-safe in conditional\nlet maybe_obj = null\nif (maybe_obj?.value != null) {\n    assert(false) // should not reach\n}\n\nlet real_obj = {value = 42}\nif (real_obj?.value != null) {\n    assert(real_obj.value == 42)\n}\n\nprint(\"null_safety: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/null_safety.out",
    "content": "null_safety: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/operators.nut",
    "content": "// Valid syntax: All operators\n\n// Arithmetic operators\nlet a = 10 + 5      // 15\nlet b = 10 - 5      // 5\nlet c = 10 * 5      // 50\nlet d = 10 / 5      // 2\nlet e = 10 % 3      // 1\nassert(a == 15)\nassert(b == 5)\nassert(c == 50)\nassert(d == 2)\nassert(e == 1)\n\n// Unary negation\nlet neg = -42\nassert(neg == -42)\n\n// Increment/decrement\nlocal inc_val = 5\ninc_val++\nassert(inc_val == 6)\n++inc_val\nassert(inc_val == 7)\ninc_val--\nassert(inc_val == 6)\n--inc_val\nassert(inc_val == 5)\n\n// Post-increment returns old value\nlocal pv = 10\nlet old_val = pv++\nassert(old_val == 10)\nassert(pv == 11)\n\n// Pre-increment returns new value\nlet new_val = ++pv\nassert(new_val == 12)\nassert(pv == 12)\n\n// Comparison operators\nassert(5 == 5)\nassert(5 != 6)\nassert(5 < 6)\nassert(6 > 5)\nassert(5 <= 5)\nassert(5 <= 6)\nassert(5 >= 5)\nassert(6 >= 5)\n\n// Three-way comparison\nassert((5 <=> 6) < 0)\nassert((5 <=> 5) == 0)\nassert((6 <=> 5) > 0)\n\n// Logical operators\nassert(true && true)\nassert(!(true && false))\nassert(true || false)\nassert(!(false || false))\nassert(!false)\nassert(!!true)\n\n// Bitwise operators\nassert((0xFF & 0x0F) == 0x0F)\nassert((0xF0 | 0x0F) == 0xFF)\nassert((0xFF ^ 0x0F) == 0xF0)\nassert(~0 == -1)\nassert((1 << 4) == 16)\nassert((16 >> 2) == 4)\nassert((16 >>> 2) == 4)\n\n// Compound assignment\nlocal ca = 10\nca += 5\nassert(ca == 15)\nca -= 3\nassert(ca == 12)\nca *= 2\nassert(ca == 24)\nca /= 4\nassert(ca == 6)\nca %= 4\nassert(ca == 2)\n\n// Ternary operator\nlet ter = true ? \"yes\" : \"no\"\nassert(ter == \"yes\")\nlet ter2 = false ? \"yes\" : \"no\"\nassert(ter2 == \"no\")\n\n// typeof operator\nassert(typeof 42 == \"integer\")\nassert(typeof 3.14 == \"float\")\nassert(typeof \"str\" == \"string\")\nassert(typeof true == \"bool\")\nassert(typeof null == \"null\")\nassert(typeof [] == \"array\")\nassert(typeof {} == \"table\")\n\n// in operator\nlet tbl = {a = 1, b = 2}\nassert(\"a\" in tbl)\nassert(!(\"c\" in tbl))\n\n// not in operator\nassert(\"c\" not in tbl)\nassert(!(\"a\" not in tbl))\n\n// instanceof\nclass MyClass {}\nlet inst = MyClass()\nassert(inst instanceof MyClass)\n\n// Null-coalescing operator\nlet nc1 = null ?? \"default\"\nassert(nc1 == \"default\")\nlet nc2 = \"value\" ?? \"default\"\nassert(nc2 == \"value\")\nlet nc3 = null ?? null ?? \"last\"\nassert(nc3 == \"last\")\n\n// String concatenation with +\nlet str_cat = \"hello\" + \" \" + \"world\"\nassert(str_cat == \"hello world\")\n\n// delete operator (with allow directive)\n#allow-delete-operator\nlocal del_tbl = {a = 1, b = 2}\ndelete del_tbl.a\nassert(!(\"a\" in del_tbl))\n\n// clone operator\nlet orig = {x = 1, y = 2}\nlet copy = clone orig\nassert(copy.x == 1)\ncopy.x = 99\nassert(orig.x == 1)\n\nprint(\"operators: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/operators.out",
    "content": "operators: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/static_memo.nut",
    "content": "// Valid syntax: Static memoization\n\n// Static with simple value\nfunction get_config() {\n    return static {\n        name = \"app\",\n        version = \"1.0\"\n    }\n}\n\nlet cfg1 = get_config()\nlet cfg2 = get_config()\n// Both return the same cached frozen object\n\nassert(cfg1.name == \"app\")\nassert(cfg1.version == \"1.0\")\n\n// Static with array\nfunction get_list() {\n    return static [1, 2, 3, 4, 5]\n}\nlet list1 = get_list()\nassert(list1.len() == 5)\nassert(list1[0] == 1)\n\n// Static with simple expression\nfunction get_value() {\n    return static 42 * 2 + 1\n}\nassert(get_value() == 85)\n\n// Static objects are frozen\nlet frozen_tbl = static {a = 1, b = 2}\nassert(frozen_tbl.is_frozen())\n\nlet frozen_arr = static [1, 2, 3]\nassert(frozen_arr.is_frozen())\n\n// Inline const expressions\nlet const_arr = const [10, 20, 30]\nassert(const_arr.is_frozen())\nassert(const_arr[0] == 10)\n\nlet const_tbl = const {x = 1, y = 2}\nassert(const_tbl.is_frozen())\n\n// Const function\nlet const_fn = const @(x) x * 2\nassert(const_fn(5) == 10)\n\n// freeze function\nlet mutable_arr = [1, 2, 3]\nlet immutable_arr = freeze(mutable_arr)\nassert(immutable_arr.is_frozen())\n\nlet mutable_tbl = {a = 1}\nlet immutable_tbl = freeze(mutable_tbl)\nassert(immutable_tbl.is_frozen())\n\nprint(\"static_memo: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/static_memo.out",
    "content": "static_memo: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/strings.nut",
    "content": "// Valid syntax: Strings\n\n// Basic strings\nlet s1 = \"hello\"\nlet s2 = \"world\"\nassert(s1 == \"hello\")\n\n// Escape sequences\nlet esc_tab = \"a\\tb\"\nlet esc_nl = \"a\\nb\"\nlet esc_cr = \"a\\rb\"\nlet esc_bs = \"a\\\\b\"\nlet esc_dq = \"a\\\"b\"\nlet esc_sq = \"a\\'b\"\nlet esc_null = \"a\\0b\"\nlet esc_hex = \"\\x41\\x42\\x43\"\nassert(esc_hex == \"ABC\")\nlet esc_uni = \"\\u0048\\u0069\"\nassert(esc_uni == \"Hi\")\n\n// Verbatim strings\nlet verb1 = @\"no escapes \\n \\t here\"\nassert(verb1.contains(\"\\\\n\"))\nlet verb2 = @\"multiline\nverbatim\"\nassert(verb2.contains(\"\\n\"))\nlet verb3 = @\"doubled \"\"quotes\"\" inside\"\nassert(verb3.contains(\"\\\"\"))\n\n// String interpolation\nlet name = \"World\"\nlet interp = $\"Hello {name}!\"\nassert(interp == \"Hello World!\")\n\nlocal val = 42\nlet interp2 = $\"val={val}, doubled={val * 2}\"\nassert(interp2 == \"val=42, doubled=84\")\n\n// String methods\nassert(\"hello\".len() == 5)\nassert(\"hello world\".indexof(\"world\") == 6)\nassert(\"hello world\".contains(\"world\"))\nassert(!\"hello\".contains(\"xyz\"))\nassert(\"HELLO\".tolower() == \"hello\")\nassert(\"hello\".toupper() == \"HELLO\")\nassert(\"hello world\".slice(0, 5) == \"hello\")\nassert(\"hello world\".slice(6) == \"world\")\n\n// split\nlet parts = \"a,b,c\".split(\",\")\nassert(parts.len() == 3)\nassert(parts[0] == \"a\")\nassert(parts[2] == \"c\")\n\n// split_by_chars\nlet chars_split = \"a.b-c_d\".split_by_chars(\".-_\")\nassert(chars_split.len() == 4)\n\n// strip / lstrip / rstrip\nassert(\"  hello  \".strip() == \"hello\")\nassert(\"  hello  \".lstrip() == \"hello  \")\nassert(\"  hello  \".rstrip() == \"  hello\")\n\n// startswith\nassert(\"hello world\".startswith(\"hello\"))\nassert(!\"hello world\".startswith(\"world\"))\n\n// replace\nlet replaced = \"aabbcc\".replace(\"bb\", \"XX\")\nassert(replaced == \"aaXXcc\")\n\n// join\nlet joined = \", \".join([\"a\", \"b\", \"c\"])\nassert(joined == \"a, b, c\")\n\n// tointeger / tofloat\nassert(\"42\".tointeger() == 42)\nassert(\"3.14\".tofloat() == 3.14)\nassert(\"0xFF\".tointeger(16) == 255)\n\n// String concatenation\nlet concat = \"hello\" + \" \" + \"world\"\nassert(concat == \"hello world\")\n\n// concat with numbers\nlet numstr = \"val=\" + 42\nassert(numstr == \"val=42\")\n\n// Empty string\nlet empty_str = \"\"\nassert(empty_str.len() == 0)\n\n// String as iterable\nlocal count = 0\nforeach (ch in \"hello\") {\n    count++\n}\nassert(count == 5)\n\n// hasindex\nassert(\"hello\".hasindex(0))\nassert(\"hello\".hasindex(4))\nassert(!\"hello\".hasindex(5))\n\n// hash\nlet h = \"hello\".hash()\nassert(typeof h == \"integer\")\n\n// tostring on various types (use variables to avoid parse issues)\nlocal int_val = 42\nassert(int_val.tostring() == \"42\")\nlocal float_val = 3.14\nassert(float_val.tostring() == \"3.14\")\nassert(true.tostring() == \"true\")\nassert(false.tostring() == \"false\")\n\nprint(\"strings: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/strings.out",
    "content": "strings: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/tables.nut",
    "content": "// Valid syntax: Tables\n#allow-delete-operator\n\n// Empty table\nlet empty = {}\nassert(empty.len() == 0)\n\n// Table with identifier keys\nlet t1 = {\n    name = \"John\",\n    age = 30,\n    active = true\n}\nassert(t1.name == \"John\")\nassert(t1.age == 30)\nassert(t1.active == true)\n\n// Table with computed/bracket keys\nlet t2 = {\n    [\"dynamic-key\"] = \"value\",\n    [42] = \"numeric key\",\n    [\"a\" + \"b\"] = \"computed\"\n}\nassert(t2[\"dynamic-key\"] == \"value\")\nassert(t2[42] == \"numeric key\")\nassert(t2[\"ab\"] == \"computed\")\n\n// Table with methods\nlet t3 = {\n    value = 10,\n    function get() { return this.value },\n    function set(v) { this.value = v }\n}\nassert(t3.get() == 10)\nt3.set(20)\nassert(t3.get() == 20)\n\n// ES2015 shorthand\nlocal x = 123\nlocal y = 456\nlet shorthand = {x, y}\nassert(shorthand.x == 123)\nassert(shorthand.y == 456)\n\n// Mixed shorthand and explicit\nlocal z = 789\nlet mixed = {x, y = 20, z}\nassert(mixed.x == 123)\nassert(mixed.y == 20)\nassert(mixed.z == 789)\n\n// Trailing comma\nlet trailing = {\n    a = 1,\n    b = 2,\n}\nassert(trailing.a == 1)\n\n// No comma (space-separated)\nlet no_comma = {\n    a = 1\n    b = 2\n    c = 3\n}\nassert(no_comma.len() == 3)\n\n// Nested table\nlet nested = {\n    inner = {\n        deep = {\n            value = 42\n        }\n    }\n}\nassert(nested.inner.deep.value == 42)\n\n// Slot creation with <-\nlocal t4 = {}\nt4.newkey <- \"hello\"\nassert(t4.newkey == \"hello\")\nt4[\"another\"] <- 42\nassert(t4.another == 42)\n\n// Slot deletion\nlocal t5 = {a = 1, b = 2, c = 3}\ndelete t5.a\nassert(!(\"a\" in t5))\nassert(t5.len() == 2)\n\n// Table methods\nlet methods_tbl = {a = 1, b = 2, c = 3}\nassert(methods_tbl.len() == 3)\nassert(methods_tbl.rawin(\"a\"))\nassert(methods_tbl.rawget(\"a\") == 1)\n\nlet keys = methods_tbl.keys()\nassert(keys.len() == 3)\n\nlet values = methods_tbl.values()\nassert(values.len() == 3)\n\n// Table functional methods\nlet mapped = methods_tbl.map(@(v) v * 2)\nassert(mapped.a == 2)\n\nlet filtered = methods_tbl.filter(@(v) v > 1)\nassert(!(\"a\" in filtered))\nassert(\"b\" in filtered)\n\nlocal each_sum = 0\nmethods_tbl.each(@(v) each_sum += v)\nassert(each_sum == 6)\n\n// rawset returns the table (for chaining)\nlet chain_tbl = {}\nchain_tbl.rawset(\"a\", 1).rawset(\"b\", 2).rawset(\"c\", 3)\nassert(chain_tbl.a == 1)\nassert(chain_tbl.b == 2)\nassert(chain_tbl.c == 3)\n\n// topairs\nlet pairs = {x = 10, y = 20}.topairs()\nassert(pairs.len() == 2)\n\n// __merge\nlet base_tbl = {a = 1, b = 2}\nlet extra = {b = 3, c = 4}\nlet merged = base_tbl.__merge(extra)\nassert(merged.a == 1)\nassert(merged.b == 3)\nassert(merged.c == 4)\nassert(base_tbl.b == 2) // original unchanged\n\n// __update (in-place)\nlocal updatable = {a = 1, b = 2}\nupdatable.__update({b = 3, c = 4})\nassert(updatable.b == 3)\nassert(updatable.c == 4)\n\n// in / not in\nlet membership = {a = 1, b = 2}\nassert(\"a\" in membership)\nassert(\"c\" not in membership)\n\n// Iteration\nlocal iter_count = 0\nforeach (k, v in {a = 1, b = 2, c = 3}) {\n    iter_count++\n}\nassert(iter_count == 3)\n\n// clone table\nlet orig = {x = 1, y = [1, 2]}\nlet cloned = clone orig\ncloned.x = 99\nassert(orig.x == 1) // original not modified\n\n// Table with function values\nlet fn_tbl = {\n    add = @(a, b) a + b,\n    mul = @(a, b) a * b,\n}\nassert(fn_tbl.add(2, 3) == 5)\nassert(fn_tbl.mul(2, 3) == 6)\n\nprint(\"tables: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/tables.out",
    "content": "tables: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/threads.nut",
    "content": "// Valid syntax: Threads/Coroutines\n\n// Create thread\nfunction thread_fn(a, b) {\n    local val = suspend(a + b)\n    return val * 2\n}\n\nlet t = newthread(thread_fn)\nassert(typeof t == \"thread\")\n\n// Start thread\nlet first = t.call(3, 4)\nassert(first == 7) // a + b = 7\n\n// Resume thread\nlet result = t.wakeup(10)\nassert(result == 20) // 10 * 2\n\n// Thread status\nfunction status_fn() {\n    suspend(\"first\")\n    suspend(\"second\")\n    return \"done\"\n}\n\nlet st = newthread(status_fn)\nassert(st.getstatus() == \"idle\")\nlet v1 = st.call()\nassert(v1 == \"first\")\nassert(st.getstatus() == \"suspended\")\nlet v2 = st.wakeup()\nassert(v2 == \"second\")\nassert(st.getstatus() == \"suspended\")\nlet v3 = st.wakeup()\nassert(v3 == \"done\")\n\n// Multiple coroutines\nfunction counter(start) {\n    local n = start\n    while (true) {\n        suspend(n)\n        n++\n    }\n}\n\nlet c1 = newthread(counter)\nlet c2 = newthread(counter)\n\nassert(c1.call(0) == 0)\nassert(c2.call(100) == 100)\nassert(c1.wakeup() == 1)\nassert(c2.wakeup() == 101)\nassert(c1.wakeup() == 2)\nassert(c2.wakeup() == 102)\n\n// Passing values to suspended thread\nfunction receiver() {\n    local val = suspend(\"ready\")\n    return val\n}\n\nlet recv = newthread(receiver)\nlet ready = recv.call()\nassert(ready == \"ready\")\nlet final_val = recv.wakeup(42)\nassert(final_val == 42)\n\nprint(\"threads: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/threads.out",
    "content": "threads: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/type_annotations.nut",
    "content": "// Valid syntax: Type annotations\n\n// Variable type annotations\nlocal xi: int = 42\nlocal xf: float = 3.14\nlocal xs: string = \"hello\"\nlocal xb: bool = true\nlocal xn: null = null\nlocal xa: array = [1, 2]\nlocal xt: table = {a = 1}\nlocal xfn: function = @(x) x\n\n// let with type annotations\nlet li: int = 100\nlet lf: float = 2.71\nlet ls: string = \"world\"\n\n// Union types\nlocal nu: int|null = null\nnu = 42\nlocal ns: string|null = \"text\"\nns = null\nlocal nif: int|float = 42\nnif = 3.14\n\n// Function parameter types\nfunction typed_add(a: int, b: int): int {\n    return a + b\n}\nassert(typed_add(2, 3) == 5)\n\n// Function with union param types\nfunction flex(val: int|string) {\n    return val\n}\nassert(flex(42) == 42)\nassert(flex(\"hi\") == \"hi\")\n\n// Function with nullable params\nfunction opt(x: int|null = null): int {\n    return x ?? 0\n}\nassert(opt() == 0)\nassert(opt(10) == 10)\n\n// Lambda with type annotations\nlet typed_lambda = @(x: int, y: int): int x + y\nassert(typed_lambda(3, 4) == 7)\n\n// number type (int | float)\nfunction accept_number(n: number): number {\n    return n\n}\nassert(accept_number(42) == 42)\nassert(accept_number(3.14) == 3.14)\n\n// any type\nfunction accept_any(v: any): any {\n    return v\n}\nassert(accept_any(42) == 42)\nassert(accept_any(\"str\") == \"str\")\nassert(accept_any(null) == null)\n\n// Varargs type annotation\nfunction sum_floats(first: float, ...: float): float {\n    local total = first\n    foreach (v in vargv) total += v\n    return total\n}\nassert(sum_floats(1.0, 2.0, 3.0) == 6.0)\n\n// Complex return type\nfunction maybe_string(flag: bool): string|null {\n    if (flag) return \"yes\"\n    return null\n}\nassert(maybe_string(true) == \"yes\")\nassert(maybe_string(false) == null)\n\nprint(\"type_annotations: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/type_annotations.out",
    "content": "type_annotations: OK\n"
  },
  {
    "path": "testData/exec/valid_syntax/variables.nut",
    "content": "// Valid syntax: Variable declarations and scoping\n\n// local declaration\nlocal x = 10\nlocal y\nassert(x == 10)\nassert(y == null)\n\n// Multiple local declarations\nlocal a = 1, b = 2, c = 3\nassert(a == 1)\nassert(b == 2)\nassert(c == 3)\n\n// let declarations (immutable bindings)\nlet lx = 42\nlet ly = \"hello\"\nassert(lx == 42)\nassert(ly == \"hello\")\n\n// let with mutable objects\nlet arr = [1, 2, 3]\narr[0] = 99\nassert(arr[0] == 99)\n\nlet tbl = {a = 1}\ntbl.a = 2\nassert(tbl.a == 2)\n\n// Block scoping\n{\n    local inner = 100\n    assert(inner == 100)\n}\n\n// local in for loop\nfor (local i = 0; i < 3; i++) {\n    assert(i >= 0)\n}\n\n// Multiple assignment\nlocal m1 = 1\nlocal m2 = 2\nm1 = 10\nm2 = 20\nassert(m1 == 10)\nassert(m2 == 20)\n\n// Variable referencing earlier variable\nlocal va = 5\nlocal vb = va + 1\nassert(vb == 6)\n\n// Uninitialized local defaults to null\nlocal uninit\nassert(uninit == null)\n\n// Nested scopes with different variable names\nlocal outer = \"outer\"\n{\n    local inner2 = \"inner\"\n    assert(inner2 == \"inner\")\n    assert(outer == \"outer\")\n}\nassert(outer == \"outer\")\n\nprint(\"variables: OK\\n\")\n"
  },
  {
    "path": "testData/exec/valid_syntax/variables.out",
    "content": "variables: OK\n"
  },
  {
    "path": "testData/exec/weird/2000_args.nut",
    "content": "local function fn(\n a000, a001, a002, a003, a004, a005, a006, a007, a008, a009,\n a010, a011, a012, a013, a014, a015, a016, a017, a018, a019,\n a020, a021, a022, a023, a024, a025, a026, a027, a028, a029,\n a030, a031, a032, a033, a034, a035, a036, a037, a038, a039,\n a040, a041, a042, a043, a044, a045, a046, a047, a048, a049,\n a050, a051, a052, a053, a054, a055, a056, a057, a058, a059,\n a060, a061, a062, a063, a064, a065, a066, a067, a068, a069,\n a070, a071, a072, a073, a074, a075, a076, a077, a078, a079,\n a080, a081, a082, a083, a084, a085, a086, a087, a088, a089,\n a090, a091, a092, a093, a094, a095, a096, a097, a098, a099,\n a100, a101, a102, a103, a104, a105, a106, a107, a108, a109,\n a110, a111, a112, a113, a114, a115, a116, a117, a118, a119,\n a120, a121, a122, a123, a124, a125, a126, a127, a128, a129,\n a130, a131, a132, a133, a134, a135, a136, a137, a138, a139,\n a140, a141, a142, a143, a144, a145, a146, a147, a148, a149,\n a150, a151, a152, a153, a154, a155, a156, a157, a158, a159,\n a160, a161, a162, a163, a164, a165, a166, a167, a168, a169,\n a170, a171, a172, a173, a174, a175, a176, a177, a178, a179,\n a180, a181, a182, a183, a184, a185, a186, a187, a188, a189,\n a190, a191, a192, a193, a194, a195, a196, a197, a198, a199,\n a200, a201, a202, a203, a204, a205, a206, a207, a208, a209,\n a210, a211, a212, a213, a214, a215, a216, a217, a218, a219,\n a220, a221, a222, a223, a224, a225, a226, a227, a228, a229,\n a230, a231, a232, a233, a234, a235, a236, a237, a238, a239,\n a240, a241, a242, a243, a244, a245, a246, a247, a248, a249,\n a250, a251, a252, a253, a254, a255, a256, a257, a258, a259,\n a260, a261, a262, a263, a264, a265, a266, a267, a268, a269,\n a270, a271, a272, a273, a274, a275, a276, a277, a278, a279,\n a280, a281, a282, a283, a284, a285, a286, a287, a288, a289,\n a290, a291, a292, a293, a294, a295, a296, a297, a298, a299,\n a300, a301, a302, a303, a304, a305, a306, a307, a308, a309,\n a310, a311, a312, a313, a314, a315, a316, a317, a318, a319,\n a320, a321, a322, a323, a324, a325, a326, a327, a328, a329,\n a330, a331, a332, a333, a334, a335, a336, a337, a338, a339,\n a340, a341, a342, a343, a344, a345, a346, a347, a348, a349,\n a350, a351, a352, a353, a354, a355, a356, a357, a358, a359,\n a360, a361, a362, a363, a364, a365, a366, a367, a368, a369,\n a370, a371, a372, a373, a374, a375, a376, a377, a378, a379,\n a380, a381, a382, a383, a384, a385, a386, a387, a388, a389,\n a390, a391, a392, a393, a394, a395, a396, a397, a398, a399,\n a400, a401, a402, a403, a404, a405, a406, a407, a408, a409,\n a410, a411, a412, a413, a414, a415, a416, a417, a418, a419,\n a420, a421, a422, a423, a424, a425, a426, a427, a428, a429,\n a430, a431, a432, a433, a434, a435, a436, a437, a438, a439,\n a440, a441, a442, a443, a444, a445, a446, a447, a448, a449,\n a450, a451, a452, a453, a454, a455, a456, a457, a458, a459,\n a460, a461, a462, a463, a464, a465, a466, a467, a468, a469,\n a470, a471, a472, a473, a474, a475, a476, a477, a478, a479,\n a480, a481, a482, a483, a484, a485, a486, a487, a488, a489,\n a490, a491, a492, a493, a494, a495, a496, a497, a498, a499,\n a500, a501, a502, a503, a504, a505, a506, a507, a508, a509,\n a510, a511, a512, a513, a514, a515, a516, a517, a518, a519,\n a520, a521, a522, a523, a524, a525, a526, a527, a528, a529,\n a530, a531, a532, a533, a534, a535, a536, a537, a538, a539,\n a540, a541, a542, a543, a544, a545, a546, a547, a548, a549,\n a550, a551, a552, a553, a554, a555, a556, a557, a558, a559,\n a560, a561, a562, a563, a564, a565, a566, a567, a568, a569,\n a570, a571, a572, a573, a574, a575, a576, a577, a578, a579,\n a580, a581, a582, a583, a584, a585, a586, a587, a588, a589,\n a590, a591, a592, a593, a594, a595, a596, a597, a598, a599,\n a600, a601, a602, a603, a604, a605, a606, a607, a608, a609,\n a610, a611, a612, a613, a614, a615, a616, a617, a618, a619,\n a620, a621, a622, a623, a624, a625, a626, a627, a628, a629,\n a630, a631, a632, a633, a634, a635, a636, a637, a638, a639,\n a640, a641, a642, a643, a644, a645, a646, a647, a648, a649,\n a650, a651, a652, a653, a654, a655, a656, a657, a658, a659,\n a660, a661, a662, a663, a664, a665, a666, a667, a668, a669,\n a670, a671, a672, a673, a674, a675, a676, a677, a678, a679,\n a680, a681, a682, a683, a684, a685, a686, a687, a688, a689,\n a690, a691, a692, a693, a694, a695, a696, a697, a698, a699,\n a700, a701, a702, a703, a704, a705, a706, a707, a708, a709,\n a710, a711, a712, a713, a714, a715, a716, a717, a718, a719,\n a720, a721, a722, a723, a724, a725, a726, a727, a728, a729,\n a730, a731, a732, a733, a734, a735, a736, a737, a738, a739,\n a740, a741, a742, a743, a744, a745, a746, a747, a748, a749,\n a750, a751, a752, a753, a754, a755, a756, a757, a758, a759,\n a760, a761, a762, a763, a764, a765, a766, a767, a768, a769,\n a770, a771, a772, a773, a774, a775, a776, a777, a778, a779,\n a780, a781, a782, a783, a784, a785, a786, a787, a788, a789,\n a790, a791, a792, a793, a794, a795, a796, a797, a798, a799,\n a800, a801, a802, a803, a804, a805, a806, a807, a808, a809,\n a810, a811, a812, a813, a814, a815, a816, a817, a818, a819,\n a820, a821, a822, a823, a824, a825, a826, a827, a828, a829,\n a830, a831, a832, a833, a834, a835, a836, a837, a838, a839,\n a840, a841, a842, a843, a844, a845, a846, a847, a848, a849,\n a850, a851, a852, a853, a854, a855, a856, a857, a858, a859,\n a860, a861, a862, a863, a864, a865, a866, a867, a868, a869,\n a870, a871, a872, a873, a874, a875, a876, a877, a878, a879,\n a880, a881, a882, a883, a884, a885, a886, a887, a888, a889,\n a890, a891, a892, a893, a894, a895, a896, a897, a898, a899,\n a900, a901, a902, a903, a904, a905, a906, a907, a908, a909,\n a910, a911, a912, a913, a914, a915, a916, a917, a918, a919,\n a920, a921, a922, a923, a924, a925, a926, a927, a928, a929,\n a930, a931, a932, a933, a934, a935, a936, a937, a938, a939,\n a940, a941, a942, a943, a944, a945, a946, a947, a948, a949,\n a950, a951, a952, a953, a954, a955, a956, a957, a958, a959,\n a960, a961, a962, a963, a964, a965, a966, a967, a968, a969,\n a970, a971, a972, a973, a974, a975, a976, a977, a978, a979,\n a980, a981, a982, a983, a984, a985, a986, a987, a988, a989,\n a990, a991, a992, a993, a994, a995, a996, a997, a998, a999,\n b000, b001, b002, b003, b004, b005, b006, b007, b008, b009,\n b010, b011, b012, b013, b014, b015, b016, b017, b018, b019,\n b020, b021, b022, b023, b024, b025, b026, b027, b028, b029,\n b030, b031, b032, b033, b034, b035, b036, b037, b038, b039,\n b040, b041, b042, b043, b044, b045, b046, b047, b048, b049,\n b050, b051, b052, b053, b054, b055, b056, b057, b058, b059,\n b060, b061, b062, b063, b064, b065, b066, b067, b068, b069,\n b070, b071, b072, b073, b074, b075, b076, b077, b078, b079,\n b080, b081, b082, b083, b084, b085, b086, b087, b088, b089,\n b090, b091, b092, b093, b094, b095, b096, b097, b098, b099,\n b100, b101, b102, b103, b104, b105, b106, b107, b108, b109,\n b110, b111, b112, b113, b114, b115, b116, b117, b118, b119,\n b120, b121, b122, b123, b124, b125, b126, b127, b128, b129,\n b130, b131, b132, b133, b134, b135, b136, b137, b138, b139,\n b140, b141, b142, b143, b144, b145, b146, b147, b148, b149,\n b150, b151, b152, b153, b154, b155, b156, b157, b158, b159,\n b160, b161, b162, b163, b164, b165, b166, b167, b168, b169,\n b170, b171, b172, b173, b174, b175, b176, b177, b178, b179,\n b180, b181, b182, b183, b184, b185, b186, b187, b188, b189,\n b190, b191, b192, b193, b194, b195, b196, b197, b198, b199,\n b200, b201, b202, b203, b204, b205, b206, b207, b208, b209,\n b210, b211, b212, b213, b214, b215, b216, b217, b218, b219,\n b220, b221, b222, b223, b224, b225, b226, b227, b228, b229,\n b230, b231, b232, b233, b234, b235, b236, b237, b238, b239,\n b240, b241, b242, b243, b244, b245, b246, b247, b248, b249,\n b250, b251, b252, b253, b254, b255, b256, b257, b258, b259,\n b260, b261, b262, b263, b264, b265, b266, b267, b268, b269,\n b270, b271, b272, b273, b274, b275, b276, b277, b278, b279,\n b280, b281, b282, b283, b284, b285, b286, b287, b288, b289,\n b290, b291, b292, b293, b294, b295, b296, b297, b298, b299,\n b300, b301, b302, b303, b304, b305, b306, b307, b308, b309,\n b310, b311, b312, b313, b314, b315, b316, b317, b318, b319,\n b320, b321, b322, b323, b324, b325, b326, b327, b328, b329,\n b330, b331, b332, b333, b334, b335, b336, b337, b338, b339,\n b340, b341, b342, b343, b344, b345, b346, b347, b348, b349,\n b350, b351, b352, b353, b354, b355, b356, b357, b358, b359,\n b360, b361, b362, b363, b364, b365, b366, b367, b368, b369,\n b370, b371, b372, b373, b374, b375, b376, b377, b378, b379,\n b380, b381, b382, b383, b384, b385, b386, b387, b388, b389,\n b390, b391, b392, b393, b394, b395, b396, b397, b398, b399,\n b400, b401, b402, b403, b404, b405, b406, b407, b408, b409,\n b410, b411, b412, b413, b414, b415, b416, b417, b418, b419,\n b420, b421, b422, b423, b424, b425, b426, b427, b428, b429,\n b430, b431, b432, b433, b434, b435, b436, b437, b438, b439,\n b440, b441, b442, b443, b444, b445, b446, b447, b448, b449,\n b450, b451, b452, b453, b454, b455, b456, b457, b458, b459,\n b460, b461, b462, b463, b464, b465, b466, b467, b468, b469,\n b470, b471, b472, b473, b474, b475, b476, b477, b478, b479,\n b480, b481, b482, b483, b484, b485, b486, b487, b488, b489,\n b490, b491, b492, b493, b494, b495, b496, b497, b498, b499,\n b500, b501, b502, b503, b504, b505, b506, b507, b508, b509,\n b510, b511, b512, b513, b514, b515, b516, b517, b518, b519,\n b520, b521, b522, b523, b524, b525, b526, b527, b528, b529,\n b530, b531, b532, b533, b534, b535, b536, b537, b538, b539,\n b540, b541, b542, b543, b544, b545, b546, b547, b548, b549,\n b550, b551, b552, b553, b554, b555, b556, b557, b558, b559,\n b560, b561, b562, b563, b564, b565, b566, b567, b568, b569,\n b570, b571, b572, b573, b574, b575, b576, b577, b578, b579,\n b580, b581, b582, b583, b584, b585, b586, b587, b588, b589,\n b590, b591, b592, b593, b594, b595, b596, b597, b598, b599,\n b600, b601, b602, b603, b604, b605, b606, b607, b608, b609,\n b610, b611, b612, b613, b614, b615, b616, b617, b618, b619,\n b620, b621, b622, b623, b624, b625, b626, b627, b628, b629,\n b630, b631, b632, b633, b634, b635, b636, b637, b638, b639,\n b640, b641, b642, b643, b644, b645, b646, b647, b648, b649,\n b650, b651, b652, b653, b654, b655, b656, b657, b658, b659,\n b660, b661, b662, b663, b664, b665, b666, b667, b668, b669,\n b670, b671, b672, b673, b674, b675, b676, b677, b678, b679,\n b680, b681, b682, b683, b684, b685, b686, b687, b688, b689,\n b690, b691, b692, b693, b694, b695, b696, b697, b698, b699,\n b700, b701, b702, b703, b704, b705, b706, b707, b708, b709,\n b710, b711, b712, b713, b714, b715, b716, b717, b718, b719,\n b720, b721, b722, b723, b724, b725, b726, b727, b728, b729,\n b730, b731, b732, b733, b734, b735, b736, b737, b738, b739,\n b740, b741, b742, b743, b744, b745, b746, b747, b748, b749,\n b750, b751, b752, b753, b754, b755, b756, b757, b758, b759,\n b760, b761, b762, b763, b764, b765, b766, b767, b768, b769,\n b770, b771, b772, b773, b774, b775, b776, b777, b778, b779,\n b780, b781, b782, b783, b784, b785, b786, b787, b788, b789,\n b790, b791, b792, b793, b794, b795, b796, b797, b798, b799,\n b800, b801, b802, b803, b804, b805, b806, b807, b808, b809,\n b810, b811, b812, b813, b814, b815, b816, b817, b818, b819,\n b820, b821, b822, b823, b824, b825, b826, b827, b828, b829,\n b830, b831, b832, b833, b834, b835, b836, b837, b838, b839,\n b840, b841, b842, b843, b844, b845, b846, b847, b848, b849,\n b850, b851, b852, b853, b854, b855, b856, b857, b858, b859,\n b860, b861, b862, b863, b864, b865, b866, b867, b868, b869,\n b870, b871, b872, b873, b874, b875, b876, b877, b878, b879,\n b880, b881, b882, b883, b884, b885, b886, b887, b888, b889,\n b890, b891, b892, b893, b894, b895, b896, b897, b898, b899,\n b900, b901, b902, b903, b904, b905, b906, b907, b908, b909,\n b910, b911, b912, b913, b914, b915, b916, b917, b918, b919,\n b920, b921, b922, b923, b924, b925, b926, b927, b928, b929,\n b930, b931, b932, b933, b934, b935, b936, b937, b938, b939,\n b940, b941, b942, b943, b944, b945, b946, b947, b948, b949,\n b950, b951, b952, b953, b954, b955, b956, b957, b958, b959,\n b960, b961, b962, b963, b964, b965, b966, b967, b968, b969,\n b970, b971, b972, b973, b974, b975, b976, b977, b978, b979,\n b980, b981, b982, b983, b984, b985, b986, b987, b988, b989,\n b990, b991, b992, b993, b994, b995, b996, b997, b998, b999\n) {}\n"
  },
  {
    "path": "testData/exec/weird/2000_args.out",
    "content": ""
  },
  {
    "path": "testData/exec/weird/assign_to_optional_1.nut",
    "content": "local t = {a = 5}\nt?.a = 10\n"
  },
  {
    "path": "testData/exec/weird/assign_to_optional_1.out",
    "content": ""
  },
  {
    "path": "testData/exec/weird/assign_to_optional_2.nut",
    "content": "local t = {a = 5}\nt?.b <- 10"
  },
  {
    "path": "testData/exec/weird/assign_to_optional_2.out",
    "content": ""
  },
  {
    "path": "testData/exec/weird/assign_to_optional_3.nut",
    "content": "local t = {a = 5}\nt?[\"c\"] <- 20"
  },
  {
    "path": "testData/exec/weird/assign_to_optional_3.out",
    "content": ""
  },
  {
    "path": "testData/exec/weird/many_locals.nut",
    "content": "#disable-optimizer\n#allow-switch-statement\nlet _sv = @(_e) (type(_e) == \"integer\" || type(_e) == \"float\" || type(_e) == \"null\" || type(_e) == \"bool\" || type(_e) == \"string\") ? \"\" + _e : type(_e)\ntry {\n// Code Bricks assembly - seed 1680\n  global enum S1680_E1 { A, B, C }\n  let v0 = S1680_E1.A + S1680_E1.B + S1680_E1.C  // [enum_basic]\n  let v1_fn = function(x: int|float): int { return x.tointeger() }\n  let v1 = v1_fn(v0)  // [typed_union_param]\n  let v2_fn = function(x: int|null): int { return x != null ? x : -255 }\n  let v2 = v2_fn(v0)  // [typed_nullable_param]\n  let v3_fn = function(p0, p1) {\n    local u0 = 3\n    switch (v2 & 3) {\n      case 0: u0 = -65538; break\n      case 1: u0 = '9'; break\n      case 2: u0 = -4; break\n      default: u0 = 128\n    }  // [switch_int]\n    local u1_t = {arr = [2, null, {key = p1}]}\n    local u1_inner = u1_t?.arr?[2]\n    if (u1_inner != null) u1_inner.key += 9223372036854775807\n    let u1 = u1_t?.arr?[2]?.key ?? 129  // [nested_table_array_modify]\n    let u2 = [v1, p1]  // [array_of_ints]\n    let u3 = [p1, v1]  // [array_of_ints]\n    let {da = 0xFFFFFFFF, db = 127} = {da = u0}\n    let u4 = da + db  // [destruct_defaults]\n    let u5_fn = function([da, db]) { return da - db }\n    let u5 = u5_fn([v1, u4])  // [destruct_param_array]\n    let u6_Base = class {\n      function compute(x) { return x + 0xFF }\n    }\n    let u6_Der = class(u6_Base) {\n      function compute(x) { return base.compute(x) * -32770 }\n    }\n    let u6 = u6_Der().compute(u0)  // [class_method_override]\n    let u7 = $\"val={u1}\"  // [string_interp]\n    return u7\n  }\n  let v3 = v3_fn(v1, v0)  // [nested_func depth=1]\n  let v4_fn = function() {\n    local u0 = v1\n    u0++  // [postfix_inc]\n    let u1 = static({x = -2147483649, y = -32768})  // [static_table]\n    let u2 = v3.len() > 2 ? v3.slice(-2) : v3  // [string_slice_neg]\n    const u3 = -1  // [const_int]\n    local u4_val = 0\n    let u4_fn = function(x) { u4_val = u4_val + x }\n    local u4_i = 0\n    while (u4_i < 2) {\n      u4_fn(v0)\n      u4_i++\n    }\n    let u4 = u4_val  // [closure_in_loop]\n    let u5 = (function() {\n      let g = (function() {\n        for (local i = 0; i < 0; i++) yield i\n      })()\n      local s = 0\n      while (g.getstatus() == \"suspended\") {\n        s += resume g\n      }\n      return s\n    })()  // [coroutine_sum]\n    return u5\n  }\n  let v4 = v4_fn()  // [nested_func depth=1]\n  let v5_fn = function(...) {\n    local m = 257\n    foreach (v in vargv)\n      if (typeof v == \"integer\" && v > m) m = v\n    return m\n  }\n  let v5 = v5_fn(v2, v0)  // [vargv_max]\n  local v6 = v1\n  v6--  // [postfix_dec]\n  let v7_fn = function(p0, p1, p2) {\n    let {da = -65536, db = 0x8000} = {da = p2}\n    let u0 = da + db  // [destruct_defaults]\n    let u1 = array(p1 & 7, -2147483647)  // [array_function_init]\n    enum S1680_E2 { LOW = 0, MID = 50, HIGH = 100 }\n    local u2 = \"\"\n    if (v4 < S1680_E2.MID) u2 = \"low\"\n    else if (v4 < S1680_E2.HIGH) u2 = \"mid\"\n    else u2 = \"high\"  // [enum_compare_chain]\n    local u3 = p1\n    u3--  // [postfix_dec]\n    let u4_fn = function(q0, q1, q2) {\n      let w0 = u1.filter(@(v) v != null).map(@(v) v)  // [array_filter_map]\n      let w1_fn = function(x, ops = [@(v) v + -129, @(v) v * 2147483648, @(v) v - 0x7FFFFFFF]) {\n        local r = x\n        foreach (op in ops) r = op(r)\n        return r\n      }\n      let w1_a = w1_fn(v1)\n      let w1_b = w1_fn(v1, [@(v) v, @(v) v + -32770])\n      let w1 = w1_a + w1_b  // [default_param_array_of_fns]\n      let w2 = w0.indexof(p2) ?? 2147483648  // [array_indexof]\n      let w3_fn = function(x, opts = {f = @(v) v + -65538, scale = -256}) {\n        return opts.f(x) * opts.scale\n      }\n      let w3_a = w3_fn(w1)\n      let w3_b = w3_fn(w1, {f = @(v) v * -256, scale = -32769})\n      let w3 = w3_a + w3_b  // [default_param_fn_in_table]\n      let w4_fn = function(r0, r1) {\n        let z0 = v3 != r1  // [string_cmp_ne]\n        let z1 = u3 ^ v5  // [int_xor]\n        let z2 = q1 > v4  // [int_cmp_gt]\n        local z3 = 0\n        for (local z3_i = 8; z3_i > 0; z3_i--) {\n          z3 += p0\n        }  // [for_countdown]\n        return z3\n      }\n      let w4 = w4_fn(v0, u2)  // [nested_func depth=3]\n      return w4\n    }\n    let u4 = u4_fn(v6, p1, u2)  // [nested_func depth=2]\n    return u4\n  }\n  let v7 = v7_fn(v4, v2, v0)  // [nested_func depth=1]\n  let v8_fn = function(p0, p1, p2) {\n    let u0 = p1\n    assert(u0 >= 0 || u0 <= 0, \"value check\")  // [assert_msg]\n    let u1_t = {x = v7}\n    u1_t.x -= 65537\n    let u1 = u1_t.x  // [table_field_minuseq]\n    global enum S1680_E3 { A, B, C }\n    let u2 = S1680_E3.A + S1680_E3.B + S1680_E3.C  // [enum_basic]\n    let u3 = (((false ? ' ' : v7)).tofloat() != (((-129) >>> 1)).tofloat())  // [bool_literal]\n    let u4_outer = function(x) {\n      let inner = @(n) n * -256\n      return inner(x) + 0x8000\n    }\n    let u4 = u4_outer(u1)  // [nested_function]\n    local u5: int = p2  // [typed_int_var]\n    return u5\n  }\n  let v8 = v8_fn(v6, v2, v7)  // [nested_func depth=1]\n  let v9_C = class {\n    xv = 0\n    constructor(x) { this.xv = x }\n  }\n  let v9_arr = [v9_C(v5), v9_C(v5 + 1), v9_C(v5 + 2)]\n  let v9 = v9_arr[0].xv + v9_arr[1].xv + v9_arr[2].xv  // [class_array_of]\n  global enum S1680_E4 { A = \"\\u0100\", B = \"-1\" }\n  let v10 = $\"{S1680_E4.A}{S1680_E4.B}\"  // [enum_string]\n  let v11_fn = function(p0, p1, p2) {\n    let u0_a = [v9, v9 + 1]\n    u0_a.append(v9 * 2)\n    let u0 = u0_a.pop()  // [array_push_pop]\n    local u1 = v5\n    u1++  // [postfix_inc]\n    let u2 = array(v6 & 7, 0x7FFFFFFF)  // [array_function_init]\n    let u3 = v6 + p1  // [int_add]\n    let u4 = u2.len() > 0 ? u2.reduce(@(a, _b) a) : 0x1  // [array_reduce_lambda]\n    local u5_rows = [{v = v9}, null, {v = v9 + 1}, null, {v = '\\\\'}]\n    local u5 = 0\n    foreach (row in u5_rows) u5 += row?.v ?? 0  // [array_of_tables_nullable_sum]\n    let [u6_a, u6_b] = [u4, u4 + 1]\n    let [u6_c] = [u6_a + u6_b]\n    let u6 = u6_c  // [destruct_nested]\n    return u6\n  }\n  let v11 = v11_fn(v0, v2, v7)  // [nested_func depth=1]\n  let v12_fn = function(p0, p1, p2) {\n    let u0 = v9 + v7  // [int_add]\n    local u1 = p2\n    u1 /= p0  // [modify_div_int_unsafe]\n    let u2_fn = function(q0, q1) {\n      let w0 = v10.split(\"\\u0001\")  // [string_split]\n      let w1_base = {extra = 256, x = -256}\n      let w1_t = {x = v4}\n      let w1 = w1_t.rawget(\"x\") ?? w1_base.extra  // [table_setdelegate]\n      let w2 = u1 != 0 ? w1 % u1 : 65537  // [int_mod_safe]\n      local w3_ops = {\n        inc  = @(x) x + -130,\n        dec  = @(x) x - 257,\n        dbl  = @(x) x * 2\n      }\n      let w3_op = w3_ops?[v10]\n      let w3 = w3_op != null ? w3_op(v9) : v9  // [table_of_closures_dispatch]\n      local w4 = v9\n      w4 /= w2  // [modify_div_int_unsafe]\n      return w4\n    }\n    let u2 = u2_fn(v2, v3)  // [nested_func depth=2]\n    let u3_fn = function(q0, q1, q2) {\n      let w0 = u0 | v7  // [int_bitor]\n      let w1_Base = class { xv = 0; constructor(x) { this.xv = x } }\n      let w1_Der = class(w1_Base) { constructor(x) { base.constructor(x) } }\n      let w1_obj = w1_Der(q0)\n      let w1 = w1_obj instanceof w1_Base  // [class_instanceof_base]\n      let w2_t = {x = w0}\n      w2_t.x -= 9223372036854775807\n      let w2 = w2_t.x  // [table_field_minuseq]\n      let w3_C = class {\n        xv = 0\n        constructor(x) { this.xv = x }\n        function _unm() { return this.getclass()(-this.xv) }\n      }\n      let w3_r = -w3_C(v4)\n      let w3 = w3_r.xv  // [meta_unm]\n      let w4 = v0 < p0 ? v0 : p0  // [int_min_two]\n      return w4\n    }\n    let u3 = u3_fn(v6, v3, u0)  // [nested_func depth=2]\n    let u4_a = [u0]\n    u4_a[0] *= 2147483648\n    let u4 = u4_a[0]  // [array_elem_muleq]\n    let u5_fn = function(q0, q1) {\n      local w0_val = v2\n      let w0_set = function(x) { w0_val = x }\n      let w0_get = function() { return w0_val }\n      w0_set(v2 + 1)\n      let w0 = w0_get()  // [closure_getter_setter]\n      local w1 = 128\n      switch (v1 % 3) {\n        case 0: w1 = -2147483649; break\n        case 1: w1 = 65536; break\n        default: w1 = 2147483647; break\n      }  // [switch_default]\n      let w2_fn = function(r0, r1, r2) {\n        let z0_Base = class { xv = 0; constructor(x) { this.xv = x } }\n        let z0_Der = class(z0_Base) { constructor(x) { base.constructor(x) } }\n        let z0_obj = z0_Der(w1)\n        let z0 = z0_obj instanceof z0_Base  // [class_instanceof_base]\n        let z1_make = @(bv) @(x) x + bv\n        let z1_add = z1_make(u2)\n        let z1 = z1_add(-129)  // [func_returns_func]\n        let z2_fn = function(x, ops = [@(v) v + 4294967297, @(v) v * -4294967296, @(v) v - -3]) {\n          local r = x\n          foreach (op in ops) r = op(r)\n          return r\n        }\n        let z2_a = z2_fn(z1)\n        let z2_b = z2_fn(z1, [@(v) v, @(v) v + 2])\n        let z2 = z2_a + z2_b  // [default_param_array_of_fns]\n        return z2\n      }\n      let w2 = w2_fn(v2, w1, v1)  // [nested_func depth=3]\n      return w2\n    }\n    let u5 = u5_fn(v10, v4)  // [nested_func depth=2]\n    let u6_C = class {\n      xv = 0\n      constructor(x) { this.xv = x }\n      function _add(o) { return this.getclass()(this.xv + o.xv) }\n    }\n    let u6_r = u6_C(v5) + u6_C(u4)\n    let u6 = u6_r.xv  // [meta_add]\n    local u7 = v7\n    ++u7  // [prefix_inc]\n    return u7\n  }\n  let v12 = v12_fn(v6, v3, v2)  // [nested_func depth=1]\n  local v13 = v2\n  ++v13  // [prefix_inc]\n  let v14 = v3.startswith(v10)  // [string_startswith]\n  local v15_state = {scores = [v8, -2147483648, 4294967296], tag = \"\\u0001\"}\n  v15_state.scores[0] += 4294967295\n  v15_state.scores[2] = v15_state.scores[0] + v15_state.scores[1]\n  let v15 = v15_state.scores.reduce(@(a, v) a + v, 0)  // [table_slot_array_modify]\n  let v16 = (function() {\n    let g = (function() {\n      for (local i = 0; i < 2; i++) yield i\n    })()\n    local s = 0\n    while (g.getstatus() == \"suspended\") {\n      s += resume g\n    }\n    return s\n  })()  // [coroutine_sum]\n  let v17 = v7 * v5  // [int_mul]\n  let v18_fn = function() {\n    const u0 = true  // [const_bool]\n    let u1 = v10.len() > 2 ? v10.slice(-2) : v10  // [string_slice_neg]\n    local u2_sum = 0\n    let u2_add = function(x) { u2_sum = u2_sum + x }\n    u2_add(v7)\n    u2_add(v16)\n    u2_add(v7 + v16)\n    let u2 = u2_sum  // [closure_accumulator]\n    let u3_fns = [@(x) x + 32769, @(x) x * 0, @(x) x - -65536]\n    local u3 = v15\n    foreach (f in u3_fns) u3 = f(u3)  // [array_of_closures_accumulate]\n    let u4 = -v9  // [int_neg]\n    return u4\n  }\n  let v18 = v18_fn()  // [nested_func depth=1]\n  let v19_fn = function(p0, p1) {\n    local u0 = -129\n    try { u0 = v3.tointeger() } catch (_e) {}  // [string_tointeger]\n    let u1_fn = @[pure, nodiscard] (a, b) a + b\n    let u1 = u1_fn(p1, v1)  // [func_pure_nodiscard]\n    let u2_fn = function(q0, q1, q2) {\n      local w0_ops = {\n        inc  = @(x) x + -65538,\n        dec  = @(x) x - 2147483649,\n        dbl  = @(x) x * 2\n      }\n      let w0_op = w0_ops?[q2]\n      let w0 = w0_op != null ? w0_op(v11) : v11  // [table_of_closures_dispatch]\n      let w1 = p0.replace(\";\", \"\\\\\")  // [string_replace]\n      let w2_make = @(bv) @(x) x + bv\n      let w2_add = w2_make(u0)\n      let w2 = w2_add(-65537)  // [func_returns_func]\n      local w3_store = {pages = [{lines = [0x8000, -32767]}, {lines = [-1, -9223372036854775807]}]}\n      w3_store.pages[0].lines[1] += w0\n      let w3 = w3_store?.pages?[0]?.lines?[1] ?? -129  // [nested_db_array_field]\n      let w4_t = freeze({x = v1, y = -32769})\n      let w4 = w4_t.x + w4_t.y  // [freeze_nested]\n      return w4\n    }\n    let u2 = u2_fn(p1, v4, p0)  // [nested_func depth=2]\n    let u3 = v18 / v17  // [int_div_unsafe]\n    let u4 = [p0, v3, \" \"]  // [array_of_strings]\n    let u5 = v3.tofloat()  // [string_tofloat]\n    local u6 = v6\n    u6 += u1\n    u6 -= u0\n    u6 *= -4  // [modify_chain]\n    return u6\n  }\n  let v19 = v19_fn(v3, v15)  // [nested_func depth=1]\n  let v20 = v15 > 0 ? 1 : (v15 < 0 ? -1 : 0)  // [int_sign]\n  let v21 = v10.len() > 4 ? v10.slice(1, 3) : v10  // [string_slice_both]\n  let v22_fn = function(x, opts = {f = @(v) v + 65537, scale = 257}) {\n    return opts.f(x) * opts.scale\n  }\n  let v22_a = v22_fn(v2)\n  let v22_b = v22_fn(v2, {f = @(v) v * 4294967297, scale = -65535})\n  let v22 = v22_a + v22_b  // [default_param_fn_in_table]\n  let v23_fn = @(a: int, b: int) a * b\n  let v23 = v23_fn(v16, v5)  // [typed_lambda]\n  let v24_fn = function() {\n    local u0 = 0\n    for (local u0_i = 0; u0_i < -1; u0_i++) {\n      u0 = u0 + v12\n    }  // [for_sum]\n    let u1 = typeof v3 == \"string\"  // [typeof_string_check]\n    let u2 = [v1, u0]  // [array_of_ints]\n    local u3 = u0\n    u3++  // [postfix_inc]\n    let u4_fn = function(...) {\n      local s = 0\n      foreach (v in vargv) s += v\n      return s\n    }\n    let u4 = u4_fn(v16, v7, 2)  // [vargv_sum]\n    return u4\n  }\n  let v24 = v24_fn()  // [nested_func depth=1]\n  let v25_fn = function(x, s, cfg = {\n      fmt = @(n, t) $\"{n}:{t}\",\n      limits = {lo = 0xFFFF, hi = -256}\n    }) {\n    local clamped = x < cfg.limits.lo ? cfg.limits.lo\n                  : x > cfg.limits.hi ? cfg.limits.hi : x\n    return cfg.fmt(clamped, s)\n  }\n  let v25 = v25_fn(v16, v3)  // [default_param_config_nested]\n  let v26_fn = function(x: int|float): int { return x.tointeger() }\n  let v26 = v26_fn(v12)  // [typed_union_param]\n  let v27_fn = function(p0, p1, p2) {\n    local u0_ops = {\n      inc  = @(x) x + -65536,\n      dec  = @(x) x - 257,\n      dbl  = @(x) x * 2\n    }\n    let u0_op = u0_ops?[v25]\n    let u0 = u0_op != null ? u0_op(v11) : v11  // [table_of_closures_dispatch]\n    let u1 = ((0xFF).tofloat()).tointeger()  // [int_literal]\n    let u2_C = class {\n      xv = 0\n      constructor(x) { this.xv = x }\n      function _cmp(o) { return this.xv <=> o.xv }\n    }\n    let u2 = u2_C(v13) < u2_C(p1)  // [meta_cmp]\n    let u3 = [-4294967295, -256, -2147483648]\n    u3.insert(1, v6)\n    u3.remove(0)  // [array_insert_remove]\n    let u4_fn = function({da, db = \"\\\\\\\\\"}) {\n      return $\"{_sv(da)}{_sv(db)}\"\n    }\n    let u4 = u4_fn({da = v19, db = v21})  // [destruct_param_nested_table]\n    return u4\n  }\n  let v27 = v27_fn(v16, v20, v15)  // [nested_func depth=1]\n  let v28 = v19 >= 0 ? v19 : -v19  // [int_abs_ternary]\n  let v29 = $\"flag={v14}\"  // [string_interp_bool]\n  let v30_C = class {\n    _v = 0\n    constructor(xv) { this._v = xv }\n  }\n  let v30_obj = v30_C(v9)\n  let v30 = v30_obj instanceof v30_C  // [instanceof_check]\n  enum S1680_E5 { A, B, C }\n  let v31 = S1680_E5.A + S1680_E5.B + S1680_E5.C  // [enum_basic]\n  let v32_a = [v6, v22, -4294967297]\n  let v32 = v32_a.top()  // [array_top]\n  local v33_val = v7\n  let v33_set = function(x) { v33_val = x }\n  let v33_get = function() { return v33_val }\n  v33_set(v7 + 0xCAFE)\n  let v33 = v33_get()  // [closure_getter_setter]\n  let v34_fn = function([da, db = 0xFFFF]) { return da * db }\n  let v34 = v34_fn([v19])  // [destruct_param_array_default]\n  let v35 = v3.len()  // [string_len]\n  let v36_C = class {\n    xv = 0\n    constructor(x) { this.xv = x }\n    function _mul(o) { return this.getclass()(this.xv * o.xv) }\n  }\n  let v36_r = v36_C(v20) * v36_C(v6)\n  let v36 = v36_r.xv  // [meta_mul]\n  let v37 = [v25, v29, \"\"]  // [array_of_strings]\n  let v38 = \"{0}+{1}\".subst(v29, \"hello\")  // [string_subst]\n  let v39_fn = function(p0, p1, p2) {\n    let u0 = v25.startswith(v3)  // [string_startswith]\n    local u1 = v2\n    if (v20 != 0) u1 %= v20  // [modify_mod_int_safe]\n    let u2_C = class {\n      _n = 0\n      constructor(n) { this._n = n & 7 }\n      function _nexti(idx) {\n        local next = idx == null ? 0 : idx + 1\n        return next < this._n ? next : null\n      }\n      function _get(idx) { return idx * 255 }\n    }\n    let u2_obj = u2_C(v1)\n    local u2 = 0\n    foreach (_i, v in u2_obj) u2 += v  // [meta_nexti]\n    let u3 = v36 << 3  // [int_shl]\n    local u4 = 4294967297\n    foreach (v in v37) {\n      if (typeof v == \"integer\") { u4 = v; break }\n    }  // [foreach_array_break]\n    return u4\n  }\n  let v39 = v39_fn(v18, v15, v25)  // [nested_func depth=1]\n  let v40_fn = function(x,\n      cls = class { function calc(v) { return v + 128 } }) {\n    return cls().calc(x)\n  }\n  let v40_a = v40_fn(v32)\n  let v40_other = class { function calc(v) { return v * 9223372036854775807 } }\n  let v40_b = v40_fn(v32, v40_other)\n  let v40 = v40_a + v40_b  // [default_param_class]\n  let v41_Base = class {\n    function compute(x) { return x + -127 }\n  }\n  let v41_Der = class(v41_Base) {\n    function compute(x) { return base.compute(x) * 2 }\n  }\n  let v41 = v41_Der().compute(v23)  // [class_method_override]\n  local v42_ops = {\n    inc  = @(x) x + ' ',\n    dec  = @(x) x - 42,\n    dbl  = @(x) x * 2\n  }\n  let v42_op = v42_ops?[v29]\n  let v42 = v42_op != null ? v42_op(v1) : v1  // [table_of_closures_dispatch]\n  let v43 = v34 + v5  // [int_add]\n  let v44 = v14 && v30  // [bool_and]\n  let v45 = null  // [null_var]\n  let v46_fn = function(p0, p1) {\n    let u0 = v3.tolower()  // [string_tolower]\n    local u1 = \"\"\n    switch (v31 <=> -128) {\n      case -1: u1 = \"less\"; break\n      case 0: u1 = \"equal\"; break\n      case 1: u1 = \"greater\"; break\n      default: u1 = \"other\"\n    }  // [switch_three_way]\n    let u2_fn = function() {\n      let w0_fn = function(x, pipe = {pre = @(v) v & 0xFF,\n                                       run = @(v) v + 32767,\n                                       post = @(v) v * -257}) {\n        return pipe.post(pipe.run(pipe.pre(x)))\n      }\n      let w0 = w0_fn(p0)  // [default_param_pipeline]\n      let w1 = [v3, v21, \"\\t\\n\\r\"]  // [array_of_strings]\n      let w2_fn = function(x, pipe = {pre = @(v) v & 0xFF,\n                                       run = @(v) v + -257,\n                                       post = @(v) v * 2}) {\n        return pipe.post(pipe.run(pipe.pre(x)))\n      }\n      let w2 = w2_fn(v13)  // [default_param_pipeline]\n      let w3 = v44 || v30  // [bool_or]\n      local w4_items = [{k = \".\", v = -65536},\n                         {k = \"\\t\\n\\r\", v = 0x8000},\n                         {k = \"\\r\\n\", v = v41}]\n      foreach (item in w4_items)\n        if (item.v > -32770) item.v *= 2147483648\n      local w4 = 0\n      foreach (item in w4_items) w4 += item.v  // [foreach_array_tables_modify]\n      return w4\n    }\n    let u2 = u2_fn()  // [nested_func depth=2]\n    let u3_fn = function() {\n      const w0 = false  // [const_bool]\n      const function [pure] w1_fn(x) { return x + 0xFF }\n      const w1_a = -2147483649\n      const w1 = w1_fn(w1_a)  // [const_chain]\n      let w2 = [-4, -4294967296, 128]\n      w2.insert(1, v20)\n      w2.remove(0)  // [array_insert_remove]\n      let w3 = v39.tofloat()  // [int_to_float]\n      let w4_inner = function(...) {\n        local s = 0\n        foreach (v in vargv) s += v\n        return s\n      }\n      let w4_outer = function(a, ...) { return a + w4_inner(vargv.len(), a) }\n      let w4 = w4_outer(p0, v2)  // [vargv_forward]\n      let w5 = v45 && p0  // [logical_and_val]\n      return w5\n    }\n    let u3 = u3_fn()  // [nested_func depth=2]\n    return u3\n  }\n  let v46 = v46_fn(v35, v20)  // [nested_func depth=1]\n  let v47_fn = function(a, b,\n      combine = {op = @(x, y) x + y, identity = -65535}) {\n    return combine.op(a, b) + combine.identity\n  }\n  let v47_add = v47_fn(v42, v20)\n  let v47_mul = v47_fn(v42, v20,\n    {op = @(x, y) x * y, identity = 1000})\n  let v47 = v47_add + v47_mul  // [default_param_fn_field_call]\n  local v48_cfg = {a = {val = v32 + -256}, b = {val = v32 - 257}}\n  let v48 = v44 ? (v48_cfg?.a?.val ?? 2147483648) : (v48_cfg?.b?.val ?? 1000)  // [conditional_deep_path]\n  let v49 = \",\".join(v37.map(@(v) $\"{_sv(v)}\"))  // [string_join]\n  let v50 = v3.toupper()  // [string_toupper]\n  let v51_tbl = {a = v6, b = v26}\n  let v51 = v51_tbl.a + v51_tbl.b  // [destruct_table]\n  let v52_C = class {\n    _v = 0\n    constructor(xv) { this._v = xv }\n    function _call(_env, arg) { return this._v + arg }\n  }\n  let v52_obj = v52_C(v43)\n  let v52 = v52_obj(-65536)  // [meta_call]\n  let v53 = v13 >= v23  // [int_cmp_ge]\n  local v54 = 0\n  local v54_i = 0\n  while (v54_i < -1) {\n    v54_i++\n    if (v54_i % 2 == 0) continue\n    v54 += v33\n  }  // [while_continue_skip]\n  local v55 = v4\n  v55 /= v12  // [modify_div_int_unsafe]\n  enum S1680_E6 { X = -32769, Y = 32767, Z = 2147483649 }\n  let v56 = S1680_E6.X + S1680_E6.Y + S1680_E6.Z  // [enum_explicit]\n  let v57 = v3.len() > 4 ? v3.slice(1, 3) : v3  // [string_slice_both]\n  let v58_fn = function(p0, p1, p2) {\n    local u0_a = (v56 & 0xFFFF) + 1\n    local u0_b = (v31 & 0xFFFF) + 1\n    while (u0_b != 0) {\n      local u0_tmp = u0_b\n      u0_b = u0_a % u0_b\n      u0_a = u0_tmp\n    }\n    let u0 = u0_a  // [int_gcd]\n    let u1 = v29.split_by_chars(\"\\n\")  // [string_split_by_chars]\n    let u2 = clone v37\n    u2.replace_with(v37.map(@(v) v))  // [array_replace_with]\n    return u0\n  }\n  let v58 = v58_fn(v54, v47, v28)  // [nested_func depth=1]\n  let v59 = v37?[-4294967298] ?? 0x7FFFFFFF  // [nullsafe_array_index]\n  local v60 = v1\n  ++v60  // [prefix_inc]\n  local v61_sum = 0\n  let v61_add = function(x) { v61_sum = v61_sum + x }\n  v61_add(v28)\n  v61_add(v12)\n  v61_add(v28 + v12)\n  let v61 = v61_sum  // [closure_accumulator]\n  let v62_v = v33 & 0xFFFF\n  let v62 = v62_v > 0 && (v62_v & (v62_v - 1)) == 0  // [int_pow2_check]\n  let v63_fn = function(x, acc = []) {\n    acc.append(x)\n    return acc.len()\n  }\n  let v63_a = v63_fn(v22)\n  let v63_b = v63_fn(v22 + 1)\n  let v63 = v63_a + v63_b  // [default_param_mutable_shared]\n  local v64 = -9223372036854775807\n  for (local v64_i = 0; v64_i < 2; v64_i++) {\n    v64 += v41\n  }  // [modify_in_loop]\n  let v65_fn = function(p0, p1, p2) {\n    let u0_fn = function({da, db = \"true\"}) {\n      return $\"{_sv(da)}{_sv(db)}\"\n    }\n    let u0 = u0_fn({da = v64, db = v49})  // [destruct_param_nested_table]\n    let u1_f = @(x) x * -4\n    let u1_g = @(x) x + 2147483648\n    let u1 = u1_f(u1_g(v1))  // [func_compose]\n    let u2_lo = -2\n    let u2_hi = u2_lo + 256\n    let u2 = v32 < u2_lo ? u2_lo : (v32 > u2_hi ? u2_hi : v32)  // [int_clamp]\n    let u3_C = class {\n      _v = 0\n      constructor(xv) { this._v = xv }\n      function _call(_env, arg) { return this._v + arg }\n    }\n    let u3_obj = u3_C(v26)\n    let u3 = u3_obj(2147483647)  // [meta_call]\n    local u4 = p2 & 7\n    do {\n      u4--\n    } while (u4 > 0)  // [do_while_dec]\n    let u5_fn = function(q0, q1) {\n      let w0 = q0.len()  // [string_len]\n      let w1_fn = function({da, db = \" \"}) {\n        return $\"{_sv(da)}{_sv(db)}\"\n      }\n      let w1 = w1_fn({da = v55, db = v21})  // [destruct_param_nested_table]\n      let w2_fn = function(r0, r1, r2) {\n        let z0_fn = @[nodiscard] (x) x + -129\n        let z0 = z0_fn(p2)  // [func_nodiscard]\n        let z1_f = @(x) x * -258\n        let z1_g = @(x) x + 0x80000000\n        let z1 = z1_f(z1_g(v1))  // [func_compose]\n        local z2 = 0\n        foreach (idx, v in v37) {\n          if (idx % 2 != 0) continue\n          if (typeof v == \"integer\") z2 += v\n        }  // [foreach_array_continue]\n        return z2\n      }\n      let w2 = w2_fn(v40, v2, v33)  // [nested_func depth=3]\n      let w3 = v64 <= v17  // [int_cmp_le]\n      let w4_C = class {\n        xv = 0\n        constructor(x) { this.xv = x }\n        function _typeof() { return \"mytype\" }\n      }\n      let w4 = typeof w4_C(v32)  // [meta_typeof]\n      let w5 = q0.endswith(v3)  // [string_endswith]\n      return w5\n    }\n    let u5 = u5_fn(v27, v26)  // [nested_func depth=2]\n    let u6 = (1e-40 * (-2.5))  // [float_literal]\n    let u7 = u6 + v1.tofloat()  // [float_add_int]\n    return u7\n  }\n  let v65 = v65_fn(v24, v13, v9)  // [nested_func depth=1]\n  let v66 = clone v37\n  v66.replace_with(v37.map(@(v) v))  // [array_replace_with]\n  let v67_C = class {\n    _n = 0\n    constructor(n) { this._n = n & 7 }\n    function _nexti(idx) {\n      local next = idx == null ? 0 : idx + 1\n      return next < this._n ? next : null\n    }\n    function _get(idx) { return idx * 2147483647 }\n  }\n  let v67_obj = v67_C(v17)\n  local v67 = 0\n  foreach (_i, v in v67_obj) v67 += v  // [meta_nexti]\n  let v68_fn = function(x, ops = [@(v) v + -65537, @(v) v * 2, @(v) v - -4294967296]) {\n    local r = x\n    foreach (op in ops) r = op(r)\n    return r\n  }\n  let v68_a = v68_fn(v43)\n  let v68_b = v68_fn(v43, [@(v) v, @(v) v + -257])\n  let v68 = v68_a + v68_b  // [default_param_array_of_fns]\n  let v69_fn = function({dx, dy = 0}, [da, db]) {\n    return dx + dy + da + db\n  }\n  let v69 = v69_fn({dx = v11}, [v33, v55])  // [destruct_param_mixed]\n  let v70_fn = function(x, ctx = {\n      cls = class { v = 0; constructor(n) { this.v = n } },\n      wrap = @(inst) inst.v + 0\n    }) {\n    return ctx.wrap(ctx.cls(x))\n  }\n  let v70 = v70_fn(v40)  // [default_param_table_class]\n  let v71_inner = function(...) {\n    local s = 0\n    foreach (v in vargv) s += v\n    return s\n  }\n  let v71_outer = function(a, ...) { return a + v71_inner(vargv.len(), a) }\n  let v71 = v71_outer(v45, v58)  // [vargv_forward]\n  let v72 = v2 != 0 ? v45 / v2 : -4294967298  // [int_div_safe]\n  let v73 = null  // [null_var]\n  let v74 = (@(x) -x)(v55)  // [lambda_negate]\n  function [nodiscard] v75_fn(x) { return x + 32768 }\n  let v75 = v75_fn(v7)  // [named_func_nodiscard]\n  let v76_fn = function() {\n    let u0_fn = function(x, ops = [@(v) v + 0, @(v) v * 32768, @(v) v - -1]) {\n      local r = x\n      foreach (op in ops) r = op(r)\n      return r\n    }\n    let u0_a = u0_fn(v31)\n    let u0_b = u0_fn(v31, [@(v) v, @(v) v + 1])\n    let u0 = u0_a + u0_b  // [default_param_array_of_fns]\n    let u1_fn = function(a: int, b: int): int { return a + b }\n    let u1 = u1_fn(v17, v13)  // [typed_function_params]\n    local u2 = -4294967295\n    if (v62) {\n      u2 = u2 + v51\n      u2 = u2 + -2147483650\n    }  // [if_accum]\n    let u3_fn = function(x, opts = {f = @(v) v + 'Z', scale = 65536}) {\n      return opts.f(x) * opts.scale\n    }\n    let u3_a = u3_fn(u2)\n    let u3_b = u3_fn(u2, {f = @(v) v * -129, scale = 0})\n    let u3 = u3_a + u3_b  // [default_param_fn_in_table]\n    return u3\n  }\n  let v76 = v76_fn()  // [nested_func depth=1]\n  local v77 = v29\n  v77 += v50  // [modify_string_concat]\n  let v78 = v30 ? v60 : v8  // [ternary_int]\n  let v79_t = freeze({x = v42, y = 32768})\n  let v79 = v79_t.x + v79_t.y  // [freeze_nested]\n  let v80 = v10.lstrip()  // [string_lstrip]\n  let v81_fn = function(p0) {\n    local u0: float = v65  // [typed_float_var]\n    local u1 = 0\n    switch (v31 & 3) {\n      case 0:\n      case 1: u1 = -32770; break\n      case 2: u1 = 255; break\n      default: u1 = -255\n    }  // [switch_fallthrough]\n    let u2 = typeof v58 == \"integer\"  // [typeof_int_check]\n    local u3 = 0\n    foreach (_c in v21) u3++  // [foreach_string_chars]\n    return u3\n  }\n  let v81 = v81_fn(v61)  // [nested_func depth=1]\n  local v82 = v45\n  v82 += v54\n  v82 -= v78\n  v82 *= -258  // [modify_chain]\n  let v83 = v69 <= v54  // [int_cmp_le]\n  let v84_C = class {\n    _v = 0\n    constructor(xv) { this._v = xv }\n    function _call(_env, arg) { return this._v + arg }\n  }\n  let v84_obj = v84_C(v68)\n  let v84 = v84_obj('9')  // [meta_call]\n  local v85_items = [{k = \"\\r\\n\", v = 0xFF},\n                     {k = @\"raw_string\", v = -128},\n                     {k = \"test\", v = v73}]\n  foreach (item in v85_items)\n    if (item.v > 0x8000) item.v *= 2147483649\n  local v85 = 0\n  foreach (item in v85_items) v85 += item.v  // [foreach_array_tables_modify]\n  let v86 = v82 | v39  // [int_bitor]\n  local v87 = v0\n  v87 += -2  // [modify_add_const]\n  let v88_C = class {\n    _bv = 0\n    constructor(xb) { this._bv = xb }\n    function _get(idx) { return this._bv + idx }\n  }\n  let v88_obj = v88_C(v64)\n  let v88 = v88_obj[0xDEADBEEF]  // [meta_get]\n  let v89_fn = function({da, db}) { return da + db }\n  let v89 = v89_fn({da = v26, db = v28})  // [destruct_param_table]\n  let v90 = v53 ? v50 : v77  // [ternary_str]\n  let v91_fn = function([da, db = -1]) { return da * db }\n  let v91 = v91_fn([v60])  // [destruct_param_array_default]\n  let v92 = v37.findindex(@(val) val != null) ?? -2147483649  // [array_findindex]\n  let v93_fn = function(a, b = -4294967297) { return a + b }\n  let v93 = v93_fn(v84)  // [default_param_one]\n  let v94_C = class {\n    xv = 0\n    constructor(x) { this.xv = x }\n    function _cmp(o) { return this.xv <=> o.xv }\n  }\n  let v94 = v94_C(v32) < v94_C(v15)  // [meta_cmp]\n  let v95 = v61 < v48  // [int_cmp_lt]\n  local v96 = 0\n  for (local v96_i = 0; v96_i < 0; v96_i++) {\n    v96 = v96 + v47\n  }  // [for_sum]\n  local v97 = false\n  try { v97 = v28 == v20 } catch (_e) {}  // [any_cmp_eq]\n  local v98_items = [1000, null, {fn = @(x) x * -65535, tag = \"\\uffff\"}, null]\n  let v98_entry = v98_items?[2]\n  let v98 = v98_entry != null ? v98_entry.fn(v26) : 0x100  // [mixed_array_fn_call]\n  let v99_C = class {\n    _items = []\n    function add(x) { this._items.append(x) }\n    function sum() {\n      local s = 0\n      foreach (v in this._items) s += v\n      return s\n    }\n  }\n  let v99_obj = v99_C()\n  v99_obj.add(v6)\n  v99_obj.add(v6 + 1)\n  let v99 = v99_obj.sum()  // [class_with_array]\n  let v100 = (function() {\n    let g = (function() {\n      for (local i = 0; i < 7; i++) yield i\n    })()\n    local s = 0\n    while (g.getstatus() == \"suspended\") {\n      s += resume g\n    }\n    return s\n  })()  // [coroutine_sum]\n  let v101 = v80.endswith(v10)  // [string_endswith]\n  let v102 = v53.tostring()  // [bool_to_string]\n  let v103_fn = function(x, s, cfg = {\n      fmt = @(n, t) $\"{n}:{t}\",\n      limits = {lo = 32769, hi = 32768}\n    }) {\n    local clamped = x < cfg.limits.lo ? cfg.limits.lo\n                  : x > cfg.limits.hi ? cfg.limits.hi : x\n    return cfg.fmt(clamped, s)\n  }\n  let v103 = v103_fn(v8, v50)  // [default_param_config_nested]\n  let v104 = (((-129) + (-130))).tofloat()  // [float_literal]\n\n  // --- dump pool ---\n  function _prn_t(_t) { let _a = []; _t.each(function(_k, _v) { _a.append(_sv(_k)); _a.append(_sv(_v)) }); _a.sort(); foreach (i, _v in _a) { if (i >= 10) { print(\"...\"); break }; if (i > 0) print(\", \"); print(_v) }; }\n  function _prn_a(_a) { foreach (i, _v in _a) { if (i >= 10) { print(\"...\"); break }; if (i > 0) print(\", \"); print(_v) }; }\n  print($\"v0={v0}\\n\")\n  print($\"v1={v1}\\n\")\n  print($\"v2={v2}\\n\")\n  print($\"v3={v3}\\n\")\n  print($\"v4={v4}\\n\")\n  print($\"v5={v5}\\n\")\n  print($\"v6={v6}\\n\")\n  print($\"v7={v7}\\n\")\n  print($\"v8={v8}\\n\")\n  print($\"v9={v9}\\n\")\n  print($\"v10={v10}\\n\")\n  print($\"v11={v11}\\n\")\n  print($\"v12={v12}\\n\")\n  print($\"v13={v13}\\n\")\n  print($\"v14={v14}\\n\")\n  print($\"v15={v15}\\n\")\n  print($\"v16={v16}\\n\")\n  print($\"v17={v17}\\n\")\n  print($\"v18={v18}\\n\")\n  print($\"v19={v19}\\n\")\n  print($\"v20={v20}\\n\")\n  print($\"v21={v21}\\n\")\n  print($\"v22={v22}\\n\")\n  print($\"v23={v23}\\n\")\n  print($\"v24={v24}\\n\")\n  print($\"v25={v25}\\n\")\n  print($\"v26={v26}\\n\")\n  print($\"v27={v27}\\n\")\n  print($\"v28={v28}\\n\")\n  print($\"v29={v29}\\n\")\n  print($\"v30={v30}\\n\")\n  print($\"v31={v31}\\n\")\n  print($\"v32={v32}\\n\")\n  print($\"v33={v33}\\n\")\n  print($\"v34={v34}\\n\")\n  print($\"v35={v35}\\n\")\n  print($\"v36={v36}\\n\")\n  print(\"v37=[\"); _prn_a(v37); print(\"]\\n\")\n  print($\"v38={v38}\\n\")\n  print($\"v39={v39}\\n\")\n  print($\"v40={v40}\\n\")\n  print($\"v41={v41}\\n\")\n  print($\"v42={v42}\\n\")\n  print($\"v43={v43}\\n\")\n  print($\"v44={v44}\\n\")\n  print($\"v45={v45}\\n\")\n  print($\"v46={v46}\\n\")\n  print($\"v47={v47}\\n\")\n  print($\"v48={v48}\\n\")\n  print($\"v49={v49}\\n\")\n  print($\"v50={v50}\\n\")\n  print($\"v51={v51}\\n\")\n  print($\"v52={v52}\\n\")\n  print($\"v53={v53}\\n\")\n  print($\"v54={v54}\\n\")\n  print($\"v55={v55}\\n\")\n  print($\"v56={v56}\\n\")\n  print($\"v57={v57}\\n\")\n  print($\"v58={v58}\\n\")\n  print($\"v59={v59}\\n\")\n  print($\"v60={v60}\\n\")\n  print($\"v61={v61}\\n\")\n  print($\"v62={v62}\\n\")\n  print($\"v63={v63}\\n\")\n  print($\"v64={v64}\\n\")\n  print($\"v65={v65}\\n\")\n  print(\"v66=[\"); _prn_a(v66); print(\"]\\n\")\n  print($\"v67={v67}\\n\")\n  print($\"v68={v68}\\n\")\n  print($\"v69={v69}\\n\")\n  print($\"v70={v70}\\n\")\n  print($\"v71={v71}\\n\")\n  print($\"v72={v72}\\n\")\n  print($\"v73={v73}\\n\")\n  print($\"v74={v74}\\n\")\n  print($\"v75={v75}\\n\")\n  print($\"v76={v76}\\n\")\n  print($\"v77={v77}\\n\")\n  print($\"v78={v78}\\n\")\n  print($\"v79={v79}\\n\")\n  print($\"v80={v80}\\n\")\n  print($\"v81={v81}\\n\")\n  print($\"v82={v82}\\n\")\n  print($\"v83={v83}\\n\")\n  print($\"v84={v84}\\n\")\n  print($\"v85={v85}\\n\")\n  print($\"v86={v86}\\n\")\n  print($\"v87={v87}\\n\")\n  print($\"v88={v88}\\n\")\n  print($\"v89={v89}\\n\")\n  print($\"v90={v90}\\n\")\n  print($\"v91={v91}\\n\")\n  print($\"v92={v92}\\n\")\n  print($\"v93={v93}\\n\")\n  print($\"v94={v94}\\n\")\n  print($\"v95={v95}\\n\")\n  print($\"v96={v96}\\n\")\n  print($\"v97={v97}\\n\")\n  print($\"v98={v98}\\n\")\n  print($\"v99={v99}\\n\")\n  print($\"v100={v100}\\n\")\n  print($\"v101={v101}\\n\")\n  print($\"v102={v102}\\n\")\n  print($\"v103={v103}\\n\")\n  print($\"v104={v104}\\n\")\n} catch(e) { print(e) }\nprint(\"===\\n\")\n"
  },
  {
    "path": "testData/exec/weird/many_locals.out",
    "content": "division by zero===\n"
  },
  {
    "path": "testData/proposed_optimizations/clone_newslot_vs_merge.nut",
    "content": "/*\n\nProposed optimization: replace t.__merge({small literal table}) with\nclone + newslot sequence, avoiding temporary table allocation.\n\nPattern:\n  local r = t.__merge({y = 5, f = 5.3})\n\nCan be optimized to:\n  local r = clone t\n  r.y <- 5\n  r.f <- 5.3\n\nThis is faster because __merge allocates a temporary table literal\non every call, while clone + newslot avoids that overhead.\n\n*/\n\nlet {clock} = require(\"datetime\")\n\nfunction profile_it(cnt, f) {\n  local res = 0\n  for (local i = 0; i < cnt; ++i) {\n    let start = clock()\n    f()\n    let measured = clock() - start\n    if (i == 0 || measured < res)\n      res = measured\n  }\n  return res / 1.0\n}\n\nlet t = { x = 4, z = 5, u = 123 }\n\nfunction test_clone_newslot() {\n  local cnt = 1000000\n  local r = null\n  while (--cnt) {\n    r = clone t\n    r.y <- 5\n    r.f <- 5.3\n  }\n  return r\n}\n\nfunction test_merge() {\n  local cnt = 1000000\n  local r = null\n  while (--cnt) {\n    r = t.__merge({y = 5, f = 5.3})\n  }\n  return r\n}\n\nlet a = test_clone_newslot()\nlet b = test_merge()\nassert(a.x == b.x && a.z == b.z && a.u == b.u && a.y == b.y && a.f == b.f)\n\nconst numTests = 10\nlet profile = @(name, func) println(\"\".concat(name, \", \", profile_it(numTests, func), $\", {numTests}\"))\n\nprofile(\"\\\"clone_newslot\\\"\", test_clone_newslot)\nprofile(\"\\\"merge\\\"\", test_merge)\n"
  },
  {
    "path": "testData/proposed_optimizations/filter_map_folding.nut",
    "content": "/*\n\nThis test shows that it is possible to optimize map().filter().map().each() into loop\nWhich is faster\n\n*/\n\nlet {clock} = require(\"datetime\")\n\nfunction profile_it(cnt, f) {//for quirrel version\n  local res = 0\n  for (local i = 0; i < cnt; ++i) {\n    let start = clock()\n    f()\n    let measured = clock() - start\n    if (i == 0 || measured < res)\n      res = measured\n  }\n  return res / 1.0\n}\n\n//prepare testdata\nlet testdata = freeze(array(17*120005).reduce(function(a, _, i) { a[i]<-{key = i}; return a;}, {}))\nfunction log(d){\n  foreach(k, v in d)\n    println($\"{k} = {v}\")\n}\n\n\n// 'classic' functional code\nlet test_filterampreduce = @() testdata\n  .map(@(v) v.key) //extract func\n  .filter(@(r) r%17==0) //filter func\n  .map(@(r, i) (r*1000-i)/30)\n  .reduce(@(res, v) res+(v%2==0 ? 1 : -1)*v, 0) //reduce func\n\n// 'fully unrolled' functional code. can be theoritically done for function that are declared inplace, like code above\nfunction test_loop_max() {\n  local res = 0\n  foreach (i, v in testdata) {\n    local r = v.key\n    if (r%17 != 0)\n      continue\n    r = (r*1000 - i)/30\n    res += (r%2==0 ? 1 : -1)*r\n  }\n  return res\n}\n\n// 'partially unrolled' functional code (can be use for any functions used in map\\filter\\reduce\\each hidden loops)\nfunction test_loop_func() {\n  local res = 0\n  let extract = @(v) v.key\n  let filter = @(v) v%17==0\n  let map2 = @(v, i) (v*1000-i)/30\n  let reduce = @(res, v) res+(v%2==0 ? 1 : -1)*v\n  foreach (i, v in testdata) {\n    local r = extract(v)\n    if (!filter(r))\n      continue\n    r = map2(r, i)\n    res = reduce(res, r)\n  }\n  return res\n}\nconst numTests = 20\nlet profile = @(name, func) println(\"\".concat(name, \", \", profile_it(numTests, func), $\", {numTests}\"))\n\nassert(test_filterampreduce() == test_loop_max() && test_filterampreduce() == test_loop_func())\nprofile(\"\\\"map_filter_map_reduce\\\"\", test_filterampreduce)\nprofile(\"\\\"test_loop_max\\\"\", test_loop_max)\nprofile(\"\\\"test_loop_func\\\"\", test_loop_func)\n"
  },
  {
    "path": "testData/proposed_optimizations/filter_map_folding2.nut",
    "content": "/*\n\nThis test shows that it is possible to optimize map().filter().map().each() into loop\nWhich is faster\n\n*/\n\nlet {clock} = require(\"datetime\")\n\nfunction profile_it(cnt, f) {//for quirrel version\n  local res = 0\n  for (local i = 0; i < cnt; ++i) {\n    let start = clock()\n    f()\n    let measured = clock() - start\n    if (i == 0 || measured < res)\n      res = measured\n  }\n  return res / 1.0\n}\n\n//prepare testdata\nlet testdata = freeze(array(17*120005).reduce(function(a, _, i) { a[i]<-{key = i}; return a;}, {}))\nfunction log(d){\n  foreach(k, v in d)\n    println($\"{k} = {v}\")\n}\n\n\n// 'classic' functional code\nlet test_filtermap = @() testdata\n  .map(@(v) v.key) //extract func\n  .filter(@(r) r%17==0) //filter func\n\nlet test_filtermap_opt = function() {\n  let mapfunc = @(v) v.key\n  let filterfunc = @(v) v%17==0\n  return testdata\n    .map(function(v) {\n      let res = mapfunc(v)\n      if (!filterfunc(res))\n        throw null\n      return res\n    })\n} //extract func\n\nlet test_map = @() testdata\n  .map(function(v) {\n    let a = v.key\n    if (a%17 != 0)\n      throw null\n    return a\n  }) //extract func\n\n// 'fully unrolled' functional code. can be theoritically done for function that are declared inplace, like code above\nfunction test_loop_max() {\n  let res = []\n  foreach (i, v in testdata) {\n    let r = v.key\n    if (r%17 != 0)\n      continue\n    res.append(r)\n  }\n  return res\n}\n\nconst numTests = 20\nlet profile = @(name, func) println(\"\".concat(name, \", \", profile_it(numTests, func), $\", {numTests}\"))\nlet [a,b,c,d] = [test_filtermap, test_map, test_filtermap, test_filtermap_opt].map(@(f) f().reduce(@(a,b) a+b))\n\nassert(a == b && b == c && c==d )\nprofile(\"\\\"plain_map_filter\\\"\", test_filtermap)\nprofile(\"\\\"test_stupid_simple_optimization\\\"\", test_filtermap_opt)\nprofile(\"\\\"map_replace_filter_with_throw\\\"\", test_map)\nprofile(\"\\\"test_loop_max\\\"\", test_loop_max)\n"
  },
  {
    "path": "testData/proposed_optimizations/strings_folding.nut",
    "content": "/*\n\nThis test shows that it is possible to convert plus and\\or concat operations to string substituation\nWhich is faster\n\n*/\n\nlet {clock} = require(\"datetime\")\n\nfunction profile_it(cnt, f) {//for quirrel version\n  local res = 0\n  for (local i = 0; i < cnt; ++i) {\n    let start = clock()\n    f()\n    let measured = clock() - start\n    if (i == 0 || measured < res)\n      res = measured\n  }\n  return res / 1.0\n}\n\nconst foo = \"foo\"\nlocal bar = \"bar\"\nlocal num = 1234\nlocal somestring = \" somestring\"\n\nlet plus = @(i) foo + \"_\" +bar+\"_\"+num +\"_\" +somestring + i\nlet concat = @(i) \"\".concat(foo, \"_\",bar,\"_\",num,\"_\",somestring, i)\nlet fstring = @(i) $\"{foo}_{bar}_{num}_ {somestring} {i}\"\n\nfunction test(iters, func) {\n  local res\n  local i = iters\n  while(--i){\n    res = func(i)\n  }\n  return res\n}\n\n\nconst numTests = 20\nconst iters = 200000\nfunction profile(name, func){\n  println(\"\".concat(name, \", \", profile_it(numTests, func), $\", {numTests}\"))\n}\nprofile(\"\\\"string plus\\\"\", @() test(iters, plus))\nprofile(\"\\\"string concat\\\"\",@() test(iters, concat))\nprofile(\"\\\"string format\\\"\", @() test(iters, fstring))\n"
  },
  {
    "path": "testData/static_analyzer/.sqconfig",
    "content": "; for w238_sqconfig.nut\nfunction_result_must_be_utilized = _must_be_utilized\n; for w239_sqconfig.nut\nfunction_should_return_bool_prefix = returnBool\n; ; for w260_table_sqconfig.nut\nfunction_should_return_something_prefix = make"
  },
  {
    "path": "testData/static_analyzer/200_nullc.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Comparison operation with potentially nullable expression.\ntestData/static_analyzer/200_nullc.nut:7:44\n\nlet _x =  (((item?.isPrimaryBuy ?? false) > (res?.isPrimaryBuy ?? null) ? item : res))\n                                            ^-------------------------\n\n\nWARNING: w305 (relative-bool-cmp) Relative comparison of non-boolean with boolean. It is a potential runtime error.\ntestData/static_analyzer/200_nullc.nut:7:12\n\nlet _x =  (((item?.isPrimaryBuy ?? false) > (res?.isPrimaryBuy ?? null) ? item : res))\n            ^---------------------------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/200_nullc.nut",
    "content": "function foo() {}\n\nlet item = foo()\nlet res = foo()\n\n\nlet _x =  (((item?.isPrimaryBuy ?? false) > (res?.isPrimaryBuy ?? null) ? item : res))\n\n\n\n//-file:useless-null-coalescing\n"
  },
  {
    "path": "testData/static_analyzer/function_rt_detect.diag.txt",
    "content": "WARNING: w226 (return-different-types) Function can return different types.\ntestData/static_analyzer/function_rt_detect.nut:6:0\n\nfunction _foo(p) { // EXPECTED\n^\n    if (p)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/function_rt_detect.nut",
    "content": "\n// -file:plus-string\n\nfunction trim(s) { return s }\n\nfunction _foo(p) { // EXPECTED\n    if (p)\n        return 1\n    else\n        return 1 + trim(\"A\") + trim(\"B\") + trim(\"C\").join(true) + 9\n}\n\nfunction _bar(p) { // FP\n    if (p)\n        return \"1\"\n    else\n        return 2 + trim(\"A\") + trim(\"B\") + trim(\"C\").join(true) + 8\n}"
  },
  {
    "path": "testData/static_analyzer/logic_ops_paren.diag.txt",
    "content": "WARNING: w202 (and-or-paren) Priority of the '&&' operator is higher than that of the '||' operator. Perhaps parentheses are missing?\ntestData/static_analyzer/logic_ops_paren.nut:5:8\n\nlet a = x && y || z\n        ^----------\nlet b = x || y && z\n\n\nWARNING: w202 (and-or-paren) Priority of the '&&' operator is higher than that of the '||' operator. Perhaps parentheses are missing?\ntestData/static_analyzer/logic_ops_paren.nut:6:8\n\nlet a = x && y || z\nlet b = x || y && z\n        ^----------\nlet c = (x && y) || z\n\n\nWARNING: w203 (bitwise-bool-paren) Result of bitwise operation used in boolean expression. Perhaps parentheses are missing?\ntestData/static_analyzer/logic_ops_paren.nut:10:8\n\nlet e = x || y | z\n        ^---------\nlet f = x || y & z\n\n\nWARNING: w203 (bitwise-bool-paren) Result of bitwise operation used in boolean expression. Perhaps parentheses are missing?\ntestData/static_analyzer/logic_ops_paren.nut:11:8\n\nlet e = x || y | z\nlet f = x || y & z\n        ^---------\nlet g = x && y | z\n\n\nWARNING: w203 (bitwise-bool-paren) Result of bitwise operation used in boolean expression. Perhaps parentheses are missing?\ntestData/static_analyzer/logic_ops_paren.nut:12:8\n\nlet f = x || y & z\nlet g = x && y | z\n        ^---------\nlet h = x && y & z\n\n\nWARNING: w203 (bitwise-bool-paren) Result of bitwise operation used in boolean expression. Perhaps parentheses are missing?\ntestData/static_analyzer/logic_ops_paren.nut:13:8\n\nlet g = x && y | z\nlet h = x && y & z\n        ^---------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/logic_ops_paren.nut",
    "content": "//-file:declared-never-used\n//-file:const-in-bool-expr\nlocal x = 1, y = 2, z = 3;\n\nlet a = x && y || z\nlet b = x || y && z\nlet c = (x && y) || z\nlet d = x || (y && z)\n\nlet e = x || y | z\nlet f = x || y & z\nlet g = x && y | z\nlet h = x && y & z"
  },
  {
    "path": "testData/static_analyzer/module_foo.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/module_foo.nut",
    "content": "return { foo = @(a, b) a+b }\n"
  },
  {
    "path": "testData/static_analyzer/nullcheck_ternary.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/nullcheck_ternary.nut:9:4\n\nfoo(p.z)\n    ^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/nullcheck_ternary.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nfunction foo(_p) {}\nlet x = {}\n\nlet p = foo(1) ? x?.x : x.y\n\nfoo(p.z)\n\n\n\n//-file:expr-cannot-be-null\n"
  },
  {
    "path": "testData/static_analyzer/pattern_class_check.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_class_check.nut",
    "content": "function foo() { return class {} }\nlet x = foo()\nlet _c = class(x) {}\n"
  },
  {
    "path": "testData/static_analyzer/pattern_effect_from_call.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_effect_from_call.nut",
    "content": "function foo(_p) {}\nfunction bar(_p) {}\nfunction qux() {}\n\nlet val = qux()?.z\n\nbar(foo(val) ? val.tointeger() : 0)\n"
  },
  {
    "path": "testData/static_analyzer/pattern_forloop_merge.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_forloop_merge.nut",
    "content": "//-file:declared-never-used\n\n// What does this test check???\n\nfunction findlast(str, substr, startidx=0) {\n  local ret = null\n  for(local i=startidx; i<str.len(); i++) {\n    local k = str.indexof(substr, i)\n    if (k!=null) {\n      i = k\n      ret = k\n    }\n    else\n      break;\n  }\n  return ret\n}\n"
  },
  {
    "path": "testData/static_analyzer/pattern_intersected_assignment.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_intersected_assignment.nut",
    "content": "local curAction = null\n\n\nfunction foo() {}\n\nlet func = foo()\nlet leading = foo()\n\nfunction _throttled(...){\n  let doWait = curAction != null\n  curAction = @() func.acall([null].extend(vargv))\n  if (doWait) {\n    return\n  }\n  if (leading) {\n    curAction()\n  }\n}"
  },
  {
    "path": "testData/static_analyzer/pattern_lambdas.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_lambdas.nut",
    "content": "local x = 10\nlet _y = x > 320 ? @() 20 : function() { return 30 }\n"
  },
  {
    "path": "testData/static_analyzer/pattern_loop_state.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_loop_state.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nfunction foo() {}\n\nlocal found = false\n\nlet diap = foo()\n\nforeach (_seg in diap) {\n//   if (seg[1] - seg[0] < size)\n//     continue\n\n  if (found)\n    continue\n\n  found = true\n}\n\nreturn 0\n"
  },
  {
    "path": "testData/static_analyzer/pattern_param_check.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/pattern_param_check.nut",
    "content": "function _appls(ar) {\n    foreach (_x in ar) {\n        let a = @(perk) (perk?.items ?? []).len() > 0\n        let _b  = @(perk) !a(perk)\n    }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w190.diag.txt",
    "content": "WARNING: w190 (paren-is-function-call) '(' on a new line parsed as function call.\ntestData/static_analyzer/w190.nut:9:4\n\n    foo(10)\n    (x.bar) ? 10 : 20\n    ^\n]\n\n\n\nAN ERROR HAS OCCURRED [attempt to call 'string']\n\nCALLSTACK\n*FUNCTION [__main__()] testData/static_analyzer/w190.nut:8\n\nLOCALS\n[x] TABLE={bar=\"T\"}\n[foo] CLOSURE=FN:foo\n[vargv] ARRAY=[]\n[this] NULL\n"
  },
  {
    "path": "testData/static_analyzer/w190.nut",
    "content": "//-file:suspicious-bracket\n\nfunction foo(_p) { return \"X\" }\n\nlet x = { bar = \"T\" }\n\nlet _a = [\n    foo(10)\n    (x.bar) ? 10 : 20\n]\n"
  },
  {
    "path": "testData/static_analyzer/w192.diag.txt",
    "content": "WARNING: w192 (statement-on-same-line) Next statement on the same line after 'then' statement.\ntestData/static_analyzer/w192.nut:4:9\n\nif (test == 3)\n  a = 6; a = 10\n         ^\n\n\nWARNING: w192 (statement-on-same-line) Next statement on the same line after 'else' statement.\ntestData/static_analyzer/w192.nut:10:9\n\nelse\n  a = 6; a = 10\n         ^\n\n\nWARNING: w192 (statement-on-same-line) Next statement on the same line after 'while loop body' statement.\ntestData/static_analyzer/w192.nut:14:11\n\nwhile (a > b)\n    a = 0; b = 20;\n           ^\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 3 and 4.\ntestData/static_analyzer/w192.nut:4:9\n\nif (test == 3)\n  a = 6; a = 10\n         ^-----\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 4 and 7.\ntestData/static_analyzer/w192.nut:7:0\n\nif (test == 5)\n^\n  a = 7\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 7 and 10.\ntestData/static_analyzer/w192.nut:10:9\n\nelse\n  a = 6; a = 10\n         ^-----\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 10 and 13.\ntestData/static_analyzer/w192.nut:13:0\n\nwhile (a > b)\n^\n    a = 0; b = 20;\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 13 and 14.\ntestData/static_analyzer/w192.nut:14:11\n\nwhile (a > b)\n    a = 0; b = 20;\n           ^-----\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 14 and 18.\ntestData/static_analyzer/w192.nut:18:0\n\nprint(a + b);\n^-----------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w192.nut",
    "content": "local test = true\nlocal a = 1, b = 2\nif (test == 3)\n  a = 6; a = 10\n\n\nif (test == 5)\n  a = 7\nelse\n  a = 6; a = 10\n\n\nwhile (a > b)\n    a = 0; b = 20;\n\n\n\nprint(a + b);"
  },
  {
    "path": "testData/static_analyzer/w200.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Comparison operation with potentially nullable expression.\ntestData/static_analyzer/w200.nut:2:10\n\nfunction fn(mod, wpUnitRank) { //-declared-never-used\n  return (mod?.reqRank > wpUnitRank)\n          ^-----------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w200.nut",
    "content": "function fn(mod, wpUnitRank) { //-declared-never-used\n  return (mod?.reqRank > wpUnitRank)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w200_3wcmp.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w200_3wcmp.nut",
    "content": "// This check is (intentionally?) disabled for <=> operator.\n// If needed, change isBoolRelationOperator() to isRelationOperator()\n// in checkPotentiallyNullableOperands() function in analyzer\n\nfunction _itemsSorter(a, b) { // -return-different-types\n  a = a?.item\n  b = b?.item\n  if (!a || !b)\n    return a <=> b\n  return 42\n}\n"
  },
  {
    "path": "testData/static_analyzer/w200_arith.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Arithmetic operation with potentially nullable expression.\ntestData/static_analyzer/w200_arith.nut:4:10\n\nlocal x = {y = 2}\nlocal a = x?.y - 8\n          ^---\nprint(a)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w200_arith.nut",
    "content": "//-file:expr-cannot-be-null\n\nlocal x = {y = 2}\nlocal a = x?.y - 8\nprint(a)\n"
  },
  {
    "path": "testData/static_analyzer/w200_arith_deep.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Arithmetic operation with potentially nullable expression.\ntestData/static_analyzer/w200_arith_deep.nut:5:10\n\nlocal z = x?.y\nlocal a = z - 8\n          ^\nprint(a)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w200_arith_deep.nut",
    "content": "//-file:expr-cannot-be-null\n\nlocal x = {y = 2}\nlocal z = x?.y\nlocal a = z - 8\nprint(a)\n"
  },
  {
    "path": "testData/static_analyzer/w200_arith_plus_eq.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Arithmetic operation with potentially nullable expression.\ntestData/static_analyzer/w200_arith_plus_eq.nut:5:0\n\nlocal a = x?.z\na -= 10\n^\nprint(a)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w200_arith_plus_eq.nut",
    "content": "//-file:expr-cannot-be-null\n\nlocal x = {y = 2, z = 1}\nlocal a = x?.z\na -= 10\nprint(a)\n"
  },
  {
    "path": "testData/static_analyzer/w200_special_func_name.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Arithmetic operation with potentially nullable expression.\ntestData/static_analyzer/w200_special_func_name.nut:6:7\n\nreturn ::a.b.c.indexof(\"x\") + 6;\n       ^-------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w200_special_func_name.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nreturn ::a.b.c.indexof(\"x\") + 6;\n\n"
  },
  {
    "path": "testData/static_analyzer/w200_static_memo_expr.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Comparison operation with potentially nullable expression.\ntestData/static_analyzer/w200_static_memo_expr.nut:2:10\n\nfunction fn(mod, wpUnitRank) { //-declared-never-used\n  return (static(mod?.reqRank) > wpUnitRank) // -w316\n          ^------------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w200_static_memo_expr.nut",
    "content": "function fn(mod, wpUnitRank) { //-declared-never-used\n  return (static(mod?.reqRank) > wpUnitRank) // -w316\n}\n"
  },
  {
    "path": "testData/static_analyzer/w200_stringconcat.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w200_stringconcat.nut",
    "content": "//-file:expr-cannot-be-null\n//-file:plus-string\n//-file:decl-in-expression\n\n// Potentially nullable operand check (w200) explicitly allows nulls in string concatenation\n\nlet o = {}\nlet s = o?.x\nlet ss = \"a\" + o + s //-declared-never-used\n\n"
  },
  {
    "path": "testData/static_analyzer/w203.diag.txt",
    "content": "WARNING: w203 (bitwise-bool-paren) Result of bitwise operation used in boolean expression. Perhaps parentheses are missing?\ntestData/static_analyzer/w203.nut:11:18\n\nif (condition1 || condition2 || condition3 | condition4)\n                  ^------------------------------------\n  print(\"ok\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w203.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlocal condition1 = ::x\nlocal condition2 = ::y\nlocal condition3 = ::z\nlocal condition4 = ::w\n\nif (condition1 || condition2 || condition3 | condition4)\n  print(\"ok\")\n"
  },
  {
    "path": "testData/static_analyzer/w204.diag.txt",
    "content": "WARNING: w204 (bitwise-apply-to-bool) The '&' or '|' operator is applied to boolean type. You've probably forgotten to include parentheses or intended to use the '&&' or '||' operator.\ntestData/static_analyzer/w204.nut:2:6\n\nfunction foo(x){ //-declared-never-used\n  if (x & 15 == 8)\n      ^----------\n    print(\"ok\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w204.nut",
    "content": "function foo(x){ //-declared-never-used\n  if (x & 15 == 8)\n    print(\"ok\")\n}\n"
  },
  {
    "path": "testData/static_analyzer/w205-2.diag.txt",
    "content": "WARNING: w205 (unreachable-code) Unreachable code after 'return'.\ntestData/static_analyzer/w205-2.nut:3:2\n\n  return\n  let t = { //-declared-never-used\n  ^\n    a = 1\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w205-2.nut",
    "content": "function y() { //-declared-never-used\n  return\n  let t = { //-declared-never-used\n    a = 1\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w205.diag.txt",
    "content": "WARNING: w205 (unreachable-code) Unreachable code after 'return'.\ntestData/static_analyzer/w205.nut:3:4\n\n  return\n    callback()\n    ^---------\n}\n\n\nWARNING: w315 (invalid-indentation) Invalid indentation. Pay attention to lines 2 and 3.\ntestData/static_analyzer/w205.nut:3:4\n\n  return\n    callback()\n    ^---------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w205.nut",
    "content": "function x(callback) { //-declared-never-used\n  return\n    callback()\n}\n"
  },
  {
    "path": "testData/static_analyzer/w206.diag.txt",
    "content": "WARNING: w206 (assigned-twice) Variable is assigned twice successively.\ntestData/static_analyzer/w206.nut:4:0\n\ntab.y = 7\ntab.x = 8\n^--------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w206.nut",
    "content": "local tab = {x=0, y=0, z=0}\ntab.x = 6\ntab.y = 7\ntab.x = 8\n\n"
  },
  {
    "path": "testData/static_analyzer/w206_arith.diag.txt",
    "content": "WARNING: w206 (assigned-twice) Variable is assigned twice successively.\ntestData/static_analyzer/w206_arith.nut:11:0\n\nx /= foo();\nx = foo();\n^--------\nprint(x)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w206_arith.nut",
    "content": "function foo() { return 20 }\n\nlocal x = 10\n\nx = foo();\nx += foo();\nx -= foo();\nx *= foo();\nx %= foo();\nx /= foo();\nx = foo();\nprint(x)\nx = foo()\nprint(\"\")\nx = foo()"
  },
  {
    "path": "testData/static_analyzer/w208.diag.txt",
    "content": "WARNING: w208 (potentially-nulled-assign) Assignment to potentially nullable expression.\ntestData/static_analyzer/w208.nut:2:0\n\nlocal x = { z = {y = 3}}\nx.z?.y <- 6\n^-----\nprint(x.z.y)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w208.nut",
    "content": "local x = { z = {y = 3}}\nx.z?.y <- 6\nprint(x.z.y)"
  },
  {
    "path": "testData/static_analyzer/w209.diag.txt",
    "content": "WARNING: w209 (assigned-to-itself) The variable is assigned to itself.\ntestData/static_analyzer/w209.nut:3:0\n\nx.y = (((x.y)))\n^-----------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w209.nut",
    "content": "local x = {y = 3}\n\nx.y = (((x.y)))"
  },
  {
    "path": "testData/static_analyzer/w210.diag.txt",
    "content": "WARNING: w210 (potentially-nulled-index) Potentially nullable expression used as array index.\ntestData/static_analyzer/w210.nut:6:9\n\n::f <- x[y?[\"a\"]]\n         ^------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w210.nut",
    "content": "//-file:expr-cannot-be-null\n\nlocal x = { b =  1 }\nlocal y = { a = \"b\" }\n\n::f <- x[y?[\"a\"]]\n"
  },
  {
    "path": "testData/static_analyzer/w210_complex.diag.txt",
    "content": "WARNING: w210 (potentially-nulled-index) Potentially nullable expression used as array index.\ntestData/static_analyzer/w210_complex.nut:13:6\n\nfoo(x[y])\n      ^\nfoo(x?[y])\n\n\nWARNING: w210 (potentially-nulled-index) Potentially nullable expression used as array index.\ntestData/static_analyzer/w210_complex.nut:17:12\n\nfoo(x.y?[10].y?[y])\nfoo(x.y.z.u[y])\n            ^\nfoo(x.y?.z.u[y])\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w210_complex.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\n\n\nfunction foo(_x) { return 20 }\n\nlet y = null\nlet x = {}\n\n\nfoo(x[y])\nfoo(x?[y])\nfoo(x?.z[y])\nfoo(x.y?[10].y?[y])\nfoo(x.y.z.u[y])\nfoo(x.y?.z.u[y])\n\n\n\n//-file:expr-cannot-be-null\n"
  },
  {
    "path": "testData/static_analyzer/w210_deep.diag.txt",
    "content": "WARNING: w210 (potentially-nulled-index) Potentially nullable expression used as array index.\ntestData/static_analyzer/w210_deep.nut:7:9\n\n::f <- x[index]\n         ^----\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w210_deep.nut",
    "content": "//-file:expr-cannot-be-null\n\nlocal y = { a = \"b\" }\nlocal index = y?[\"a\"]\nlocal x = { b =  1 }\n\n::f <- x[index]\n"
  },
  {
    "path": "testData/static_analyzer/w210_def.diag.txt",
    "content": "WARNING: w210 (potentially-nulled-index) Potentially nullable expression used as array index.\ntestData/static_analyzer/w210_def.nut:7:31\n\nlocal buildBtnParams = ::kwarg(function(icon=null, option=null, count_list=null, counterFunc=null){ //-declared-never-used\n  local list = ::contactsLists[count_list ?? option].list\n                               ^-------------------\n  counterFunc = counterFunc ?? function(_){ return list }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w210_def.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlocal buildBtnParams = ::kwarg(function(icon=null, option=null, count_list=null, counterFunc=null){ //-declared-never-used\n  local list = ::contactsLists[count_list ?? option].list\n  counterFunc = counterFunc ?? function(_){ return list }\n  return counterFunc\n})\n\nreturn buildBtnParams\n"
  },
  {
    "path": "testData/static_analyzer/w211.diag.txt",
    "content": "WARNING: w211 (duplicate-case) Duplicate case value.\ntestData/static_analyzer/w211.nut:13:7\n\n  case MODE.MODE_2: print(\"2\"); break;\n  case MODE.MODE_1: print(\"3\"); break;\n       ^----------\n  default:\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w211.nut",
    "content": "#allow-switch-statement\n\nlocal MODE = {\n  MODE_1 = 1\n  MODE_2 = 2\n  MODE_3 = 3\n}\n\nlocal x = 1\nswitch(x) {\n  case MODE.MODE_1: print(\"1\"); break;\n  case MODE.MODE_2: print(\"2\"); break;\n  case MODE.MODE_1: print(\"3\"); break;\n  default:\n    print(\"0\")\n    break;\n}"
  },
  {
    "path": "testData/static_analyzer/w212.diag.txt",
    "content": "WARNING: w212 (duplicate-if-expression) Detected pattern 'if (A) {...} else if (A) {...}'. Branch unreachable.\ntestData/static_analyzer/w212.nut:9:9\n\n  print(\"2\")\nelse if (x == 1) // OK\n         ^-----\n  print(\"3\")\n\n\nWARNING: w212 (duplicate-if-expression) Detected pattern 'if (A) {...} else if (A) {...}'. Branch unreachable.\ntestData/static_analyzer/w212.nut:26:8\n\n    ;\n    if (x == 1) // OK\n        ^-----\n        print(\"3\");\n\n\nWARNING: w212 (duplicate-if-expression) Detected pattern 'if (A) {...} else if (A) {...}'. Branch unreachable.\ntestData/static_analyzer/w212.nut:35:9\n\n  print(\"2\")\nelse if (x == 1) // OK\n         ^-----\n    print(\"3\");;;\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w212.nut",
    "content": "local x = 1\n\nfunction foo() { return 10 }\n\nif (x == 1)\n  print(\"1\")\nelse if (x == 2)\n  print(\"2\")\nelse if (x == 1) // OK\n  print(\"3\")\nelse {\n    x = foo()\n    print(\"4\");\n    if (x == 1) // WRONG\n        print(\"5\");\n}\n\n\nif (x == 1)\n  print(\"1\")\nelse if (x == 2)\n  print(\"2\")\nelse {\n    ;\n    ;\n    if (x == 1) // OK\n        print(\"3\");\n}\n\n\nif (x == 1)\n  print(\"1\")\nelse if (x == 2)\n  print(\"2\")\nelse if (x == 1) // OK\n    print(\"3\");;;"
  },
  {
    "path": "testData/static_analyzer/w213.diag.txt",
    "content": "WARNING: w213 (then-and-else-equals) 'then' statement is equivalent to 'else' statement.\ntestData/static_analyzer/w213.nut:6:7\n\n  }\n  else {\n       ^\n    x /= 4\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w213.nut",
    "content": "function _foo(x) {\n  if (x == 1) {\n    x /= 4\n    print(x)\n  }\n  else {\n    x /= 4\n    print(x)\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w214.diag.txt",
    "content": "WARNING: w214 (operator-returns-same-val) Both branches of operator '<> ? <> : <>' are equivalent.\ntestData/static_analyzer/w214.nut:13:7\n\n::x <- test ? REPLAY.SKIRMISH : REPLAY.SKIRMISH\n       ^---------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w214.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlocal test = ::f\n\nenum REPLAY {\n  SKIRMISH = 2\n  BATTLE = 3 //-declared-never-used\n}\n\n::x <- test ? REPLAY.SKIRMISH : REPLAY.SKIRMISH\n"
  },
  {
    "path": "testData/static_analyzer/w214_static_memo_expr.diag.txt",
    "content": "WARNING: w214 (operator-returns-same-val) Both branches of operator '<> ? <> : <>' are equivalent.\ntestData/static_analyzer/w214_static_memo_expr.nut:13:14\n\n::x <- static(test ? REPLAY.SKIRMISH : REPLAY.SKIRMISH) //-w316\n              ^---------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w214_static_memo_expr.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlocal test = ::f\n\nenum REPLAY {\n  SKIRMISH = 2\n  BATTLE = 3 //-declared-never-used\n}\n\n::x <- static(test ? REPLAY.SKIRMISH : REPLAY.SKIRMISH) //-w316\n"
  },
  {
    "path": "testData/static_analyzer/w215.diag.txt",
    "content": "WARNING: w215 (ternary-priority) The '?:' operator has lower priority than the '+' operator. Perhaps the '?:' operator works in a different way than it was expected.\ntestData/static_analyzer/w215.nut:5:10\n\nlocal flag = true\nlocal b = 10 + flag ? 1 : 2\n          ^--------\nprint(b)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w215.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlocal flag = true\nlocal b = 10 + flag ? 1 : 2\nprint(b)"
  },
  {
    "path": "testData/static_analyzer/w215_nullc.diag.txt",
    "content": "WARNING: w215 (ternary-priority) The '?:' operator has lower priority than the '??' operator. Perhaps the '?:' operator works in a different way than it was expected.\ntestData/static_analyzer/w215_nullc.nut:8:9\n\nlet _u = o?.u ?? s ? s / r : 0.0\n         ^--------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w215_nullc.nut",
    "content": "\nfunction foo() {}\n\nlet o = {}\nlet s = foo()\nlet r = foo()\n\nlet _u = o?.u ?? s ? s / r : 0.0\n\n\n//-file:expr-cannot-be-null\n"
  },
  {
    "path": "testData/static_analyzer/w216.diag.txt",
    "content": "WARNING: w216 (same-operands) Left and right operands of '<' operator are the same.\ntestData/static_analyzer/w216.nut:3:4\n\nif (a.x < a.x)\n    ^--------\n  print(\"x < y\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w216.nut",
    "content": "local a = {x=2, y=3}\n\nif (a.x < a.x)\n  print(\"x < y\")"
  },
  {
    "path": "testData/static_analyzer/w217_break.diag.txt",
    "content": "WARNING: w217 (unconditional-terminated-loop) Unconditional 'break' inside a loop.\ntestData/static_analyzer/w217_break.nut:5:4\n\n    y--;\n    break;\n    ^----\n    z--;\n\n\nWARNING: w205 (unreachable-code) Unreachable code after 'break'.\ntestData/static_analyzer/w217_break.nut:6:4\n\n    break;\n    z--;\n    ^--\n  }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w217_break.nut",
    "content": "function foo(x,y,z){ //-declared-never-used\n  for (;;) {\n    x++;\n    y--;\n    break;\n    z--;\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w217_complex.diag.txt",
    "content": "WARNING: w217 (unconditional-terminated-loop) Unconditional 'break' inside a loop.\ntestData/static_analyzer/w217_complex.nut:30:12\n\n            foo()\n            break\n            ^----\n        }\n\n\nWARNING: w217 (unconditional-terminated-loop) Unconditional 'throw' inside a loop.\ntestData/static_analyzer/w217_complex.nut:48:8\n\n        foo()\n        throw \"y\"\n        ^--------\n    }\n\n\nWARNING: w217 (unconditional-terminated-loop) Unconditional 'return' inside a loop.\ntestData/static_analyzer/w217_complex.nut:70:4\n\n    return 0\n    ^-------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w217_complex.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n#allow-switch-statement\n\nconst MB = 3\nfunction foo() {}\nfunction bar(_p) {}\nfunction qux(_p) {}\nlet n = {}\n\nfor (local offset = 1; offset < MB; offset++) {\n    let idx = (n.v + offset) % MB\n    if (foo() <= 0)\n      continue\n    foo()\n    if (idx)\n      bar(0.1)\n    qux(idx)\n    return true\n}\n\n\nfor (;;) {\n    foo()\n    {\n        foo()\n        {\n            foo()\n            break\n        }\n    }\n}\n\nfor (;;) {\n    foo()\n    try {\n        foo()\n        if (bar(10)) {\n            qux(20)\n            throw \"x\";\n        } else {\n            qux(30);\n        }\n        throw \"z\"\n    } catch (_e) {\n        foo()\n        throw \"y\"\n    }\n    foo()\n}\n\nfor (;;) {\n    foo()\n    if (qux(20)) {\n        break\n    }\n\n    switch (bar(30)) {\n        case 1:\n            foo()\n            break;\n        case 2:\n            bar(4000)\n            break;\n        default:\n            foo()\n    }\n\n    return 0\n}\n\nfor (;;) {\n    foo()\n    if (qux(20)) {\n        break\n    }\n\n    switch (bar(30)) {\n        case 1:\n            foo()\n            break;\n        default:\n            foo()\n            continue\n    }\n\n    throw \"3333\"\n}"
  },
  {
    "path": "testData/static_analyzer/w217_cond_cont.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w217_cond_cont.nut",
    "content": "\nlet data = {}\n\nlet f = 10\nlet l = 10\nlet cl = {}\nlet isArray = false\n\nfunction foo(_p1, _p2) {}\nfunction bar(_, __, ___, ____, _____) {}\n\nlet res = []\n\nforeach(k, r in data) {\n  local d = r\n  if (f <= l) {\n    let isVisible = cl.value >= 0 && foo(r, k)\n    if (!isVisible)\n      continue\n    cl(cl.value - 1)\n    if (cl.value < 0)\n      break\n  }\n  else {\n    d = bar(r, l + 1, f, r, cl)\n    if (d == null)\n      continue\n  }\n\n  if (isArray)\n    res.append(d)\n  else\n    res[k] <- d\n  if (cl.value < 0)\n    break\n\n  // This is meaningless, but is allowed\n  // We may use hasUnconditionalContinue in the analyzer to report this if needed\n  continue\n}\n"
  },
  {
    "path": "testData/static_analyzer/w217_continue.diag.txt",
    "content": "WARNING: w217 (unconditional-terminated-loop) Unconditional 'continue' inside a loop.\ntestData/static_analyzer/w217_continue.nut:7:4\n\n      ::h(::a, x)\n    continue;\n    ^-------\n    x--;\n\n\nWARNING: w205 (unreachable-code) Unreachable code after 'continue'.\ntestData/static_analyzer/w217_continue.nut:8:4\n\n    continue;\n    x--;\n    ^--\n  } while (x)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w217_continue.nut",
    "content": "//-file:undefined-global\n\nfunction foo(x) { //-declared-never-used\n  do {\n    if (::a == x)\n      ::h(::a, x)\n    continue;\n    x--;\n  } while (x)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w217_ret.diag.txt",
    "content": "WARNING: w217 (unconditional-terminated-loop) Unconditional 'return' inside a loop.\ntestData/static_analyzer/w217_ret.nut:8:4\n\n    return\n    ^-----\n  }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w217_ret.nut",
    "content": "//-file:undefined-global\n\nfunction foo(x){ //-declared-never-used\n  while (x) {\n    if (::a == x)\n      ::h(::a, x)\n\n    return\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w217_throw.diag.txt",
    "content": "WARNING: w217 (unconditional-terminated-loop) Unconditional 'throw' inside a loop.\ntestData/static_analyzer/w217_throw.nut:8:4\n\n    throw \"err\"\n    ^----------\n  }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w217_throw.nut",
    "content": "//-file:undefined-global\n\nfunction _foo(x) {\n  while (x) {\n    if (::a == x)\n      ::h(::a, x)\n\n    throw \"err\"\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w220.diag.txt",
    "content": "WARNING: w220 (potentially-nulled-container) 'foreach' on potentially nullable expression.\ntestData/static_analyzer/w220.nut:2:15\n\nfunction _foo(a) {\n  foreach(x in a?.y()) {\n               ^-----\n    print(x)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w220.nut",
    "content": "function _foo(a) {\n  foreach(x in a?.y()) {\n    print(x)\n  }\n}"
  },
  {
    "path": "testData/static_analyzer/w220_deep.diag.txt",
    "content": "WARNING: w220 (potentially-nulled-container) 'foreach' on potentially nullable expression.\ntestData/static_analyzer/w220_deep.nut:3:15\n\n  local container = a?.y()\n  foreach(x in container) {\n               ^--------\n    print(x)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w220_deep.nut",
    "content": "function _foo(a) {\n  local container = a?.y()\n  foreach(x in container) {\n    print(x)\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w221.diag.txt",
    "content": "WARNING: w221 (result-not-utilized) Result of operation is not used.\ntestData/static_analyzer/w221.nut:7:2\n\n  z--\n  ::x == y\n  ^-------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w221.nut",
    "content": "//-file:undefined-global\n\nlocal z\nfunction _foo(y) {\n  ++z\n  z--\n  ::x == y\n}\n"
  },
  {
    "path": "testData/static_analyzer/w221_delete.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w221_delete.nut",
    "content": "#allow-delete-operator\n\nlet x = {}\n\nx.y <- \"2\"\n\ndelete x.y"
  },
  {
    "path": "testData/static_analyzer/w222.diag.txt",
    "content": "WARNING: w222 (bool-as-index) Boolean used as array index.\ntestData/static_analyzer/w222.nut:2:10\n\nfunction _foo(a,x,y) {\n  print(a[x < y])\n          ^----\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w222.nut",
    "content": "function _foo(a,x,y) {\n  print(a[x < y])\n}"
  },
  {
    "path": "testData/static_analyzer/w222_deep.diag.txt",
    "content": "WARNING: w222 (bool-as-index) Boolean used as array index.\ntestData/static_analyzer/w222_deep.nut:12:12\n\n    let index = x < y\n    print(a[index])\n            ^----\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w222_deep.nut",
    "content": "//-file:potentially-nullable-index\n//-file:undefined-global\n//-file:declared-never-used\n\nlocal x, y\nfunction b(...) {}\n\n// `let` binding with external function call\n// Should warn - let bindings are immutable and preserved\nfunction test_let(a) {\n    let index = x < y\n    print(a[index])\n}\n\n// Direct use without any function call (baseline)\n// Doesn't work now!!!\n// Should warn - no function calls to potentially kill the value\nfunction test_local(a) {\n    local index = x < y\n    print(a[index])\n}\n\n// Local variable, local function call, then external function call\n// Doesn't currently warn - the implementation is too complex.\n// Should warn - local function b() doesn't modify index\nfunction test_local_with_local_and_external_call(a) {\n    local index = x < y\n    b()\n    print(a[index])\n}\n\n// Local variable in nested block scope\n// Doesn't currently warn - the implementation is too complex\n// Should warn - nested scope doesn't affect the fix\nfunction test_nested_block_scope(a) {\n    local index = x < y\n    {\n        print(a[index])\n    }\n}\n\n// Multiple external function calls\n// Doesn't currently warn - the implementation is too complex\n// Should warn - external calls don't affect function-local variables\nfunction test_multiple_external_calls(a) {\n    local index = x < y\n    print(\"before\")\n    print(\"middle\")\n    print(a[index])\n}\n\n// Local variable used inside loop scope\n// Doesn't currently warn - the implementation is too complex\n// Should warn - loop scope is still within the function\nfunction test_loop_scope(a, arr) {\n    local index = x < y\n    foreach (_k, v in arr) { //-potentially-nullable\n        if (v)\n            print(a[index])\n    }\n}\n\n// Local function that doesn't modify the variable\n// Doesn't currently warn - the implementation is too complex\n// Should warn - inner() has empty body, doesn't modify index\nfunction test_local_function_no_modification(a) {\n    local index = x < y\n    function inner() {} //-declared-never-used\n    inner()\n    print(a[index])\n}\n\n\n// Variable reassigned - should NOT warn\nfunction test_reassigned_variable(a) {\n    local index = x < y\n    index = 42\n    print(a[index])\n}\n\n// Conditional assignment - should NOT warn (index could be non-boolean)\nfunction test_conditional_assignment(a, cond) {\n    local index = x < y\n    if (cond)\n        index = 42\n    print(a[index])\n}\n\n// Local variable, local function call capturing `index` as a free variable\n// Should NOT warn - the function can modify the variable\nfunction test_local_with_local_call_with_outer(a) {\n    local index = x < y\n    function localFunc() {\n      index = 42\n    }\n    localFunc()\n    print(a[index])\n}\n\n// A variation of above - should NOT warn\nfunction test_local_with_local_call_with_outer_2(a) {\n    local index = x < y\n    b(function() {\n      index = 42\n    })\n    print(a[index])\n}\n"
  },
  {
    "path": "testData/static_analyzer/w222_inside_detructure.diag.txt",
    "content": "WARNING: w222 (bool-as-index) Boolean used as array index.\ntestData/static_analyzer/w222_inside_detructure.nut:3:12\n\n  function foo(a,x,y) {\n    print(a[x < y])\n            ^----\n  }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w222_inside_detructure.nut",
    "content": "function fn([v =\n  function foo(a,x,y) {\n    print(a[x < y])\n  }\n]) {\n  return v\n}\n\nreturn fn\n"
  },
  {
    "path": "testData/static_analyzer/w223.diag.txt",
    "content": "WARNING: w223 (compared-with-bool) Comparison with boolean.\ntestData/static_analyzer/w223.nut:4:4\n\nlocal z = 2\nif (x == y > z)\n    ^---------\n  print(\"a\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w223.nut",
    "content": "local x = 1\nlocal y = 1\nlocal z = 2\nif (x == y > z)\n  print(\"a\")\n\nif ((x > y) != z)\n  print(\"b\")\n\nif (x == (y > z))\n  print(\"c\")"
  },
  {
    "path": "testData/static_analyzer/w223_method_is.diag.txt",
    "content": "WARNING: w223 (compared-with-bool) Comparison with boolean.\ntestData/static_analyzer/w223_method_is.nut:11:4\n\nif (r.foo() != s) // warns\n    ^-----------\n    print(\"d\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w223_method_is.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlet sec = 10000\nlet s = sec > 0\nlet r = ::external_data //-undefined-global\n\nif (r.isVisible() != s) // doesn't warn\n    print(\"d\")\n\nif (r.foo() != s) // warns\n    print(\"d\")\n"
  },
  {
    "path": "testData/static_analyzer/w224_then.diag.txt",
    "content": "WARNING: w224 (empty-body) 'then' branch of 'if' has an empty body.\ntestData/static_analyzer/w224_then.nut:3:11\n\nif (x == 5);\n           ^\n{\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w224_then.nut",
    "content": "local x = 19\n\nif (x == 5);\n{\n  x++;\n  return 0;\n}\n"
  },
  {
    "path": "testData/static_analyzer/w224_while.diag.txt",
    "content": "WARNING: w224 (empty-body) 'while' loop has an empty body.\ntestData/static_analyzer/w224_while.nut:9:18\n\n      break;\n  } while (x < 6) ;\n                  ^\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w224_while.nut",
    "content": "//-file:statement-on-same-line\n//-file:invalid-indentation\n\nfunction foo(x){ //-declared-never-used\n  while (x) {\n    x++;\n    if (x > 5)\n      break;\n  } while (x < 6) ;\n}"
  },
  {
    "path": "testData/static_analyzer/w225.diag.txt",
    "content": "WARNING: w225 (all-paths-return-value) Not all control paths return a value.\ntestData/static_analyzer/w225.nut:1:0\n\nfunction _x(y) {\n^\n  if (y == 1)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w225.nut",
    "content": "function _x(y) {\n  if (y == 1)\n    return \"y == 1\"\n  else if (y == 2)\n    return \"y == 2\"\n}\n"
  },
  {
    "path": "testData/static_analyzer/w225_empty_stmt.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w225_empty_stmt.nut",
    "content": "// Ensure there are no false positives after the last semicolon\n\nlet function _foo(filename) {\n  assert(type(filename)==\"string\");\n  return {};\n}\n\n\nlet function _oneliner() { return []; }\n"
  },
  {
    "path": "testData/static_analyzer/w225_switch.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w225_switch.nut",
    "content": "#allow-switch-statement\n\n// No false positives in switch fallthrough\n\nfunction foo(_p) {}\nfunction _dataToBlk(data) {\n    let blk = {}\n    let dataType = foo(data) ? \"DataBlock\" : foo(data)\n    switch (dataType) {\n      case \"null\":\n        return \"__null\"\n      case \"bool\":\n      case \"integer\":\n      case \"float\":\n      case \"string\":\n        return data\n      case \"array\":\n      case \"table\":\n        foreach (key, value in data) {\n          foo(key)\n          foo(value)\n        }\n        return \"04\"\n      case \"DataBlock\":\n        blk.setFrom(data)\n        blk.__datablock <- true\n        return \"999\"\n      default:\n        return \"__unsupported \"\n    }\n  }"
  },
  {
    "path": "testData/static_analyzer/w226.diag.txt",
    "content": "WARNING: w226 (return-different-types) Function can return different types.\ntestData/static_analyzer/w226.nut:6:4\n\nlet function x(y) {\n    ^\n  if (y == 1)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w226.nut",
    "content": "//-file:declared-never-used\n//-file:plus-string\n\nlet o = {}\n\nlet function x(y) {\n  if (y == 1)\n    return \"y == 1\"\n  else if (y == 2)\n    return y == 2\n  else\n    return \"unknown\"\n}\n\nfunction foo(a, b) {\n    return a.value ? b?.getEcsTemplates(\"ss\") ?? [] : []\n}\n\nlet B = {\n    D = {}\n    DC = {}\n}\n\nfunction bar(w) {\n    if (w?.c != null)\n      return {\n        c = w?.c\n      }\n    if (w?.b == null)\n      return B.D\n\n    return B.findvalue(@(bt) bt.p != null && (w?.bt.indexof(bt.p) ?? -1) == 0)\n    ?? B.DC\n  }\n\n\n\nfunction qux() {\n    return o.isGG() ? \"\" : o.get1Txt() + \" \" + o.get2Txt()\n}\n\nfunction loc(a) { return a }\n\nfunction getabc() {\n    let p = o.gts()?.aaa\n    return p != null ? p + loc(\"dskjfhjs\") : \"\"\n  }\n\nconst SVG_EXT = \"xxx\"\n\nlet sahj = @(id, p = \"ddd\") (id in o) ? p + id + SVG_EXT : \"\"\n\nlet _sumScore = o.reduce(@(res, v) res + (v?.score ?? 0))\n"
  },
  {
    "path": "testData/static_analyzer/w227.diag.txt",
    "content": "WARNING: w227 (ident-hides-ident) variable 'a' hides parameter with the same name.\ntestData/static_analyzer/w227.nut:4:4\n\n    local x = c\n    local a = x\n    ^----------\n    print(a)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w227.nut",
    "content": "function foo(a, c) { //-declared-never-used\n  local b = function() {\n    local x = c\n    local a = x\n    print(a)\n    return x\n  }\n  return b()\n}\n"
  },
  {
    "path": "testData/static_analyzer/w227_external.diag.txt",
    "content": "WARNING: w227 (ident-hides-ident) parameter 'println' hides external binding with the same name.\ntestData/static_analyzer/w227_external.nut:1:14\n\nfunction _foo(println) {\n              ^------\n    return println + 1\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w227_external.nut",
    "content": "function _foo(println) {\n    return println + 1\n}\n"
  },
  {
    "path": "testData/static_analyzer/w227_fn_with_same_param.diag.txt",
    "content": "WARNING: w227 (ident-hides-ident) parameter 'txt' hides function with the same name.\ntestData/static_analyzer/w227_fn_with_same_param.nut:1:13\n\nfunction txt(txt) {} //-declared-never-used\n             ^--\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w227_fn_with_same_param.nut",
    "content": "function txt(txt) {} //-declared-never-used\n"
  },
  {
    "path": "testData/static_analyzer/w227_foreach_destr_shadow.diag.txt",
    "content": "WARNING: w228 (declared-never-used) parameter 'x' was declared but never used.\ntestData/static_analyzer/w227_foreach_destr_shadow.nut:4:15\n\n// through Visitor::visitDestructuringDecl so visitVarDecl runs for each name.\nfunction outer(x) {\n               ^\n  function inner() {\n\n\nWARNING: w227 (ident-hides-ident) binding 'x' hides parameter with the same name.\ntestData/static_analyzer/w227_foreach_destr_shadow.nut:6:14\n\n  function inner() {\n    foreach ({x = 99} in [{x = 1}]) {\n              ^-----\n      println(x)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w227_foreach_destr_shadow.nut",
    "content": "// w227 (ident-hides-ident) must fire for a destructured foreach binding that\n// shadows an outer parameter / binding. Covers NameShadowingChecker routing\n// through Visitor::visitDestructuringDecl so visitVarDecl runs for each name.\nfunction outer(x) {\n  function inner() {\n    foreach ({x = 99} in [{x = 1}]) {\n      println(x)\n    }\n  }\n  inner()\n}\nouter(5)\n"
  },
  {
    "path": "testData/static_analyzer/w227_let_init_fun.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w227_let_init_fun.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nfunction foo(_p) {}\n// This is allowed, no warning here\nlet setGroup = foo(function setGroup(_crew, _group, _onFinishCb) {\n})\n\nsetGroup()\n"
  },
  {
    "path": "testData/static_analyzer/w227_table.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w227_table.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nlet getSoldierFace = @() 1\n\nlet _fx = 10\n\n// This is not a name shadowing\nreturn  {\n    getSoldierFace = @() getSoldierFace()\n    _fx = 100\n}\n"
  },
  {
    "path": "testData/static_analyzer/w227_varargs.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w227_varargs.nut",
    "content": "// Var args are not conflicting\n\nfunction foo(a, ...) {\n    return function (b, ...) { return a + b; }\n}\n\n\nfoo(\"...\")"
  },
  {
    "path": "testData/static_analyzer/w228.diag.txt",
    "content": "WARNING: w228 (declared-never-used) variable 'str' was declared but never used.\ntestData/static_analyzer/w228.nut:2:8\n\nfunction _x() {\n  local str = \"string\"\n        ^--\n  return\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w228.nut",
    "content": "function _x() {\n  local str = \"string\"\n  return\n}"
  },
  {
    "path": "testData/static_analyzer/w228_2.diag.txt",
    "content": "WARNING: w228 (declared-never-used) variable 'f' was declared but never used.\ntestData/static_analyzer/w228_2.nut:2:8\n\nfunction _fn() {\n  local f = 123\n        ^\n  local c = { f = 3 }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w228_2.nut",
    "content": "function _fn() {\n  local f = 123\n  local c = { f = 3 }\n  return c.f\n}\n"
  },
  {
    "path": "testData/static_analyzer/w228_3.diag.txt",
    "content": "WARNING: w228 (declared-never-used) variable 'f' was declared but never used.\ntestData/static_analyzer/w228_3.nut:4:8\n\nfunction _fn() {\n  local f = 123\n        ^\n  local c = { f = 3 }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w228_3.nut",
    "content": "//-file:expr-cannot-be-null\n\nfunction _fn() {\n  local f = 123\n  local c = { f = 3 }\n  return c?.f\n}\n"
  },
  {
    "path": "testData/static_analyzer/w228_4.diag.txt",
    "content": "WARNING: w228 (declared-never-used) binding 'f' was declared but never used.\ntestData/static_analyzer/w228_4.nut:1:4\n\nlet f = function foo() {}\n    ^\nlet c = class {}\n\n\nWARNING: w228 (declared-never-used) binding 'c' was declared but never used.\ntestData/static_analyzer/w228_4.nut:2:4\n\nlet f = function foo() {}\nlet c = class {}\n    ^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w228_4.nut",
    "content": "let f = function foo() {}\nlet c = class {}\n"
  },
  {
    "path": "testData/static_analyzer/w228_foreach_destr_default_uses.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w228_foreach_destr_default_uses.nut",
    "content": "// Identifier referenced inside a destructuring default-value expression must\n// be marked as used by the analyzer. Without the fix that routes\n// visitForeachStatement through valDestructuring->visit, the analyzer never\n// walks the default expression and would emit a spurious w228\n// (declared-never-used) for `fallback_value`.\nfunction f() {\n  let fallback_value = 42\n  foreach ({n = fallback_value} in [{}, {n = 1}]) {\n    println(n)\n  }\n}\nf()\n"
  },
  {
    "path": "testData/static_analyzer/w228_table.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w228_table.nut",
    "content": "// Nothing unused here\nfunction _foo(y) {\n    let x = y\n    return {\n        x = x\n    }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w228_trivial.diag.txt",
    "content": "WARNING: w228 (declared-never-used) binding 'refreshOnWindowActivate' was declared but never used.\ntestData/static_analyzer/w228_trivial.nut:5:9\n\nfunction refreshOnWindowActivate(repeatAmount = 1, refreshPeriodSec = 10.0) {\n         ^----------------------\n    readyRefreshTime = 0\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w228_trivial.nut",
    "content": "local readyRefreshTime = 1;\nlocal timeLeftToUpdate = 2;\nlocal refreshPeriod = 3;\n\nfunction refreshOnWindowActivate(repeatAmount = 1, refreshPeriodSec = 10.0) {\n    readyRefreshTime = 0\n    timeLeftToUpdate = repeatAmount\n    refreshPeriod = refreshPeriodSec\n  }\n\n\nfunction xxx(_a, _b, _c) {\n}\n\n\nxxx(readyRefreshTime, timeLeftToUpdate, refreshPeriod)\n"
  },
  {
    "path": "testData/static_analyzer/w229.diag.txt",
    "content": "WARNING: w229 (copy-of-expression) Duplicate expression found inside the sequence of operations.\ntestData/static_analyzer/w229.nut:2:16\n\nlocal a ={x=0, y=0, z=1}\nif (a.x == 0 && a.y == 0 && a.x == 0)\n                ^-------------------\n  print(\"vector == zero\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w229.nut",
    "content": "local a ={x=0, y=0, z=1}\nif (a.x == 0 && a.y == 0 && a.x == 0)\n  print(\"vector == zero\")\n"
  },
  {
    "path": "testData/static_analyzer/w230_unused_import.diag.txt",
    "content": "WARNING: w230 (imported-never-used) Imported field 'cos' was never used.\ntestData/static_analyzer/w230_unused_import.nut:2:24\n\n// Test for unused imported fields diagnostic\nfrom \"math\" import sin, cos, tan\n                        ^--\nfrom \"string\" import format, printf\n\n\nWARNING: w230 (imported-never-used) Imported field 'tan' was never used.\ntestData/static_analyzer/w230_unused_import.nut:2:29\n\n// Test for unused imported fields diagnostic\nfrom \"math\" import sin, cos, tan\n                             ^--\nfrom \"string\" import format, printf\n\n\nWARNING: w230 (imported-never-used) Imported field 'printf' was never used.\ntestData/static_analyzer/w230_unused_import.nut:3:29\n\nfrom \"math\" import sin, cos, tan\nfrom \"string\" import format, printf\n                             ^-----\nfrom \"io\" import *\n\n\nWARNING: w230 (imported-never-used) Imported field 'datetime' was never used.\ntestData/static_analyzer/w230_unused_import.nut:5:7\n\nfrom \"io\" import *\nimport \"datetime\"\n       ^-------\nimport \"debug\" as Debug\n\n\nWARNING: w230 (imported-never-used) Imported field 'Debug' was never used.\ntestData/static_analyzer/w230_unused_import.nut:6:18\n\nimport \"datetime\"\nimport \"debug\" as Debug\n                  ^----\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w230_unused_import.nut",
    "content": "// Test for unused imported fields diagnostic\nfrom \"math\" import sin, cos, tan\nfrom \"string\" import format, printf\nfrom \"io\" import *\nimport \"datetime\"\nimport \"debug\" as Debug\n\n// Only sin and format are used\nlet _x = sin(0.5)\nlet _str = format(\"value: %d\", 42)\n\n// Unused imports (should trigger warnings):\n// - cos, tan (from math)\n// - printf (from string)\n// - datetime (whole module)\n// - Debug (whole module alias)\n"
  },
  {
    "path": "testData/static_analyzer/w231.diag.txt",
    "content": "WARNING: w231 (format-arguments-count) Format string: arguments count mismatch.\ntestData/static_analyzer/w231.nut:3:20\n\nlocal string = require(\"string\")\nprint(string.format(\"%d%%\", 1, x))\n                    ^-----\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w231.nut",
    "content": "local x = 2\nlocal string = require(\"string\")\nprint(string.format(\"%d%%\", 1, x))\n"
  },
  {
    "path": "testData/static_analyzer/w232_cascade.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w232_cascade.nut",
    "content": "// No always-true-or-false here\n\nfunction x(_i) {}\nfunction y(_i) {}\nfunction z(_i) {}\n\nfunction _foo(size, a, b) {\n  if (a && b)\n    return x(size)\n  if (a)\n    return y(size)\n  if (b)\n    return z(size)\n  return null\n}"
  },
  {
    "path": "testData/static_analyzer/w232_false.diag.txt",
    "content": "WARNING: w232 (always-true-or-false) Expression is always 'false'.\ntestData/static_analyzer/w232_false.nut:6:6\n\n}\nprint(a == ::XEnum.PARAM_A && a == ::XEnum.PARAM_B)\n      ^-------------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w232_false.nut",
    "content": "local a = 1\n::XEnum <- {\n  PARAM_A = 1\n  PARAM_B = 2\n}\nprint(a == ::XEnum.PARAM_A && a == ::XEnum.PARAM_B)\n"
  },
  {
    "path": "testData/static_analyzer/w232_lambda.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w232_lambda.nut",
    "content": "// No always-true-or-false warning here\n\nfunction foo() {}\n\nlet w = foo()\n\nlocal vv = true\nlet wdata = foo()\nlocal _u\n\nif (type(w) == \"table\") {\n  _u = w?.update ?? @(v) wdata(v)\n  vv = w?.vv ?? vv\n} else {\n  _u = w\n}\n\n\nif (vv) {\n  foo()\n}\n"
  },
  {
    "path": "testData/static_analyzer/w232_not.diag.txt",
    "content": "WARNING: w232 (always-true-or-false) Expression is always 'false'.\ntestData/static_analyzer/w232_not.nut:2:6\n\nlocal i = {x = true}\nprint(i.x && !i.x)\n      ^----------\nprint(!i.x || i.x)\n\n\nWARNING: w232 (always-true-or-false) Expression is always 'true'.\ntestData/static_analyzer/w232_not.nut:3:6\n\nprint(i.x && !i.x)\nprint(!i.x || i.x)\n      ^----------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w232_not.nut",
    "content": "local i = {x = true}\nprint(i.x && !i.x)\nprint(!i.x || i.x)\n"
  },
  {
    "path": "testData/static_analyzer/w232_ter.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w232_ter.nut",
    "content": "// No always-true-or-false here\n\nfunction d() {\n}\n\nfunction _foo(p, bb, qq) {\n  let uu = qq.value?[bb]\n  return {\n    kk = [\n      uu == null ? null : {}\n      {\n        text = uu\n          ? p\n          : d()\n      }\n    ]\n  }\n}"
  },
  {
    "path": "testData/static_analyzer/w232_ternary.diag.txt",
    "content": "WARNING: w232 (always-true-or-false) Expression is always 'true'.\ntestData/static_analyzer/w232_ternary.nut:2:12\n\n//expect:w232\nlocal foo = function() { } ? false : true\n            ^-------------\nreturn foo\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w232_ternary.nut",
    "content": "//expect:w232\nlocal foo = function() { } ? false : true\nreturn foo\n"
  },
  {
    "path": "testData/static_analyzer/w232_true.diag.txt",
    "content": "WARNING: w232 (always-true-or-false) Expression is always 'true'.\ntestData/static_analyzer/w232_true.nut:7:6\n\nlocal i = 2\nprint(s.charAt(i) != ' ' || s.charAt(i) != '\\t')\n      ^----------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w232_true.nut",
    "content": "//expect:w232\nlocal a = \"     \"\nlocal s = {\n  charAt =  @(i) a[i]\n}\nlocal i = 2\nprint(s.charAt(i) != ' ' || s.charAt(i) != '\\t')\n"
  },
  {
    "path": "testData/static_analyzer/w233.diag.txt",
    "content": "WARNING: w233 (const-in-bool-expr) Constant in a boolean expression.\ntestData/static_analyzer/w233.nut:8:21\n\n  ::flags <- 0x2040\n  ::aspect_ratio <- (::flags && 0x40)\n                     ^--------------\n}\n\n\nWARNING: w233 (const-in-bool-expr) Constant in a boolean expression.\ntestData/static_analyzer/w233.nut:14:14\n\n  let flags = 0x2040\n  let _res = (flags && 0x40)\n              ^------------\n}\n\n\nWARNING: w233 (const-in-bool-expr) Constant in a boolean expression.\ntestData/static_analyzer/w233.nut:21:16\n\n  local flags = 0x2040\n  local _res = (flags && 0x40)\n                ^------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w233.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n// Root table slots - should warn\n// Note: usage of the root table is deprecated\n{\n  ::flags <- 0x2040\n  ::aspect_ratio <- (::flags && 0x40)\n}\n\n// Binding - should warn\n{\n  let flags = 0x2040\n  let _res = (flags && 0x40)\n}\n\n\n// Local variable - should warn\n{\n  local flags = 0x2040\n  local _res = (flags && 0x40)\n}\n\n// Indirect reference to a constant value through an unary operator - should not warn\n{\n  ::f <- 10\n  local mask = -0x40\n  ::a <- (::f && !mask)\n}\n\n// Not a subject to \"const-in-bool-expr\" check - should not warn\n{\n  function bar(_g) {}\n  function foo() {}\n  let { s, o } = foo()\n  const Z = \"xxs\"\n\n  let _seen = bar(@() o.value && s.value?[Z])\n}\n"
  },
  {
    "path": "testData/static_analyzer/w234.diag.txt",
    "content": "WARNING: w234 (div-by-zero) Integer division by zero.\ntestData/static_analyzer/w234.nut:5:8\n\n  let zero = 0\n  print(1 / (zero))\n        ^--------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w234.nut",
    "content": "//expect:w234\n\nfunction foo() { //-declared-never-used\n  let zero = 0\n  print(1 / (zero))\n}\n"
  },
  {
    "path": "testData/static_analyzer/w234_outer.diag.txt",
    "content": "WARNING: w234 (div-by-zero) Integer division by zero.\ntestData/static_analyzer/w234_outer.nut:12:8\n\nfunction fn2() { //-declared-never-used\n  print(1 / (y))\n        ^-----\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w234_outer.nut",
    "content": "//expect:w234\n\nlocal x = 0 // can be modified before calling \"fn1\"\n\nfunction fn1() { //-declared-never-used\n  print(1 / (x))\n}\n\nlet y = 0 // always equal to 0\n\nfunction fn2() { //-declared-never-used\n  print(1 / (y))\n}\n"
  },
  {
    "path": "testData/static_analyzer/w235.diag.txt",
    "content": "WARNING: w235 (round-to-int) Result of division will be integer.\ntestData/static_analyzer/w235.nut:3:19\n\n::aspect_ratio <- (1280 / (720))\n                   ^----------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w235.nut",
    "content": "//expect:w235\n\n::aspect_ratio <- (1280 / (720))"
  },
  {
    "path": "testData/static_analyzer/w236.diag.txt",
    "content": "WARNING: w236 (shift-priority) Shift operator has lower priority. Perhaps parentheses are missing?\ntestData/static_analyzer/w236.nut:4:30\n\nfunction foo(berserkFx, state){ //-declared-never-used\n  if (!berserkFx && (state & (1 << ::SCRIPT_STATE_USER_SHIFT + 4)))\n                              ^---------------------------------\n    print(1)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w236.nut",
    "content": "//expect:w236\n::SCRIPT_STATE_USER_SHIFT <- 2\nfunction foo(berserkFx, state){ //-declared-never-used\n  if (!berserkFx && (state & (1 << ::SCRIPT_STATE_USER_SHIFT + 4)))\n    print(1)\n}"
  },
  {
    "path": "testData/static_analyzer/w238_heuristic.diag.txt",
    "content": "WARNING: w238 (named-like-should-return) Function name 'isLoggedIn' implies a return value, but its result is never used.\ntestData/static_analyzer/w238_heuristic.nut:5:2\n\nfunction _x() {\n  ::isLoggedIn() //-undefined-global\n  ^-------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w238_heuristic.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nfunction _x() {\n  ::isLoggedIn() //-undefined-global\n}\n"
  },
  {
    "path": "testData/static_analyzer/w238_idname.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w238_idname.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nlet state = {}\nlet isHaHoo = state.foo()\n// prefixed with `is`, but accepts single boolean parameter - can \"apply\" this to an object\n// using a method call\nstate.isRepa(isHaHoo)\n"
  },
  {
    "path": "testData/static_analyzer/w238_isis.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w238_isis.nut",
    "content": "function isRePre(_p) { return true }\nfunction is_re_pre() { return true }\n\n// Single boolean argument - can \"apply\" this boolean to some state\n// Should not warn\nisRePre(is_re_pre())\n"
  },
  {
    "path": "testData/static_analyzer/w238_merge.diag.txt",
    "content": "WARNING: w238 (named-like-should-return) Function name '__merge' implies a return value, but its result is never used.\ntestData/static_analyzer/w238_merge.nut:7:2\n\nfunction _x() {\n  ::a.__merge(::table2)\n  ^--------------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w238_merge.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nfunction _x() {\n  ::a.__merge(::table2)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w238_sqconfig.diag.txt",
    "content": "WARNING: w238 (named-like-should-return) Function name '_must_be_utilized' implies a return value, but its result is never used.\ntestData/static_analyzer/w238_sqconfig.nut:4:2\n\nfunction x() { //-declared-never-used\n  ::a._must_be_utilized(::table2);\n  ^------------------------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w238_sqconfig.nut",
    "content": "//expect:w238\n\nfunction x() { //-declared-never-used\n  ::a._must_be_utilized(::table2);\n}\n\n//-file:undefined-global"
  },
  {
    "path": "testData/static_analyzer/w239.diag.txt",
    "content": "WARNING: w239 (named-like-return-bool) Function name 'isLoggedIn' implies a return boolean type but not all control paths return boolean.\ntestData/static_analyzer/w239.nut:3:9\n\nfunction isLoggedIn() { //-declared-never-used\n         ^---------\n  if (::userName == \"\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w239.nut",
    "content": "//expect:w239\n\nfunction isLoggedIn() { //-declared-never-used\n  if (::userName == \"\")\n    return false;\n\n  if (::serverName == \"\")\n    return\n\n  return true;\n}\n\n//-file:undefined-global\n"
  },
  {
    "path": "testData/static_analyzer/w239_sqconfig.diag.txt",
    "content": "WARNING: w239 (named-like-return-bool) Function name 'returnBoolFunctionName' implies a return boolean type but not all control paths return boolean.\ntestData/static_analyzer/w239_sqconfig.nut:3:9\n\nfunction returnBoolFunctionName() { //-declared-never-used\n         ^---------------------\n  if (::serverName == \"\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w239_sqconfig.nut",
    "content": "//expect:w239\n\nfunction returnBoolFunctionName() { //-declared-never-used\n  if (::serverName == \"\")\n    return\n\n  return true;\n}\n\n//-file:undefined-global\n"
  },
  {
    "path": "testData/static_analyzer/w240.diag.txt",
    "content": "WARNING: w240 (null-coalescing-priority) The '??' operator has a lower priority than the '!=' operator (a??b > c == a??(b > c)). Perhaps the '??' operator works in a different way than it was expected.\ntestData/static_analyzer/w240.nut:9:11\n\nprint(a ?? b != 1) // expected boolean\n           ^-----\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w240.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w240\n\nlocal a = ::x; // can be null\nlocal b = 1;\n\nprint(a ?? b != 1) // expected boolean\n\n//-file:undefined-global"
  },
  {
    "path": "testData/static_analyzer/w241.diag.txt",
    "content": "WARNING: w241 (already-required) Module 'string' has been required already.\ntestData/static_analyzer/w241.nut:7:13\n\nlocal str1 = require(\"string\")\nlocal str2 = require(\"string\")\n             ^----------------\nprint(str1, str2)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w241.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w241\n\nlocal str1 = require(\"string\")\nlocal str2 = require(\"string\")\nprint(str1, str2)\n"
  },
  {
    "path": "testData/static_analyzer/w241_conditional.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w241_conditional.nut",
    "content": "// Is this test correct?\n// It tests for `already-required` warning\n\nfunction foo() {}\nlet x = foo()\nlet d = foo()\n\nlet { _m=null } = require_optional(\"m.nut\")\n\nlet { _g=null } = d ? require_optional(\"a.nut\")\n  : x?.is_x ? require_optional(\"b.nut\")\n  : x?.is_s ? require_optional(\"c.nut\")\n  : x?.is_a ? require_optional(\"d.nut\")\n  : require_optional(\"a.nut\")\n"
  },
  {
    "path": "testData/static_analyzer/w244.diag.txt",
    "content": "WARNING: w244 (used-from-static) Access 'this.y' from static member function.\ntestData/static_analyzer/w244.nut:16:8\n\n        this.sss(); // FP 3\n        this.y = 30 // EXPECTED 1\n        ^-----\n    }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w244.nut",
    "content": "\n\nfunction fex(x) {\n    this.y = x // FP 1\n}\n\n\nclass _C {\n    static function sss() {}\n    function foo() {\n       fex(@() this.y = 10) // FP 2\n    }\n\n    static function bar() {\n        this.sss(); // FP 3\n        this.y = 30 // EXPECTED 1\n    }\n}"
  },
  {
    "path": "testData/static_analyzer/w248.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'a' can be null, but is used as a function without checking.\ntestData/static_analyzer/w248.nut:11:4\n\n} else {\n    a()\n    ^\n}\n\n\nWARNING: w248 (access-potentially-nulled) 'a' can be null, but is used as a function without checking.\ntestData/static_analyzer/w248.nut:14:7\n\nreturn a()\n       ^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w248\n\nlocal a = ::x?.b\nlocal b = a\nif (b) {\n    b()\n} else {\n    a()\n}\n\nreturn a()\n\n//-file:undefined-global"
  },
  {
    "path": "testData/static_analyzer/w248_access.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_access.nut:7:7\n\nlocal a = ::x?.b\nreturn a.b[6]\n       ^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_access.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlocal a = ::x?.b\nreturn a.b[6]\n"
  },
  {
    "path": "testData/static_analyzer/w248_additional.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:54:21\n\n  let outer = foo()?.captured\n  let _closure = @() outer.accessed\n                     ^----\n}\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:91:8\n\n  if (val == \"string\") {\n    foo(obj.asString)\n        ^--\n  } else if (val == \"number\") {\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:93:8\n\n  } else if (val == \"number\") {\n    foo(obj.asNumber)\n        ^--\n  } else if (obj != null) {\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:119:14\n\n  let nullable = foo()?.item\n  let _arr = [nullable.prop]\n              ^-------\n  let _tbl = { key = nullable.prop2 }\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:120:21\n\n  let _arr = [nullable.prop]\n  let _tbl = { key = nullable.prop2 }\n                     ^-------\n}\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:141:6\n\n  bar(arg)\n  foo(arg.field)\n      ^--\n}\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:151:8\n\n  try {\n    foo(val.attempt)\n        ^--\n  } catch (_e) {\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:153:8\n\n  } catch (_e) {\n    foo(val.fallback)\n        ^--\n  }\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_additional.nut:175:6\n\n  if (!x) return         // guard proves NEW x is non-null, but y has OLD value\n  foo(y.field)           // warning - y might be null (holds old x value)\n      ^\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_additional.nut",
    "content": "// Some cases that might logically seem like they should warn\n// are not flagged due to analyzer limitations in tracking complex flows.\n\nif (__name__ == \"__analysis__\")\n  return\n\nfunction foo(_p = null) {}\nfunction bar(_x = null) {}\n\n//=============================================================================\n// Nested ternary expressions with nullable values\n//=============================================================================\n{\n  let a = foo()?.x\n  let b = foo()?.y\n  // Nested ternary where both branches could be null\n  // TRUE NEGATIVE: a and b are checked before access in their respective branches\n  let _result = a != null\n    ? (b != null ? a.val + b.val : a.val)\n    : (b != null ? b.val : 0)\n\n  // KNOWN LIMITATION: a.missing is in else branch where a wasn't checked,\n  // but analyzer doesn't track ternary else-branch nullable state deeply\n  let c = foo()?.z\n  let _bad = c != null ? c.val : a.missing\n}\n\n//=============================================================================\n// Multiple reassignments in complex control flow\n//=============================================================================\n{\n  local x = foo()?.data\n  if (x != null) {\n    x = foo()?.other  // reassign to new nullable\n  }\n  // KNOWN LIMITATION: After if-block, analyzer loses precise tracking\n  // of reassigned variables. x could be null but no warning issued.\n  foo(x.field)\n}\n\n{\n  // TRUE NEGATIVE: y is guaranteed non-null after null-coalescing assignment\n  local y = foo()?.val\n  y = y ?? { default = 1 }\n  foo(y.default)\n}\n\n//=============================================================================\n// Closure captures of nullable variables\n//=============================================================================\n{\n  // EXPECT WARNING: closure captures nullable without outer null-check\n  let outer = foo()?.captured\n  let _closure = @() outer.accessed\n}\n\n{\n  // TRUE NEGATIVE: closure defined inside null-check block inherits the checked state\n  let checked = foo()?.val\n  if (checked != null) {\n    let _safe_closure = @() checked.safe\n  }\n}\n\n//=============================================================================\n// Loop-carried nullable dependencies\n//=============================================================================\n{\n  // TRUE NEGATIVE inside loop: prev is explicitly checked before access\n  local prev = null\n  foreach (item in [1, 2, 3]) {\n    if (prev != null) {\n      foo(prev.data)\n    }\n    prev = foo(item)?.result\n  }\n  // KNOWN LIMITATION: After loop, prev could be null but analyzer\n  // doesn't track loop exit state precisely\n  foo(prev.final)\n}\n\n//=============================================================================\n// Switch/case with nullable checks (using if-else chain pattern)\n//=============================================================================\n{\n  let val = foo()?.type\n  let obj = foo()?.obj\n\n  // EXPECT WARNING: obj not checked, only val is tested\n  if (val == \"string\") {\n    foo(obj.asString)\n  } else if (val == \"number\") {\n    foo(obj.asNumber)\n  } else if (obj != null) {\n    // TRUE NEGATIVE: obj explicitly checked in this branch\n    foo(obj.other)\n  }\n}\n\n//=============================================================================\n// Safe access chain followed by unsafe access\n//=============================================================================\n{\n  // TRUE NEGATIVE: if deep is non-null, the entire chain must have succeeded,\n  // meaning chain is non-null. Analyzer correctly infers this via extractReceiver.\n  let chain = foo()\n  let deep = chain?.level1?.level2?.level3\n  if (deep != null) {\n    foo(chain.direct)\n  }\n}\n\n//=============================================================================\n// Nullable in array/table literal (edge case)\n//=============================================================================\n{\n  // EXPECT WARNING: accessing nullable in collection literal\n  let nullable = foo()?.item\n  let _arr = [nullable.prop]\n  let _tbl = { key = nullable.prop2 }\n}\n\n//=============================================================================\n// Double negation pattern\n//=============================================================================\n{\n  // TRUE NEGATIVE: !! coerces to boolean, so if (!!val) means val is truthy (non-null)\n  let val = foo()?.x\n  if (!!val) {\n    foo(val.data)\n  }\n}\n\n//=============================================================================\n// Nullable used as function argument then accessed\n//=============================================================================\n{\n  // EXPECT WARNING: passing nullable to function is OK, but accessing member is not\n  let arg = foo()?.param\n  bar(arg)\n  foo(arg.field)\n}\n\n//=============================================================================\n// Try-catch with nullable\n//=============================================================================\n{\n  // EXPECT WARNING in both try and catch: nullable not checked in either block\n  let val = foo()?.risky\n  try {\n    foo(val.attempt)\n  } catch (_e) {\n    foo(val.fallback)\n  }\n}\n\n//=============================================================================\n// Assignment before null guard - alias tracking\n//=============================================================================\n{\n  // TRUE NEGATIVE: y holds the same value as x. The guard on x proves\n  // that value is non-null, and the analyzer tracks this aliasing relationship.\n  local x = foo()?.val\n  let y = x              // y is an alias for x's value\n  if (!x) return         // guard proves the value (held by both x and y) is non-null\n  foo(y.field)           // no warning - y is non-null via alias tracking\n}\n\n{\n  // EXPECT WARNING: x was reassigned before the guard, so y might hold old null value\n  local x = foo()?.val\n  let y = x              // y holds x's current (possibly null) value\n  x = foo()?.other       // x reassigned to different value\n  if (!x) return         // guard proves NEW x is non-null, but y has OLD value\n  foo(y.field)           // warning - y might be null (holds old x value)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_andand.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_andand.nut",
    "content": "function canEquipBothItems(_x) {}\n\nfunction _foo(data, onDropExceptionCb = null) {\n    if (onDropExceptionCb != null && !canEquipBothItems(data) && data?.item != null) {\n        onDropExceptionCb(data.item)\n    }\n}"
  },
  {
    "path": "testData/static_analyzer/w248_andor.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_andor.nut:4:26\n\n  let a = list != null && list.len() == 0\n  let b = list != null || list.len() == 0\n                          ^---\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_andor.nut",
    "content": "function _riIsEmptyGroup(x) {\n  let list = x?.list\n  let a = list != null && list.len() == 0\n  let b = list != null || list.len() == 0\n\n  return a && b\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_array.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_array.nut:7:7\n\nlocal a = ::x?.b\nreturn a[6]\n       ^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_array.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlocal a = ::x?.b\nreturn a[6]\n"
  },
  {
    "path": "testData/static_analyzer/w248_assert.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_assert.nut",
    "content": "// assert() acts as a null-check\n\nif (__name__ == \"__analysis__\")\n  return\n\n\nfunction foo() {}\nlet o = foo()\nlet c = o?.x\nassert(c != null)\nlet _g = c.y // No warning - assert guarantees c != null at this point\n"
  },
  {
    "path": "testData/static_analyzer/w248_chain.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_chain.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nlet x = {}\nlet a = 10\n\nif ((x.w.v?[a] ?? 0) == 0) {\n    x.foo()  // No warning - x is a table literal, always non-null\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_complex2.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_complex2.nut",
    "content": "function foo() {}\n\nlet a = foo()\nlet h = foo()\n\nlet v = a?.v\nlet c = h && (typeof v == \"integer\" || typeof v == \"float\")\nif (!c) {\n  return {\n    ct = @() null\n  }\n}\n\n// After early return: v is guaranteed to be integer or float (not null)\n\nlet _target = v.tointeger()  // No warning - v is known to be a number type\n"
  },
  {
    "path": "testData/static_analyzer/w248_complex_key.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_complex_key.nut:17:4\n\nqux(a.z, h.z)\n    ^\n\n\nWARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_complex_key.nut:17:9\n\nqux(a.z, h.z)\n         ^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_complex_key.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nfunction foo() {}\n\nfunction bar(_a, _b) {}\nfunction qux(_a, _b) {}\n\nlet { a = null, h = null } = foo()\n\nif (a?.x[h]) {\n    bar(a.x[h], h.x)\n}\n\n\nqux(a.z, h.z)\n"
  },
  {
    "path": "testData/static_analyzer/w248_complexcond.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_complexcond.nut:10:8\n\nif (x == null && foo(2))\n    foo(x.y)\n        ^\nelse\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_complexcond.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nfunction foo(_p) {}\n\nlocal x = foo(1)\n\n\nif (x == null && foo(2))\n    foo(x.y)\nelse\n    foo(x.x)\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_eq_get.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_eq_get.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nfunction foo(_p) {}\nlet o = {}\n\nlet u = o.value.findvalue(@(u) u.l == \"999\")\nlet _x = u?.t != \"a\" || foo(u) ? null\n  : u.t  // No warning - reaching here means u?.t == \"a\", so u is non-null\n"
  },
  {
    "path": "testData/static_analyzer/w248_evaled.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_evaled.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nlet t = {}\n\nfunction foo(_p) {}\n\nlet sr = t.value.findvalue(@(s) s.s == 10 && (s?.e ?? 0) > 0 )\nlet r = sr != null\nlet _timerObj = r ? foo({\n    ts = sr.e  // No warning - r being true means sr != null\n}) : null\n"
  },
  {
    "path": "testData/static_analyzer/w248_getfield.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_getfield.nut",
    "content": "function foo() {}\n\nlet o = foo()\n\nif (o?.w == null)\n    return\n\no.x = true  // No warning - o is non-null after the early return guard\n"
  },
  {
    "path": "testData/static_analyzer/w248_in.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_in.nut:5:9\n\n  return text.d\n         ^---\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_in.nut",
    "content": "function _foo(dict, text = null) {\n  if (text in dict)\n    return dict[text]\n\n  return text.d\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_in_container.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_in_container.nut",
    "content": "function foo() {}\nfunction bar(_a) {}\n\nlet { c = null} = foo()\n\nif (\"xx\" in c) {\n    bar(c.xx)  // No warning - \"xx\" in c implies c is non-null\n}"
  },
  {
    "path": "testData/static_analyzer/w248_not.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_not.nut",
    "content": "function foo(_p) {}\nlet soldiers = {}\nlet debriefing = foo(1)\nlet squad = foo(2)\nlet squads = foo(3)\n\nforeach (_soldierIdx, soldierStat in soldiers) {\n    let soldierData = debriefing?.soldiers.items[soldierStat.soldierId]\n    if (!soldierData)\n        continue  // Early exit if null - soldierData is non-null below\n    if (squads?[soldierData.squadId] != squad)\n        continue\n\n    foo(soldierData.guid)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_nullc_2.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_nullc_2.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlet t = {}\nlet i = 10\nlet e = t.value?[i]\n\nif ((e?.a ?? false) && (e?.b ?? true)) {\n    e.foo()  // No warning - e must be non-null for condition to be true\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_nullc_3.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_nullc_3.nut",
    "content": "//-file:undefined-global\n\nlet us = {}\n\nforeach (u in us) {\n  if (!u.t.isAvailable())\n    continue\n  let es = u.t.et\n  let d = ::g?[::f(u)]\n  if (d?[es] ?? true)\n    continue  // If d is null, we continue here\n  d[es] <- ::q(u)  // No warning - d is non-null (otherwise we'd have continued)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_oror.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_oror.nut",
    "content": "function foo() {}\nlet gg = foo()\n\nfunction _bar() {\n    let { cfg = null, hasOwned = false } = gg.value\n\n    if (cfg == null || hasOwned)\n        return  // Early exit if cfg is null OR hasOwned is true\n\n    // After return: cfg != null && !hasOwned\n    let { _c, _g } = cfg  // No warning - cfg is non-null after the guard\n    return\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_oror2.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'nullNotH' can be null, but is used as a function without checking.\ntestData/static_analyzer/w248_oror2.nut:5:2\n\n  onDoubleClickCb(itemDesc.__merge({ rectOrPos = event.targetRect }))\n  nullNotH()\n  ^-------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_oror2.nut",
    "content": "function onDoubleClick(itemDesc, event, isLocked, isInteractive, onDoubleClickCb = null, nullNotH = null) {\n  if (isLocked || !isInteractive || onDoubleClickCb == null || nullNotH != null)\n    return\n  onDoubleClickCb(itemDesc.__merge({ rectOrPos = event.targetRect }))\n  nullNotH()\n}\n\n\nonDoubleClick(1, 2, 3, 4, 5)\n"
  },
  {
    "path": "testData/static_analyzer/w248_override.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_override.nut",
    "content": "function foo() {}\nlocal x = foo()?.x\n\n\nif (foo() || !x)\n  return  // After this, x is non-null\n\nlet r = x\nx = null\n\nif (r.s) // Don't warn because r was assigned when x was non-null\n  foo()\n"
  },
  {
    "path": "testData/static_analyzer/w248_relative_pred.diag.txt",
    "content": "WARNING: w200 (potentially-nulled-ops) Comparison operation with potentially nullable expression.\ntestData/static_analyzer/w248_relative_pred.nut:13:9\n\nif (x && y > 0) {\n         ^\n  _r = b[10] / (y * 60)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_relative_pred.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nfunction foo() {}\n\nlet x =foo()\nlet y = x?.y\nlet b = {}\n\nlocal _r = null\n\nif (x && y > 0) {\n  _r = b[10] / (y * 60)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_special_name_func.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'expression' can be null, but is used as a container without checking.\ntestData/static_analyzer/w248_special_name_func.nut:7:0\n\nx.indexof(\".\").foo()\n^-------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_special_name_func.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n\nlet x = {}\n\nx.indexof(\".\").foo()"
  },
  {
    "path": "testData/static_analyzer/w248_terminated_branch1.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_terminated_branch1.nut",
    "content": "//-file:potentially-nulled-index\n\nfunction foo() {}\n\nlet a = foo()\nlet b = foo()\n\n\nfunction _bar() {\n  let c = a.value\n  let res = {}\n  foreach (g, d in b.value) {\n    let t = c?[g].t\n    let nu = c?[b].y\n    if (t == null)\n      continue  // Early exit if t is null - t is non-null below\n\n    if (t not in res) {\n      res[t] <- {}   // No w248 warning - t is non-null after continue guard\n      res[nu] <- {}  // nu is nullable but w210 is disabled for this file\n    }\n\n    res[t][g] <- d   // No w248 warning - t is non-null\n    res[nu][g] <- d  // nu is nullable but w210 is disabled\n  }\n  return res\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_tyopeof1.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_tyopeof1.nut",
    "content": "function fo(debrData) {\n  if (typeof debrData?.players != \"table\")\n    return  // Early exit if debrData is null or players isn't a table\n\n  let players = {}\n  foreach (id, player in debrData.players)\n    players[id.tointeger()] <- player\n  debrData.players = players\n}\n\n\nfo({})\n"
  },
  {
    "path": "testData/static_analyzer/w248_tyopeof2.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'f' can be null, but is used as a function without checking.\ntestData/static_analyzer/w248_tyopeof2.nut:3:15\n\n    if ((typeof colorStr != \"string\" || (colorStr.len() != 8 && colorStr.len() != 6)) && (typeof f == \"null\") )\n        return f(\"first param must be string with len 6 or 8\")\n               ^\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_tyopeof2.nut",
    "content": "function _foo(colorStr, f) {\n    if ((typeof colorStr != \"string\" || (colorStr.len() != 8 && colorStr.len() != 6)) && (typeof f == \"null\") )\n        return f(\"first param must be string with len 6 or 8\")\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_type_func.diag.txt",
    "content": "WARNING: w248 (access-potentially-nulled) 'f' can be null, but is used as a function without checking.\ntestData/static_analyzer/w248_type_func.nut:3:15\n\n    if ((type(colorStr) != \"string\" || (colorStr.len() != 8 && colorStr.len() != 6)) && (type(f) == \"null\") )\n        return f(\"first param must be string with len 6 or 8\")\n               ^\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w248_type_func.nut",
    "content": "function _foo(colorStr, f) {\n    if ((type(colorStr) != \"string\" || (colorStr.len() != 8 && colorStr.len() != 6)) && (type(f) == \"null\") )\n        return f(\"first param must be string with len 6 or 8\")\n}\n"
  },
  {
    "path": "testData/static_analyzer/w248_while_cond.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w248_while_cond.nut",
    "content": "function foo() {}\n\nlet x = foo()\nlocal c = foo()\nlet a = foo()\nlet t = \"skdhaljs\"\nlocal d = 20\n\nwhile (c && (c?.o ?? \"\") != \"\") {  // c is non-null inside loop body\n  c = a?[x.value?[t][c.o]]  // c.o safe because loop condition ensures c non-null\n  if ((c?.d ?? 0) > d) {\n    d = c.d  // No warning - c?.d > d means c is non-null (not using default 0)\n  } else {\n    d = d.xyz\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w250_array.diag.txt",
    "content": "WARNING: w250 (cmp-with-container) Comparison with a array.\ntestData/static_analyzer/w250_array.nut:8:10\n\nlet _x = (::a != [])\n          ^--------\nlet _y = (::a != {})\n\n\nWARNING: w250 (cmp-with-container) Comparison with a declaration.\ntestData/static_analyzer/w250_array.nut:9:10\n\nlet _x = (::a != [])\nlet _y = (::a != {})\n          ^--------\nlet _z = (::a != t)\n\n\nWARNING: w250 (cmp-with-container) Comparison with a declaration.\ntestData/static_analyzer/w250_array.nut:11:11\n\nlet _z = (::a != t)\nlet _xx = (::a == @ (v) v)\n           ^-------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w250_array.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nlet t = []\n\nlet _x = (::a != [])\nlet _y = (::a != {})\nlet _z = (::a != t)\nlet _xx = (::a == @ (v) v)\n"
  },
  {
    "path": "testData/static_analyzer/w250_container.diag.txt",
    "content": "WARNING: w250 (cmp-with-container) Comparison with a declaration.\ntestData/static_analyzer/w250_container.nut:6:8\n\nreturn (::a != {})\n        ^--------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w250_container.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nreturn (::a != {})\n"
  },
  {
    "path": "testData/static_analyzer/w254.diag.txt",
    "content": "WARNING: w254 (bool-passed-to-strange) Boolean passed to 'in' operator.\ntestData/static_analyzer/w254.nut:6:4\n\nif (!\"weapModSlotName\" in ::item)\n    ^---------------------------\n  return null\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w254.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w254\n\nif (!\"weapModSlotName\" in ::item)\n  return null\n\n//-file:undefined-global\n"
  },
  {
    "path": "testData/static_analyzer/w254_instanceof.diag.txt",
    "content": "WARNING: w254 (bool-passed-to-strange) Boolean passed to 'instanceof' operator.\ntestData/static_analyzer/w254_instanceof.nut:6:4\n\nlocal x = 10\nif (x instanceof !\"weapModSlotName\")\n    ^------------------------------\n  return null\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w254_instanceof.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w254\nlocal x = 10\nif (x instanceof !\"weapModSlotName\")\n  return null\n"
  },
  {
    "path": "testData/static_analyzer/w254_notin.diag.txt",
    "content": "WARNING: w254 (bool-passed-to-strange) Boolean passed to 'in' operator.\ntestData/static_analyzer/w254_notin.nut:6:4\n\nif (!\"weapModSlotName\" not in ::item)\n    ^-------------------------------\n  return null\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w254_notin.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w254\n\nif (!\"weapModSlotName\" not in ::item)\n  return null\n\n//-file:undefined-global"
  },
  {
    "path": "testData/static_analyzer/w255.diag.txt",
    "content": "WARNING: w255 (duplicate-function) Duplicate function body. Consider functions 'onTimer2' and 'onTimer'.\ntestData/static_analyzer/w255.nut:29:4\n\n    function onTimer(obj, dt) {\n    ^\n      local curOffs = obj.cur_slide_offs.tofloat()\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w255.nut",
    "content": "//expect:w255\n//-file:undefined-global\n//-file:declared-never-used\n//-file:ident-hides-ident\n\n::ClassName <- class {\n    function onTimer2(obj, dt) {\n      local curOffs = obj.cur_slide_offs.tofloat()\n\n  //    local pos = obj.getPos()\n      local size = obj.getSize()\n      local parentSize = obj.getParent().getSize()\n      local speedCreditsScroll = (size[1] / parentSize[1] ) / ::timeToShowAll\n\n      if (::pos[1] + ::size[1] < 0) {\n        curOffs = -(0.9 * ::parentSize[1]).tointeger()\n        if (obj?.inited == \"yes\") {\n          ::on_credits_finish()\n          return\n        }\n        else\n          obj.inited=\"yes\"\n      } else\n        curOffs += dt * parentSize[1] * speedCreditsScroll //* 720 / parentSize[1] / 0.9\n      obj.cur_slide_offs = ::format(\"%f\", curOffs)\n      obj.top = (-curOffs).tointeger().tostring()\n    }\n\n    function onTimer(obj, dt) {\n      local curOffs = obj.cur_slide_offs.tofloat()\n\n  //    local pos = obj.getPos()\n      local size = obj.getSize()\n      local parentSize = obj.getParent().getSize()\n      local speedCreditsScroll = (size[1] / parentSize[1] ) / ::timeToShowAll\n\n      if (::pos[1] + ::size[1] < 0) {\n        curOffs = -(0.9 * ::parentSize[1]).tointeger()\n        if (obj?.inited == \"yes\") {\n          ::on_credits_finish()\n          return\n        }\n        else\n          obj.inited=\"yes\"\n      } else\n        curOffs += dt * parentSize[1] * speedCreditsScroll //* 720 / parentSize[1] / 0.9\n      obj.cur_slide_offs = ::format(\"%f\", curOffs)\n      obj.top = (-curOffs).tointeger().tostring()\n    }\n  }\n"
  },
  {
    "path": "testData/static_analyzer/w255_2.diag.txt",
    "content": "WARNING: w255 (duplicate-function) Duplicate function body. Consider functions 'onTimer2' and 'onTimer'.\ntestData/static_analyzer/w255_2.nut:31:4\n\n    function onTimer(obj, dt) {\n    ^\n      local curOffs = obj.cur_slide_offs.tofloat()\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w255_2.nut",
    "content": "//expect:w255\n//-file:undefined-global\n//-file:declared-never-used\n//-file:ident-hides-ident\n\n//expect:w255\n\nlocal class ClassName { //-declared-never-used\n    function onTimer2(obj, dt) {\n      local curOffs = obj.cur_slide_offs.tofloat()\n\n  //    local pos = obj.getPos()\n      local size = obj.getSize()\n      local parentSize = obj.getParent().getSize()\n      local speedCreditsScroll = (size[1] / parentSize[1] ) / ::timeToShowAll\n\n      if (::pos[1] + ::size[1] < 0) {\n        curOffs = -(0.9 * ::parentSize[1]).tointeger()\n        if (obj?.inited == \"yes\") {\n          ::on_credits_finish()\n          return\n        }\n        else\n          obj.inited=\"yes\"\n      } else\n        curOffs += dt * parentSize[1] * speedCreditsScroll //* 720 / parentSize[1] / 0.9\n      obj.cur_slide_offs = ::format(\"%f\", curOffs)\n      obj.top = (-curOffs).tointeger().tostring()\n    }\n\n    function onTimer(obj, dt) {\n      local curOffs = obj.cur_slide_offs.tofloat()\n\n  //    local pos = obj.getPos()\n      local size = obj.getSize()\n      local parentSize = obj.getParent().getSize()\n      local speedCreditsScroll = (size[1] / parentSize[1] ) / ::timeToShowAll\n\n      if (::pos[1] + ::size[1] < 0) {\n        curOffs = -(0.9 * ::parentSize[1]).tointeger()\n        if (obj?.inited == \"yes\") {\n          ::on_credits_finish()\n          return\n        }\n        else\n          obj.inited=\"yes\"\n      } else\n        curOffs += dt * parentSize[1] * speedCreditsScroll //* 720 / parentSize[1] / 0.9\n      obj.cur_slide_offs = ::format(\"%f\", curOffs)\n      obj.top = (-curOffs).tointeger().tostring()\n    }\n  }\n"
  },
  {
    "path": "testData/static_analyzer/w255_foreach_destr_distinct.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w255_foreach_destr_distinct.nut",
    "content": "// Two functions whose bodies differ only in the foreach destructuring pattern\n// must NOT be flagged as duplicate (w255) or similar (w258). Covers\n// diffForeach / cmpForeach including valDestructuring() in the comparison.\nfunction sum_xy(rows) {\n  local total = 0\n  foreach ({x, y = 0} in rows) {\n    total += x + y\n  }\n  return total\n}\n\nfunction sum_a_only(rows) {\n  local total = 0\n  foreach ({a, b = 0} in rows) {\n    total += a + b\n  }\n  return total\n}\n\nprintln(sum_xy([{x = 1, y = 2}]))\nprintln(sum_a_only([{a = 1, b = 2}]))\n"
  },
  {
    "path": "testData/static_analyzer/w256.diag.txt",
    "content": "WARNING: w256 (key-and-function-name) Key and function name are not the same ('_foo2' and 'bar2').\ntestData/static_analyzer/w256.nut:8:12\n\n  \"1foo\" : function bar1() {}, // FP 1, not id\n  \"_foo2\" : function bar2() {}, // EXPECTED 1\n            ^-----------------\n  \"foo3\" : function foo3() {}, // FP 2\n\n\nWARNING: w256 (key-and-function-name) Key and function name are not the same ('foo4' and 'bar5').\ntestData/static_analyzer/w256.nut:11:9\n\n  foo4 = function bar5() {}, // EXPECTED 2\n         ^-----------------\n  foo6 = function foo6() {}, // FP 3\n\n\nWARNING: w256 (key-and-function-name) Key and function name are not the same ('foo7' and 'bar7').\ntestData/static_analyzer/w256.nut:14:13\n\n  [\"foo7\"] = function bar7() {}, // EXPECTED 3\n             ^-----------------\n  [\"8foo\"] = function bar8() {}, // FP 4, not id\n\n\nWARNING: w256 (key-and-function-name) Key and function name are not the same ('qux' and 'fex').\ntestData/static_analyzer/w256.nut:21:10\n\ntt.foo <- bar // FP 5\ntt.qux <- function fex() {} // EXPECTED 4\n          ^----------------\ntt[\"fk\"] <- function uyte() {} // EXPECTED 5\n\n\nWARNING: w256 (key-and-function-name) Key and function name are not the same ('fk' and 'uyte').\ntestData/static_analyzer/w256.nut:22:12\n\ntt.qux <- function fex() {} // EXPECTED 4\ntt[\"fk\"] <- function uyte() {} // EXPECTED 5\n            ^-----------------\ntt[\"f:g:h\"] <- function fgh() {} // FP 6\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w256.nut",
    "content": "//expect:w256\n\nconst C = 1\n\nfunction bar() {}\nlet tt = {\n  \"1foo\" : function bar1() {}, // FP 1, not id\n  \"_foo2\" : function bar2() {}, // EXPECTED 1\n  \"foo3\" : function foo3() {}, // FP 2\n\n  foo4 = function bar5() {}, // EXPECTED 2\n  foo6 = function foo6() {}, // FP 3\n\n  [\"foo7\"] = function bar7() {}, // EXPECTED 3\n  [\"8foo\"] = function bar8() {}, // FP 4, not id\n\n  [C] = function bar9(_p) {}\n}\n\ntt.foo <- bar // FP 5\ntt.qux <- function fex() {} // EXPECTED 4\ntt[\"fk\"] <- function uyte() {} // EXPECTED 5\ntt[\"f:g:h\"] <- function fgh() {} // FP 6"
  },
  {
    "path": "testData/static_analyzer/w257.diag.txt",
    "content": "WARNING: w257 (duplicate-assigned-expr) Duplicate of the assigned expression.\ntestData/static_analyzer/w257.nut:17:26\n\n]\nlocal numTextAnimations = [\n                          ^\n  { prop=AnimProp.opacity, from=0.0, to=0.0, delay=0.0, duration=0.1, play=true easing=OutCubic }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w257.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w257\n//-file:undefined-global\n\nlocal OutCubic = 2\nlocal AnimProp = ::aaa\n\nlocal numAnimations = [\n  { prop=AnimProp.opacity, from=0.0, to=0.0, delay=0.0, duration=0.1, play=true easing=OutCubic }\n  { prop=AnimProp.scale, from=[2,2], to=[1,1], delay=0.1, duration=0.5, play=true easing=OutCubic }\n  { prop=AnimProp.opacity, from=0.0, to=1.0, delay=0.1, duration=0.5, play=true easing=OutCubic }\n  { prop=AnimProp.scale, from=[1,1], to=[2,2], delay=0.0, duration=0.1, playFadeOut=true easing=OutCubic }\n  { prop=AnimProp.opacity, from=1.0, to=0.0, delay=0.1, duration=0.1, playFadeOut=true easing=OutCubic }\n]\nlocal numTextAnimations = [\n  { prop=AnimProp.opacity, from=0.0, to=0.0, delay=0.0, duration=0.1, play=true easing=OutCubic }\n  { prop=AnimProp.scale, from=[2,2], to=[1,1], delay=0.1, duration=0.5, play=true easing=OutCubic }\n  { prop=AnimProp.opacity, from=0.0, to=1.0, delay=0.1, duration=0.5, play=true easing=OutCubic }\n  { prop=AnimProp.scale, from=[1,1], to=[2,2], delay=0.0, duration=0.1, playFadeOut=true easing=OutCubic }\n  { prop=AnimProp.opacity, from=1.0, to=0.0, delay=0.1, duration=0.1, playFadeOut=true easing=OutCubic }\n]\n\nreturn [numAnimations, numTextAnimations]\n"
  },
  {
    "path": "testData/static_analyzer/w258.diag.txt",
    "content": "WARNING: w258 (similar-function) Function bodies are very similar. Consider functions 'updateEventLb' and 'updateEventLbSelfRow'.\ntestData/static_analyzer/w258.nut:46:4\n\n    function updateEventLbSelfRow(requestData, id) {\n    ^\n      local requestAction = (@(requestData, id) function () {\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w258.nut",
    "content": "//expect:w257\n//-file:undefined-global\n//-file:ident-hides-ident\n//-file:declared-never-used\n//-file:similar-assigned-expr\n\n//expect:w258\nlocal canRequestEventLb = 10\nlet leaderboardsRequestStack = []\n\n::Aaa <- class {\n    function requestUpdateEventLb(x) {}\n    canRequestEventLb = false\n    leaderboardsRequestStack = []\n\n    function updateEventLb(requestData, id) {\n      local requestAction = (@(requestData, id) function () {\n        local taskId = ::requestUpdateEventLb(requestData)\n        if (taskId < 0)\n          return\n\n        canRequestEventLb = false\n        ::add_bg_task_cb(taskId, (@(requestData, id) function() {\n          ::handleLbRequest(requestData, id)\n\n          if (leaderboardsRequestStack.len())\n            ::array_shift(leaderboardsRequestStack).fn()\n          else\n            canRequestEventLb = true\n        })(requestData, id).bindenv(this))\n      })(requestData, id).bindenv(this)\n\n      if (canRequestEventLb)\n        return requestAction()\n\n      if (id)\n        foreach (index, request in leaderboardsRequestStack)\n          if (id == request)\n            leaderboardsRequestStack.remove(index)\n\n      leaderboardsRequestStack.append({fn = requestAction, id = id})\n    }\n\n\n\n    function updateEventLbSelfRow(requestData, id) {\n      local requestAction = (@(requestData, id) function () {\n        local taskId = ::requestEventLbSelfRow(requestData)\n        if (taskId < 0)\n          return\n\n        canRequestEventLb = false\n        ::add_bg_task_cb(taskId, (@(requestData, id) function() {\n          ::handleLbSelfRowRequest(requestData, id)\n\n          if (leaderboardsRequestStack.len())\n            ::array_shift(leaderboardsRequestStack).fn()\n          else\n            canRequestEventLb = true\n        })(requestData, id).bindenv(this))\n      })(requestData, id).bindenv(this)\n\n      if (canRequestEventLb)\n        return requestAction()\n\n      if (id)\n        foreach (index, request in leaderboardsRequestStack)\n          if (id == request)\n            leaderboardsRequestStack.remove(index)\n\n      leaderboardsRequestStack.append({fn = requestAction, id = id})\n    }\n  }\n\n\n\n//-file:modified-container\n"
  },
  {
    "path": "testData/static_analyzer/w258_2.diag.txt",
    "content": "WARNING: w258 (similar-function) Function bodies are very similar. Consider functions 'updateEventLb' and 'updateEventLbSelfRow'.\ntestData/static_analyzer/w258_2.nut:47:4\n\n    function updateEventLbSelfRow(requestData, id) {\n    ^\n      local requestAction = (@(requestData, id) function () {\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w258_2.nut",
    "content": "//expect:w257\n//-file:undefined-global\n//-file:ident-hides-ident\n//-file:declared-never-used\n//-file:similar-assigned-expr\n\n//expect:w258\n\nlocal canRequestEventLb = false\nlet leaderboardsRequestStack = []\n\nlocal class Aaa {\n    function requestUpdateEventLb(x) {}\n    canRequestEventLb = false\n    leaderboardsRequestStack = []\n\n    function updateEventLb(requestData, id) {\n      local requestAction = (@(requestData, id) function () {\n        local taskId = ::requestUpdateEventLb(requestData)\n        if (taskId < 0)\n          return\n\n        canRequestEventLb = false\n        ::add_bg_task_cb(taskId, (@(requestData, id) function() {\n          ::handleLbRequest(requestData, id)\n\n          if (leaderboardsRequestStack.len())\n            ::array_shift(leaderboardsRequestStack).fn()\n          else\n            canRequestEventLb = true\n        })(requestData, id).bindenv(this))\n      })(requestData, id).bindenv(this)\n\n      if (canRequestEventLb)\n        return requestAction()\n\n      if (id)\n        foreach (index, request in leaderboardsRequestStack)\n          if (id == request)\n            leaderboardsRequestStack.remove(index)\n\n      leaderboardsRequestStack.append({fn = requestAction, id = id})\n    }\n\n\n\n    function updateEventLbSelfRow(requestData, id) {\n      local requestAction = (@(requestData, id) function () {\n        local taskId = ::requestEventLbSelfRow(requestData)\n        if (taskId < 0)\n          return\n\n        canRequestEventLb = false\n        ::add_bg_task_cb(taskId, (@(requestData, id) function() {\n          ::handleLbSelfRowRequest(requestData, id)\n\n          if (leaderboardsRequestStack.len())\n            ::array_shift(leaderboardsRequestStack).fn()\n          else\n            canRequestEventLb = true\n        })(requestData, id).bindenv(this))\n      })(requestData, id).bindenv(this)\n\n      if (canRequestEventLb)\n        return requestAction()\n\n      if (id)\n        foreach (index, request in leaderboardsRequestStack)\n          if (id == request)\n            leaderboardsRequestStack.remove(index)\n\n      leaderboardsRequestStack.append({fn = requestAction, id = id})\n    }\n  }\n\n\n\n//-file:modified-container\n"
  },
  {
    "path": "testData/static_analyzer/w259.diag.txt",
    "content": "WARNING: w259 (similar-assigned-expr) Assigned expression is very similar to one of the previous ones.\ntestData/static_analyzer/w259.nut:23:26\n\nlocal numAnimations = ::a + ::b + ::c + ::d - (::a + ::b + ::c + ::d) * ::x + 123\nlocal numTextAnimations = ::a + ::b + ::c + ::d - (::a + ::b + ::c + ::d) * ::x + 124 // EXPECTED\n                          ^----------------------------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w259.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nfunction Computed(_p) {}\nlet au = {}\nconst PP = \"!1\"\nconst PM =\"2\"\n\nlet _tt = Computed(@() au.value\n  .findvalue(@(unlock) unlock?.name == PP))\n\nlet _ttp = Computed(@() au.value // FP 1\n  .findvalue(@(unlock) unlock?.name == PM))\n\nfunction S(_p) {}\n\nlet _P = @(...) S({p = vargv.len() > 1 ? vargv : vargv[0]})\nlet _M = @(...) S({m = vargv.len() > 1 ? vargv : vargv[0]}) // FP 2\n\nlocal numAnimations = ::a + ::b + ::c + ::d - (::a + ::b + ::c + ::d) * ::x + 123\nlocal numTextAnimations = ::a + ::b + ::c + ::d - (::a + ::b + ::c + ::d) * ::x + 124 // EXPECTED\n\nlet _xx = [numAnimations, numTextAnimations]\n\nlet D = {}\nlet amin = {}\nlet amax = {}\n\nlet _gg = Computed(@() D.value > 0 ? ((D.value * 1000.0 - amin.value) * 0.1 / D.value).tointeger() : 0)\nlet _ff = Computed(@() D.value > 0 ? ((D.value * 1000.0 - amax.value) * 0.1 / D.value).tointeger() : 0) // FP 3"
  },
  {
    "path": "testData/static_analyzer/w260_local_function.diag.txt",
    "content": "WARNING: w260 (named-like-must-return-result) Function 'getSettings' has name like it should return a value, but not all control paths return a value.\ntestData/static_analyzer/w260_local_function.nut:3:6\n\nlocal function getSettings(path) { return } //-declared-never-used\n      ^------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w260_local_function.nut",
    "content": "//expect:w260\n\nlocal function getSettings(path) { return } //-declared-never-used\n\nreturn getSettings\n"
  },
  {
    "path": "testData/static_analyzer/w260_table.diag.txt",
    "content": "WARNING: w260 (named-like-must-return-result) Function 'get_setting_by_blk_path' has name like it should return a value, but not all control paths return a value.\ntestData/static_analyzer/w260_table.nut:4:28\n\n::game <- {\n  get_setting_by_blk_path = function(path) { return } //-declared-never-used\n                            ^------------------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w260_table.nut",
    "content": "//expect:w260\n\n::game <- {\n  get_setting_by_blk_path = function(path) { return } //-declared-never-used\n}\n"
  },
  {
    "path": "testData/static_analyzer/w260_table_sqconfig.diag.txt",
    "content": "WARNING: w260 (named-like-must-return-result) Function 'make_and_return_object' has name like it should return a value, but not all control paths return a value.\ntestData/static_analyzer/w260_table_sqconfig.nut:4:27\n\n::game <- {\n  make_and_return_object = function(x) { return } //-declared-never-used\n                           ^---------------------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w260_table_sqconfig.nut",
    "content": "//expect:w260\n\n::game <- {\n  make_and_return_object = function(x) { return } //-declared-never-used\n}\n"
  },
  {
    "path": "testData/static_analyzer/w262.diag.txt",
    "content": "WARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:9:0\n\n    print(1)\nelse    // EXPECTED 1\n^---\n  print(2)\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:14:4\n\n    print(3)\n    print(4) // EXPECTED 2\n    ^----\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:18:4\n\n    print(x)\n    print(y) // EXPECTED 3\n    ^----\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:26:4\n\nprint(x)\n    print(y) // EXPECTED 4\n    ^----\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:30:4\n\n    print(x)\n    print(y) // EXPECTED 5\n    ^----\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:39:4\n\n    print(x)\n    print(y) // EXPECTED 6\n    ^----\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:25:0\n\nwhile (false)\nprint(x)\n^-------\n    print(y) // EXPECTED 4\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:58:0\n\nif (x) // EXPECTED 7\nif (y)\n^\n  print(1)\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:88:0\n\nwhile (x > 100)\nprint(3) // EXPECTED 8\n^-------\n\n\nWARNING: w262 (suspicious-formatting) Suspicious code formatting.\ntestData/static_analyzer/w262.nut:92:0\n\nfor (;false;)\nprint(3) // EXPECTED 9\n^-------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w262.nut",
    "content": "//-file:invalid-indentation\n\nlocal x = 10\nlocal y = 20\n\nif (x)\n  if (y)\n    print(1)\nelse    // EXPECTED 1\n  print(2)\n\nif (x)\n    print(3)\n    print(4) // EXPECTED 2\n\nwhile (false)\n    print(x)\n    print(y) // EXPECTED 3\n\nwhile (false)\n    print(x)\nprint(y) // FP 1\n\nwhile (false)\nprint(x)\n    print(y) // EXPECTED 4\n\nfor (;false;)\n    print(x)\n    print(y) // EXPECTED 5\n\nfor (;false;)\n    print(x)\nprint(y) // FP 2\n\n\nforeach (_z in [])\n    print(x)\n    print(y) // EXPECTED 6\n\nforeach (_z in [])\n    print(x)\nprint(y) // FP 3\n\n\nif (x) {\n    print(10)\n} else // FP 4\n    print(20)\n\nif (x) {\n    print(10)\n} else if (y) { // FP 5\n    print(20)\n}\n\nif (x) // EXPECTED 7\nif (y)\n  print(1)\nelse\nprint(2)\n\n\nfunction _f1() {\nprint(1)\nprint(2)\n}\n\n\nfunction _f2() {\nprint(1)\nprint(2)\n}\n\n\nif (x); // -empty-body\nprint(3)\n\n\nwhile (x > 100); // -empty-body\nprint(3)\n\n\nfor (;false;); // -empty-body\nprint(3)\n\nwhile (x > 100)\nprint(3) // EXPECTED 8\n\n\nfor (;false;)\nprint(3) // EXPECTED 9\n\n\n\nlocal e = 10, d = 20, _z = null, aD = 2, eD = 3\n\nif (e){\n    _z = { s = \"e\", ss = \"p\" }\n\n} else if (d > 0) { // FP 6\n    if (aD > eD)\n        _z = { s = \"a\", ss = \"p\" }\n    else\n        _z = { s = \"e\", ss = \"m\" }\n\n}"
  },
  {
    "path": "testData/static_analyzer/w263.diag.txt",
    "content": "WARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:4:0\n\nfor (local i = 0; i < 5; i++) // EXPECTED\n{\n^\n  print(i)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:9:0\n\nfunction _foo(_p) // EXPECTED\n{\n^\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:23:0\n\nclass _B // EXPECTED\n{\n^\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:32:0\n\nenum _E2    // EXPECTED\n{\n^\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:43:0\n\ntry // EXPECTED\n{\n^\n    print(8)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:46:0\n\n} catch (_e) // EXPECTED\n{\n^\n    print(9)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:59:0\n\nif (!t) // EXPECTED\n{\n^\n    print(12)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:62:0\n\n} else  // EXPECTED\n{\n^\n    print(13)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:71:0\n\nwhile (t)   // EXPECTED\n{\n^\n    print(15)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:80:0\n\ndo  // EXPECTED\n{\n^\n    print(17)\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:91:4\n\n    default:    // EXPECTED\n    {\n    ^\n        break;\n\n\nWARNING: w263 (egyptian-braces) Indentation style: 'egyptian braces' required.\ntestData/static_analyzer/w263.nut:97:0\n\nswitch (t)  // EXPECTED\n{\n^\n    case 2:\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w263.nut",
    "content": "#allow-switch-statement\n\nfor (local i = 0; i < 5; i++) // EXPECTED\n{\n  print(i)\n}\n\nfunction _foo(_p) // EXPECTED\n{\n\n}\n\n\nfunction bar() { // FP\n    return false\n}\n\nclass _A { // FP\n\n}\n\nclass _B // EXPECTED\n{\n\n}\n\nenum _E1 { // FP\n\n}\n\nenum _E2    // EXPECTED\n{\n\n}\n\ntry { // FP\n    print(6)\n} catch (_e) { // FP\n    print(7)\n}\n\ntry // EXPECTED\n{\n    print(8)\n} catch (_e) // EXPECTED\n{\n    print(9)\n}\n\nlocal t = bar()\n\nif (t) {    // FP\n    print(10)\n} else { // FP\n    print(11)\n}\n\nif (!t) // EXPECTED\n{\n    print(12)\n} else  // EXPECTED\n{\n    print(13)\n}\n\nwhile (t) { // FP\n    print(14)\n}\n\nwhile (t)   // EXPECTED\n{\n    print(15)\n}\n\ndo {    // FP\n    print(16)\n} while (t)\n\ndo  // EXPECTED\n{\n    print(17)\n} while (t)\n\nswitch (t) {    // FP\n    case 1:\n        break;\n    case 2: { // FP\n        break;\n    }\n    default:    // EXPECTED\n    {\n        break;\n    }\n}\n\nswitch (t)  // EXPECTED\n{\n    case 2:\n        break;\n    default:\n        break;\n}"
  },
  {
    "path": "testData/static_analyzer/w264.diag.txt",
    "content": "WARNING: w264 (plus-string) Usage of '+' for string concatenation.\ntestData/static_analyzer/w264.nut:7:7\n\nreturn a + 3\n       ^----\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w264.nut",
    "content": "//expect:w264\n\nlocal a = \"{0}\".subst(null)\nif (a != \"\")\n  return null\n\nreturn a + 3\n"
  },
  {
    "path": "testData/static_analyzer/w266.diag.txt",
    "content": "WARNING: w266 (forgotten-do) 'while' after the statement list (forgot 'do' ?)\ntestData/static_analyzer/w266.nut:10:2\n\n  ::x++\n} while (::x)\n  ^\n::x--\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w266.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:suspicious-formatting\n//-file:undefined-global\n//-file:invalid-indentation\n\n{\n  ::x++\n} while (::x)\n::x--\n"
  },
  {
    "path": "testData/static_analyzer/w267.diag.txt",
    "content": "WARNING: w267 (suspicious-bracket) '(' will be parsed as 'function call' (forgot ',' ?)\ntestData/static_analyzer/w267.nut:11:7\n\nfoo(s1 (6+7)) // EXPECTED 1\n       ^\n\n\nWARNING: w267 (suspicious-bracket) '[' will be parsed as 'access to member' (forgot ',' ?)\ntestData/static_analyzer/w267.nut:13:7\n\nfoo(s2 [6]) // EXPECTED 2 access\n       ^\n\n\nWARNING: w267 (suspicious-bracket) '[' will be parsed as 'access to member' (forgot ',' ?)\ntestData/static_analyzer/w267.nut:19:7\n\n//    [6]       // compilation error\n    s3 [7]     // EXPECTED 3   access\n       ^\n    s4 (6+7)   // EXPECTED 4\n\n\nWARNING: w267 (suspicious-bracket) '(' will be parsed as 'function call' (forgot ',' ?)\ntestData/static_analyzer/w267.nut:20:7\n\n    s3 [7]     // EXPECTED 3   access\n    s4 (6+7)   // EXPECTED 4\n       ^\n    \"z\"\n\n\nWARNING: w267 (suspicious-bracket) '(' will be parsed as 'function call' (forgot ',' ?)\ntestData/static_analyzer/w267.nut:22:4\n\n    \"z\"\n    (6+7)       // EXPECTED 5\n    ^\n]\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w267.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n// -file:paren-is-function-call\n\n\nfunction foo(...) {}\nlet s1 = \"sum=\"\nlet s2 = \"array:\"\n\nfoo(s1 (6+7)) // EXPECTED 1\n\nfoo(s2 [6]) // EXPECTED 2 access\n\nlet s3 = \"t\", s4 = \"y\"\nlet _x = [\n    \"x\"\n//    [6]       // compilation error\n    s3 [7]     // EXPECTED 3   access\n    s4 (6+7)   // EXPECTED 4\n    \"z\"\n    (6+7)       // EXPECTED 5\n]\n\nfoo(foo(\"b\"))    // FP\n"
  },
  {
    "path": "testData/static_analyzer/w269.diag.txt",
    "content": "WARNING: w269 (mixed-separators) Mixed spaces and commas to separate elements of array.\ntestData/static_analyzer/w269.nut:4:6\n\n    20\n    30,\n      ^\n    40,\n\n\nWARNING: w269 (mixed-separators) Mixed spaces and commas to separate elements of array.\ntestData/static_analyzer/w269.nut:13:4\n\n    30\n    40\n    ^-\n    50\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w269.nut",
    "content": "let _a = [\n    10\n    20\n    30,\n    40,\n    50\n]\n\nlet _b = [\n    10,\n    20,\n    30\n    40\n    50\n]\n\nlet _c = [\n    10,\n    20,\n    30,\n    40,\n    50\n]\n\n\nlet _d = [\n    10\n    20\n    30\n    40\n    50\n]"
  },
  {
    "path": "testData/static_analyzer/w270.diag.txt",
    "content": "HINT: h270 (extent-to-append) It is better to use 'append(A, B, ...)' instead of 'extend([A, B, ...])'.\ntestData/static_analyzer/w270.nut:6:0\n\n::handlersManager[::PERSISTENT_DATA_PARAMS].extend([ \"curControlsAllowMask\", \"isCurSceneBgBlurred\" ]) // -undefined-global\n^----------------------------------------------------------------------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w270.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w270\n\n::handlersManager[::PERSISTENT_DATA_PARAMS].extend([ \"curControlsAllowMask\", \"isCurSceneBgBlurred\" ]) // -undefined-global\n"
  },
  {
    "path": "testData/static_analyzer/w271.diag.txt",
    "content": "WARNING: w271 (forgot-subst) '{}' found inside string (forgot 'subst' or '$' ?).\ntestData/static_analyzer/w271.nut:9:15\n\n    else\n        return \"$ xxxx={x}\"  // EXPECTED\n               ^-----------\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w271.nut",
    "content": "//-file:declared-never-used\n\nfunction loc(...) {}\n\nfunction _foo(x) {\n    if (x == 4)\n        return $\"$ yyyy={x}\" // FP 1\n    else\n        return \"$ xxxx={x}\"  // EXPECTED\n}\n\nfunction _bar(a, b) {\n    return \"{a}/{b}\".subst({a=a b=b}) // FP 2\n}\n\nfunction _qux(a, b) {\n    return loc(\"bb/aa\", \"{x} ({y})\", {x=b y=b})  // FP 3\n}\n\nfunction _bex(a, b) {\n    return \"jsadkl askdjal kjad\".split(\"{css}\") // FP 4\n}\n"
  },
  {
    "path": "testData/static_analyzer/w272.diag.txt",
    "content": "WARNING: w272 (not-unary-op) This '-' is not a unary operator. Please use ' ' after it or ',' before it for better understandability.\ntestData/static_analyzer/w272.nut:5:4\n\n    2\n   -3   // EXPECTED 1\n    ^\n    4\n\n\nWARNING: w272 (not-unary-op) This '+' is not a unary operator. Please use ' ' after it or ',' before it for better understandability.\ntestData/static_analyzer/w272.nut:12:5\n\n    0\n    +1  // EXPECTED 2\n     ^\n    2\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w272.nut",
    "content": "function foo(...) {}\n\nlet _a = [ 0\n    2\n   -3   // EXPECTED 1\n    4\n  - 5   // FP 1\n  ]\n\nfoo(\n    0\n    +1  // EXPECTED 2\n    2\n    + 3 // FP 2\n    4\n    * 5 // FP 3\n    14\n    /7  // FP 4\n\n)\n\n"
  },
  {
    "path": "testData/static_analyzer/w275.diag.txt",
    "content": "WARNING: w275 (missed-break) A 'break' statement is probably missing in a 'switch' statement.\ntestData/static_analyzer/w275.nut:20:6\n\n    case 4:\n      print(\"ccc\")\n      ^-----------\n    default:        // <<<<<<< here\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w275.nut",
    "content": "#allow-switch-statement\n//expect:w275\n\nfunction fn(x) { //-declared-never-used\n  switch (x) {\n    case 0:\n    case 1:\n    case 2:\n      print(\"aaa\")\n      if (x == 1) {\n        return\n      } else {\n        print(\"123\")\n        return\n      }\n    case 3:\n      print(\"bbb\")\n      break\n    case 4:\n      print(\"ccc\")\n    default:        // <<<<<<< here\n      print(\"ddd\")\n  }\n}\n"
  },
  {
    "path": "testData/static_analyzer/w275_all_variants.diag.txt",
    "content": "WARNING: w275 (missed-break) A 'break' statement is probably missing in a 'switch' statement.\ntestData/static_analyzer/w275_all_variants.nut:9:8\n\n    case 1:\n        foo();   // OK\n        ^----\n    case 2: {\n\n\nWARNING: w275 (missed-break) A 'break' statement is probably missing in a 'switch' statement.\ntestData/static_analyzer/w275_all_variants.nut:20:8\n\n    case 3:\n        foo()    // OK\n        ^----\n    default:\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w275_all_variants.nut",
    "content": "#allow-switch-statement\n\nfunction foo() {}\n\nlet x = foo()\n\nswitch (x) {\n    case 1:\n        foo();   // OK\n    case 2: {\n            {\n                foo();\n                {\n                    foo();\n                    break;   // WRONG\n                }\n            }\n        }\n    case 3:\n        foo()    // OK\n    default:\n        foo()\n        break;   // WRONG\n}\n\n\nswitch (x) {\n    case 2:\n        foo();\n        break;    // WRONG\n    case 3:\n        foo();\n        ;         // WRONG -missed-break\n    default:\n        foo()     // WRONG\n}\n\n\nswitch (x) {\n    case 1:         //WRONG\n    case 2:\n        foo();\n        break;      // WRONG\n    case 3:\n        foo()\n        ;           // WRONG -missed-break\n}\n\n\nswitch (x) {\n    case 1:\n        foo()\n        break       // WRONG\n    case 2:\n    case 3:         // WRONG\n}"
  },
  {
    "path": "testData/static_analyzer/w275_complex.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w275_complex.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n// No warnings here - the switch statement is large, but breaks are in every branch\n\n#allow-switch-statement\n\nfunction foo(_a, _b) {}\nfunction bar() {}\n\nlet d = bar()\nlet bgs = bar()\nlet ab = bar()\nlet sb = bar()\n\nlocal someBound = false\nswitch (d.a() & d.M) {\n  case d.D: {\n    foreach (val in bgs)\n      if (foo(10, val)) {\n        someBound = true\n        break\n      }\n    break\n  }\n  case d.A: {\n    foreach (val in ab) {\n      if (foo(val, 102)) {\n        someBound = true\n        break\n      }\n\n      if (foo(3, val.mn.devId) && foo(4, val.mx.devId)) {\n        someBound = true\n        break\n      }\n\n    }\n    break\n  }\n  case d.T: {\n    foreach (val in sb) {\n      if (val.di == d.P || val.di == d.J || val.di == d.G || val.di == d.N) {\n        someBound = true\n        break\n      }\n      if (foo(4, val.mx.di) && foo(5, val.mx.di)\n        && foo(7, val.my.di) && foo(8, val.my.di)) {\n        someBound = true\n        break\n      }\n    }\n    break\n  }\n}\n\nfoo(4, someBound)\n"
  },
  {
    "path": "testData/static_analyzer/w277.diag.txt",
    "content": "WARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:4:0\n\n \n^\n//expect:w277\n\n\nWARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:6:0\n\n//expect:w277\n \n^\n//expect:w277 \n\n\nWARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:7:13\n\n//expect:w277 \n             ^\n\n\nWARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:11:17\n\nfunction _foo() { \n                 ^\n  return 10\n\n\nWARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:16:14\n\n//expect:w277\nlet _z = @\"abc \n              ^\n\"\n\n\nWARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:21:9\n\n/*    aas \n         ^\n*/\n\n\nWARNING: w277 (space-at-eol) Whitespace at the end of line.\ntestData/static_analyzer/w277.nut:24:0\n\n \n^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w277.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n \n//expect:w277\n \n//expect:w277 \n\n\n\nfunction _foo() { \n  return 10\n}\n\n//expect:w277\nlet _z = @\"abc \n\"\n\n\n\n/*    aas \n*/\n\n "
  },
  {
    "path": "testData/static_analyzer/w279_1.diag.txt",
    "content": "WARNING: w279 (mismatch-loop-variable) The variable used in for-loop does not match the initialized one.\ntestData/static_analyzer/w279_1.nut:4:18\n\nlocal j;\nfor (local k = 0; j < 5; k++) {\n                  ^----\n    j = 10\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w279_1.nut",
    "content": "//-file:potentially-nulled-ops\n\nlocal j;\nfor (local k = 0; j < 5; k++) {\n    j = 10\n }\n"
  },
  {
    "path": "testData/static_analyzer/w279_2.diag.txt",
    "content": "WARNING: w279 (mismatch-loop-variable) The variable used in for-loop does not match the initialized one.\ntestData/static_analyzer/w279_2.nut:4:25\n\nlocal j = 0;\nfor (local k = 0; k < 5; j++) {\n                         ^--\n    k = 10\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w279_2.nut",
    "content": "//expect:w279\n\nlocal j = 0;\nfor (local k = 0; k < 5; j++) {\n    k = 10\n }\n"
  },
  {
    "path": "testData/static_analyzer/w280.diag.txt",
    "content": "WARNING: w280 (forbidden-parent-dir) Access to the parent directory is forbidden in this function.\ntestData/static_analyzer/w280.nut:6:9\n\nlet _x = require_optional(\"../a.nut\")\n         ^---------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w280.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w280\n\nlet _x = require_optional(\"../a.nut\")\n"
  },
  {
    "path": "testData/static_analyzer/w281.diag.txt",
    "content": "WARNING: w281 (unwanted-modification) Function 'extend' modifies the object. You probably didn't want to modify the object here.\ntestData/static_analyzer/w281.nut:13:9\n\nfunction fn(arr) {\n  return (arr ?? []).extend(x)\n         ^--------------------\n//  ::y <- (arr ?? []).extend(x)\n\n\nWARNING: w281 (unwanted-modification) Function 'extend' modifies the object. You probably didn't want to modify the object here.\ntestData/static_analyzer/w281.nut:18:12\n\nlocal tab = {\n    watch = (::alertWatched ? ::alertWatched : []).extend(::titleWatched ? ::titleWatched : [])\n            ^----------------------------------------------------------------------------------\n  }\n\n\nWARNING: w281 (unwanted-modification) Function 'extend' modifies the object. You probably didn't want to modify the object here.\ntestData/static_analyzer/w281.nut:21:36\n\nlocal getSeasonMainPrizesData = @() (::premiumUnlock.value?.meta.promo ?? [])\n                                    ^\n  .extend(::basicUnlock.value?.meta.promo ?? [])\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w281.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//expect:w281\n//-file:declared-never-used\n//-file:undefined-global\n\n\nlocal x = [1, 2]\nlocal z = 555\n\nfunction fn(arr) {\n  return (arr ?? []).extend(x)\n//  ::y <- (arr ?? []).extend(x)\n}\n\nlocal tab = {\n    watch = (::alertWatched ? ::alertWatched : []).extend(::titleWatched ? ::titleWatched : [])\n  }\n\nlocal getSeasonMainPrizesData = @() (::premiumUnlock.value?.meta.promo ?? [])\n  .extend(::basicUnlock.value?.meta.promo ?? [])\n\nfunction baz(arr) {\n  // both are temporaries - no warning needed\n  return (x[0] ? [z] : []).extend(x)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w283.diag.txt",
    "content": "WARNING: w283 (useless-null-coalescing) The expression to the right of the '??' is null.\ntestData/static_analyzer/w283.nut:9:21\n\nfunction fn(x) {\n    return ::y.cc ?? x ?? null\n                     ^--------\n}\n\n\nWARNING: w283 (useless-null-coalescing) The expression to the right of the '??' is null.\ntestData/static_analyzer/w283.nut:13:10\n\nlocal s = null\nlocal x = ::y ?? s\n          ^-------\nreturn x\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w283.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:declared-never-used\n//-file:undefined-global\n\n\nfunction fn(x) {\n    return ::y.cc ?? x ?? null\n}\n\nlocal s = null\nlocal x = ::y ?? s\nreturn x\n"
  },
  {
    "path": "testData/static_analyzer/w284.diag.txt",
    "content": "WARNING: w284 (can-be-simplified) Expression can be simplified.\ntestData/static_analyzer/w284.nut:10:10\n\nlet _c1 = ::a > 2 || ::a > 100\n          ^-------------------\n\n\nWARNING: w284 (can-be-simplified) Expression can be simplified.\ntestData/static_analyzer/w284.nut:12:10\n\nlet _c2 = fn(1) != null ? fn(1) : null\n          ^---------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w284.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\nfunction fn(x) {\n  return ::y(x)\n}\n\nlet _c1 = ::a > 2 || ::a > 100\n\nlet _c2 = fn(1) != null ? fn(1) : null\n"
  },
  {
    "path": "testData/static_analyzer/w285.diag.txt",
    "content": "WARNING: w285 (expr-cannot-be-null) The expression to the left of the 'null coalescing' cannot be null.\ntestData/static_analyzer/w285.nut:9:5\n\nlocal uu = ::sys.gh(\"fff\") ?? \"\"\nif ((uu ?? \"\") != \"\")\n     ^-\n  print($\"x: {uu}\")\n\n\nWARNING: w285 (expr-cannot-be-null) The expression to the left of the 'null coalescing' cannot be null.\ntestData/static_analyzer/w285.nut:13:42\n\nlocal regions = ::unlock?.meta.regions ?? [::unlock?.meta.region] ?? []\n                                          ^----------------------\n\n\nWARNING: w285 (expr-cannot-be-null) The expression to the left of the 'null coalescing' cannot be null.\ntestData/static_analyzer/w285.nut:16:9\n\nlocal regions2 = ::x ? [] : {}\nlet _g = regions2 ?? 123\n         ^-------\n\n\nWARNING: w285 (expr-cannot-be-null) The expression to the left of the 'equal check' cannot be null.\ntestData/static_analyzer/w285.nut:20:9\n\nlocal regions3 = ::x ? 2 : 4\nlet _h = regions3 != null\n         ^-------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w285.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n//-file:declared-never-used\n\n\nlocal uu = ::sys.gh(\"fff\") ?? \"\"\nif ((uu ?? \"\") != \"\")\n  print($\"x: {uu}\")\n\n\nlocal regions = ::unlock?.meta.regions ?? [::unlock?.meta.region] ?? []\n\nlocal regions2 = ::x ? [] : {}\nlet _g = regions2 ?? 123\n\n\nlocal regions3 = ::x ? 2 : 4\nlet _h = regions3 != null\n\n// This caused a false positive, but the bug was fixed\nfunction _foo(a=null){\n  let b = a\n  a = a ?? 3\n  return [b ?? 2, a]\n}\n"
  },
  {
    "path": "testData/static_analyzer/w286.diag.txt",
    "content": "WARNING: w286 (decl-in-expression) Declaration used in arith expression as operand.\ntestData/static_analyzer/w286.nut:5:7\n\nreturn fn1 || ::fn2 // -undefined-global\n       ^--\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w286.nut",
    "content": "//expect:w286\n\nfunction fn1() {}\n\nreturn fn1 || ::fn2 // -undefined-global\n"
  },
  {
    "path": "testData/static_analyzer/w286_2.diag.txt",
    "content": "WARNING: w286 (decl-in-expression) Declaration used in arith expression as operand.\ntestData/static_analyzer/w286_2.nut:10:7\n\nreturn cls || ::fn2 //-const-in-bool-expr -undefined-global\n       ^--\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w286_2.nut",
    "content": "//expect:w286\n\n\nlocal cls = class {\n\n}\n\n\n\nreturn cls || ::fn2 //-const-in-bool-expr -undefined-global\n"
  },
  {
    "path": "testData/static_analyzer/w286_oror_andand.diag.txt",
    "content": "WARNING: w286 (decl-in-expression) Declaration used in arith expression as operand.\ntestData/static_analyzer/w286_oror_andand.nut:7:9\n\nlet _p = t?.x || {}\nlet _x = {} || t?.y\n         ^-\nlet _y = t?.z && []\n\n\nWARNING: w286 (decl-in-expression) Declaration used in arith expression as operand.\ntestData/static_analyzer/w286_oror_andand.nut:9:9\n\nlet _y = t?.z && []\nlet _z = [] && t?.g\n         ^-\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w286_oror_andand.nut",
    "content": "//-file:const-in-bool-expr\n//-file:expr-cannot-be-null\n\nlet t = {}\n\nlet _p = t?.x || {}\nlet _x = {} || t?.y\nlet _y = t?.z && []\nlet _z = [] && t?.g\n"
  },
  {
    "path": "testData/static_analyzer/w287.diag.txt",
    "content": "WARNING: w287 (range-check) It looks like the range boundaries are not checked correctly. Pay attention to checking with minimum and maximum index.\ntestData/static_analyzer/w287.nut:10:10\n\nlet e1 = (curVal < 0 || curVal > x) // EXPECTED 1\n          ^-----------------------\nlet c1 = (curVal < 0 || curVal >= x) // FP 1\n\n\nWARNING: w287 (range-check) It looks like the range boundaries are not checked correctly. Pay attention to checking with minimum and maximum index.\ntestData/static_analyzer/w287.nut:16:9\n\nlet e2 = (value >= 0) && (value <= cnt) // EXPECTED 2\n         ^----------------------------\nlet c2 = (value >= 0) && (value < cnt) // FP 2\n\n\nWARNING: w287 (range-check) It looks like the range boundaries are not checked correctly. Pay attention to checking with minimum and maximum index.\ntestData/static_analyzer/w287.nut:19:10\n\nlet e3 = (::idx < 0 || ::idx > ::tblObj.childrenCount()) // EXPECTED 3\n          ^--------------------------------------------\nlet c3 = (::idx < 0 || ::idx >= ::tblObj.childrenCount()) // FP 3\n\n\nWARNING: w287 (range-check) It looks like the range boundaries are not checked correctly. Pay attention to checking with minimum and maximum index.\ntestData/static_analyzer/w287.nut:22:10\n\nlet e4 = (0 <= value && value <= ::obj.childrenCount()) // EXPECTED 4\n          ^-------------------------------------------\nlet c4 = (0 <= value && value < ::obj.childrenCount()) // FP 4\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w287.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n//-file:declared-never-used\n\nlocal curVal = ::a\nlocal x = ::g_chat.rooms.len()\n\nlet e1 = (curVal < 0 || curVal > x) // EXPECTED 1\nlet c1 = (curVal < 0 || curVal >= x) // FP 1\n\nlocal value = ::a\nlocal cnt = ::listObj.childrenCount()\n\nlet e2 = (value >= 0) && (value <= cnt) // EXPECTED 2\nlet c2 = (value >= 0) && (value < cnt) // FP 2\n\nlet e3 = (::idx < 0 || ::idx > ::tblObj.childrenCount()) // EXPECTED 3\nlet c3 = (::idx < 0 || ::idx >= ::tblObj.childrenCount()) // FP 3\n\nlet e4 = (0 <= value && value <= ::obj.childrenCount()) // EXPECTED 4\nlet c4 = (0 <= value && value < ::obj.childrenCount()) // FP 4"
  },
  {
    "path": "testData/static_analyzer/w288.diag.txt",
    "content": "WARNING: w288 (param-count) Function '(w288.nut:4)' (2..2147483647 parameters) is called with the wrong number of arguments (1).\ntestData/static_analyzer/w288.nut:7:7\n\nlocal b = 1\nreturn fn(b)\n       ^----\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288.nut:4:11\n\nlocal fn = function (aaa_x, bbb, ...) {return aaa_x + bbb}\n           ^----------------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w288.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlocal fn = function (aaa_x, bbb, ...) {return aaa_x + bbb}\n\nlocal b = 1\nreturn fn(b)\n"
  },
  {
    "path": "testData/static_analyzer/w288_dp_va.diag.txt",
    "content": "WARNING: w288 (param-count) Function 'foo' (1..3 parameters) is called with the wrong number of arguments (4).\ntestData/static_analyzer/w288_dp_va.nut:15:0\n\nfoo(10, 20, 30, 40)\n^------------------\nfoo(10, 20, 30)\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_dp_va.nut:8:0\n\nfunction foo(_x, _y = 10, _z = 20) {}\n^------------------------------------\n\n\nWARNING: w288 (param-count) Function 'foo' (1..3 parameters) is called with the wrong number of arguments (0).\ntestData/static_analyzer/w288_dp_va.nut:19:0\n\nfoo(10)\nfoo()\n^----\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_dp_va.nut:8:0\n\nfunction foo(_x, _y = 10, _z = 20) {}\n^------------------------------------\n\n\nWARNING: w288 (param-count) Function 'bar' (2..2147483647 parameters) is called with the wrong number of arguments (0).\ntestData/static_analyzer/w288_dp_va.nut:22:0\n\nbar()\n^----\nbar(10)\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_dp_va.nut:10:0\n\nfunction bar(_x, _y, ...) {}\n^---------------------------\n\n\nWARNING: w288 (param-count) Function 'bar' (2..2147483647 parameters) is called with the wrong number of arguments (1).\ntestData/static_analyzer/w288_dp_va.nut:23:0\n\nbar()\nbar(10)\n^------\nbar(10, 20)\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_dp_va.nut:10:0\n\nfunction bar(_x, _y, ...) {}\n^---------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w288_dp_va.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:declared-never-used\n\nfunction comp(...) {}\n\nfunction foo(_x, _y = 10, _z = 20) {}\n\nfunction bar(_x, _y, ...) {}\n\nlet FlowH = 30\nlet hflow = @(...) comp(FlowH, vargv)\n\nfoo(10, 20, 30, 40)\nfoo(10, 20, 30)\nfoo(10, 20)\nfoo(10)\nfoo()\n\n\nbar()\nbar(10)\nbar(10, 20)\nbar(10, 20, 30)\nbar(10, 20, 30, 40)"
  },
  {
    "path": "testData/static_analyzer/w288_lambdas2.diag.txt",
    "content": ""
  },
  {
    "path": "testData/static_analyzer/w288_lambdas2.nut",
    "content": "for (local x = 0; x != 0; ++x)\n    let _f = (@(val) @(arg) type(arg) == val)(\"sss\")\n"
  },
  {
    "path": "testData/static_analyzer/w288_native.diag.txt",
    "content": "WARNING: w288 (param-count) Function 'floor' (1..1 parameters) is called with the wrong number of arguments (0).\ntestData/static_analyzer/w288_native.nut:6:9\n\nlet _x = floor()\n         ^------\nlet _y = floor(111.111, 222.222)\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_native.nut:1:0\n\nfrom \"math\" import floor, clamp\n^\n\n\nWARNING: w288 (param-count) Function 'floor' (1..1 parameters) is called with the wrong number of arguments (2).\ntestData/static_analyzer/w288_native.nut:7:9\n\nlet _x = floor()\nlet _y = floor(111.111, 222.222)\n         ^----------------------\nlet _z = clamp(1, 2)\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_native.nut:1:0\n\nfrom \"math\" import floor, clamp\n^\n\n\nWARNING: w288 (param-count) Function 'clamp' (3..3 parameters) is called with the wrong number of arguments (2).\ntestData/static_analyzer/w288_native.nut:8:9\n\nlet _y = floor(111.111, 222.222)\nlet _z = clamp(1, 2)\n         ^----------\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_native.nut:1:0\n\nfrom \"math\" import floor, clamp\n^\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w288_native.nut",
    "content": "from \"math\" import floor, clamp\n\nif (__name__ == \"__analysis__\")\n  return\n\nlet _x = floor()\nlet _y = floor(111.111, 222.222)\nlet _z = clamp(1, 2)\n"
  },
  {
    "path": "testData/static_analyzer/w288_require.diag.txt",
    "content": "WARNING: w288 (param-count) Function '(module_foo.nut:1)' (2..2 parameters) is called with the wrong number of arguments (1).\ntestData/static_analyzer/w288_require.nut:2:20\n\nlet { foo } = require(\"testData/static_analyzer/module_foo.nut\")\nreturn { bar = @(x) foo(x) }\n                    ^-----\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_require.nut:1:6\n\nlet { foo } = require(\"testData/static_analyzer/module_foo.nut\")\n      ^--\nreturn { bar = @(x) foo(x) }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w288_require.nut",
    "content": "let { foo } = require(\"testData/static_analyzer/module_foo.nut\")\nreturn { bar = @(x) foo(x) }\n"
  },
  {
    "path": "testData/static_analyzer/w288_require_indirect.diag.txt",
    "content": "WARNING: w288 (param-count) Function '(module_foo.nut:1)' (2..2 parameters) is called with the wrong number of arguments (1).\ntestData/static_analyzer/w288_require_indirect.nut:3:20\n\nlet foo = mod.foo\nreturn { bar = @(x) foo(x) }\n                    ^-----\n\n\nHINT: h314 (see-other) You can find the function here.\ntestData/static_analyzer/w288_require_indirect.nut:2:10\n\nlet mod = require(\"testData/static_analyzer/module_foo.nut\")\nlet foo = mod.foo\n          ^------\nreturn { bar = @(x) foo(x) }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w288_require_indirect.nut",
    "content": "let mod = require(\"testData/static_analyzer/module_foo.nut\")\nlet foo = mod.foo\nreturn { bar = @(x) foo(x) }\n"
  },
  {
    "path": "testData/static_analyzer/w289.diag.txt",
    "content": "WARNING: w289 (param-pos) The function parameter 'aaax' seems to be in the wrong position.\ntestData/static_analyzer/w289.nut:6:13\n\nlocal b = -1;\nreturn fn(b, aaaX);\n             ^---\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w289.nut",
    "content": "//expect:w289\nfunction fn(aaa_x, bbb, ...) {return aaa_x + bbb}\n\nlocal aaaX = 1;\nlocal b = -1;\nreturn fn(b, aaaX);"
  },
  {
    "path": "testData/static_analyzer/w291.diag.txt",
    "content": "WARNING: w291 (invalid-underscore) The name of parameter '_y' is invalid. The identifier is marked as unused with a prefix underscore, but it is used.\ntestData/static_analyzer/w291.nut:6:4\n\n    x,\n    _y,  // EXPECTED\n    ^-\n    _z   // FP\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w291.nut",
    "content": "\n\n\nfunction _foo(\n    x,\n    _y,  // EXPECTED\n    _z   // FP\n    ) {\n    return x + _y;\n}\n"
  },
  {
    "path": "testData/static_analyzer/w292.diag.txt",
    "content": "WARNING: w292 (modified-container) The container was modified within the loop.\ntestData/static_analyzer/w292.nut:14:4\n\nforeach (a in c) {\n    delete c.x          // EXPECTED 1\n    ^---------\n    c.rawdelete(\"y\")    // EXPECTED 2\n\n\nWARNING: w292 (modified-container) The container was modified within the loop.\ntestData/static_analyzer/w292.nut:15:4\n\n    delete c.x          // EXPECTED 1\n    c.rawdelete(\"y\")    // EXPECTED 2\n    ^---------------\n}\n\n\nWARNING: w292 (modified-container) The container was modified within the loop.\ntestData/static_analyzer/w292.nut:35:8\n\n    if (a < 0) {\n        c.clear()     // EXPECTED 3\n        ^--------\n    } else {\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w292.nut",
    "content": "#allow-delete-operator\n//-file:declared-never-used\n//-file:unconditional-terminated-loop\n\nlet c = {}\n\nforeach (a in c) {\n    delete c.x          // FP 1\n    c.rawdelete(\"y\")    // FP 2\n    break;\n}\n\nforeach (a in c) {\n    delete c.x          // EXPECTED 1\n    c.rawdelete(\"y\")    // EXPECTED 2\n}\n\nfunction _f(arr) {\n    foreach (a in arr) {\n        c.remove(5)     // FP 3\n        return 10;\n    }\n    return 20\n}\n\nforeach (a in c) {\n    if (a > 0) {\n        c.remove(5)     // FP 4\n    }\n    return 10;\n}\n\nforeach (a in c) {\n    if (a < 0) {\n        c.clear()     // EXPECTED 3\n    } else {\n        throw \"EX\"\n    }\n}\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w293.diag.txt",
    "content": "WARNING: w293 (duplicate-persist-id) Duplicate id 'x' passed to 'persist'.\ntestData/static_analyzer/w293.nut:5:17\n\nlet _y = persist(\"y\", @() {}) // FP\nlet _z = persist(\"x\", @() {}) // EXPECTED\n                 ^--\n\n\nWARNING: w293 (duplicate-persist-id) Duplicate id 'a' passed to 'persist'.\ntestData/static_analyzer/w293.nut:14:28\n\nlet _c = mkWatched(foo, \"b\") // FP\nlet _d = mkWatched(persist, \"a\") // EXPECTED\n                            ^--\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w293.nut",
    "content": "\n\nlet _x = persist(\"x\", @() {}) // FP\nlet _y = persist(\"y\", @() {}) // FP\nlet _z = persist(\"x\", @() {}) // EXPECTED\n\nfunction mkWatched(_f, _k) { }\n\nfunction foo(p) { return p }\n\nlet _a = mkWatched(persist, \"a\") // FP\nlet _b = mkWatched(persist, \"b\") // FP\nlet _c = mkWatched(foo, \"b\") // FP\nlet _d = mkWatched(persist, \"a\") // EXPECTED"
  },
  {
    "path": "testData/static_analyzer/w295.diag.txt",
    "content": "WARNING: w307 (global-id-redef) Redefinition of existing global name 'g'.\ntestData/static_analyzer/w295.nut:7:0\n\n\nWARNING: w307 (global-id-redef) Redefinition of existing global name 'g'.\ntestData/static_analyzer/w295.nut:8:0\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w295.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\n//-file:undefined-global\n\n::f <- {}\n::g <- 1\n::g <- 2\n\nprint(::h)\n"
  },
  {
    "path": "testData/static_analyzer/w297.diag.txt",
    "content": "WARNING: w297 (call-from-root) Function 'keepref' must be called from the root scope.\ntestData/static_analyzer/w297.nut:9:4\n\nfunction _foo(p) {\n    keepref(p) // EXPECTED 1\n    ^---------\n}\n\n\nWARNING: w297 (call-from-root) Function 'keepref' must be called from the root scope.\ntestData/static_analyzer/w297.nut:13:14\n\nlet _z = @(y) keepref(y) // EXPECTED 2\n              ^---------\n\n\nWARNING: w297 (call-from-root) Function 'keepref' must be called from the root scope.\ntestData/static_analyzer/w297.nut:17:8\n\n    constructor(t){\n        keepref(t) // EXPECTED 3\n        ^---------\n    }\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w297.nut",
    "content": "\n\nlet x = {}\n\nkeepref(x) // FP\n\n\nfunction _foo(p) {\n    keepref(p) // EXPECTED 1\n}\n\n\nlet _z = @(y) keepref(y) // EXPECTED 2\n\nclass _C {\n    constructor(t){\n        keepref(t) // EXPECTED 3\n    }\n}"
  },
  {
    "path": "testData/static_analyzer/w305.diag.txt",
    "content": "WARNING: w305 (relative-bool-cmp) Relative comparison of non-boolean with boolean. It is a potential runtime error.\ntestData/static_analyzer/w305.nut:16:4\n\nif ((B == x) > y)\n    ^-----------\n  print(\"a\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w305.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nconst B = true\nlocal x = 1\nlocal y = 1\n\nlet b1 = true\nlet b2 = false\n\nprint(b1 > b2)\n\nif (B == x > y) //-compared-with-bool\n  print(\"a\")\n\nif ((B == x) > y)\n  print(\"a\")\n"
  },
  {
    "path": "testData/static_analyzer/w306.diag.txt",
    "content": "WARNING: w306 (eq-paren-miss) Suspicious expression, probably parens are missing.\ntestData/static_analyzer/w306.nut:6:4\n\nlocal z = 2\nif (x == y != z)\n    ^----------\n  print(\"a\")\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w306.nut",
    "content": "//expect:w223\n\nlocal x = 1\nlocal y = 1\nlocal z = 2\nif (x == y != z)\n  print(\"a\")\n\nif ((x == y) != z)\n  print(\"b\")\n\nif (x == (y != z))\n  print(\"c\")"
  },
  {
    "path": "testData/static_analyzer/w308.diag.txt",
    "content": "WARNING: w308 (bool-lambda-required) Function 'findindex' requires lambda which returns boolean.\ntestData/static_analyzer/w308.nut:7:28\n\nlet _expected = o.findindex(@(t) t.id = 10) // EXPECTED\n                            ^-------------\nlet _falsep = o.findvalue(@(t) t.id == 10)  // FP 1\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'findindex' must return a value.\ntestData/static_analyzer/w308.nut:7:28\n\nlet _expected = o.findindex(@(t) t.id = 10) // EXPECTED\n                            ^-------------\nlet _falsep = o.findvalue(@(t) t.id == 10)  // FP 1\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w308.nut",
    "content": "//-file:named-like-should-return\n\nlet o = {}\n\nfunction startswith(_a, _b) { return false }\n\nlet _expected = o.findindex(@(t) t.id = 10) // EXPECTED\nlet _falsep = o.findvalue(@(t) t.id == 10)  // FP 1\n\n\nlet _sr = o.findvalue(@(s) s.s == 10 && (s?.e ?? 0) > 0 ) // FP 2\n\no.findvalue(@(p) o?[p] ?? (p == \"000\")) // FP 3\n\n\nlet _set = o.filter(@(a) a && startswith(a, \"9\")) // FP 4\n"
  },
  {
    "path": "testData/static_analyzer/w309_require.diag.txt",
    "content": "WARNING: w309 (missing-destructured-value) No value for 'bar' in destructured declaration.\ntestData/static_analyzer/w309_require.nut:4:10\n\nlet { foo bar } = require(\"testData/static_analyzer/module_foo.nut\")\n          ^--\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w309_require.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlet { foo bar } = require(\"testData/static_analyzer/module_foo.nut\")\n\nreturn { foo bar }\n"
  },
  {
    "path": "testData/static_analyzer/w310_require.diag.txt",
    "content": "WARNING: w310 (destructured-type) Destructured type mismatch, right side is table.\ntestData/static_analyzer/w310_require.nut:4:0\n\nlet [ foo bar ] = require(\"testData/static_analyzer/module_foo.nut\")\n^-------------------------------------------------------------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w310_require.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlet [ foo bar ] = require(\"testData/static_analyzer/module_foo.nut\")\n\nreturn { foo, bar }\n"
  },
  {
    "path": "testData/static_analyzer/w312_require.diag.txt",
    "content": "WARNING: w312 (missing-field) No field 'baz' in table.\ntestData/static_analyzer/w312_require.nut:4:10\n\nlet baz = require(\"testData/static_analyzer/module_foo.nut\").baz\n          ^-----------------------------------------------------\nreturn baz(1)\n\n\nHINT: h314 (see-other) You can find source of table here.\ntestData/static_analyzer/w312_require.nut:4:10\n\nlet baz = require(\"testData/static_analyzer/module_foo.nut\").baz\n          ^-------------------------------------------------\nreturn baz(1)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w312_require.nut",
    "content": "if (__name__ == \"__analysis__\")\n  return\n\nlet baz = require(\"testData/static_analyzer/module_foo.nut\").baz\nreturn baz(1)\n"
  },
  {
    "path": "testData/static_analyzer/w318_merge_empty_table.diag.txt",
    "content": "WARNING: w318 (merge-empty-table) '__merge({})' with an empty table is equivalent to 'clone'. Use 'clone' instead.\ntestData/static_analyzer/w318_merge_empty_table.nut:5:8\n\nlet a = t.__merge({}) //warning:merge-empty-table\n        ^------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w318_merge_empty_table.nut",
    "content": "//-file:declared-never-used\n\nlet t = {a = 1, b = 2}\n\nlet a = t.__merge({}) //warning:merge-empty-table\n\nlet b = t.__merge({x = 1}) // ok, non-empty table\n\nlet c = clone t // ok, already using clone\n"
  },
  {
    "path": "testData/static_analyzer/w319_empty_array_resize.diag.txt",
    "content": "WARNING: w319 (empty-array-resize) '[].resize(...)' is slower than 'array(...)'. Use 'array(...)' instead.\ntestData/static_analyzer/w319_empty_array_resize.nut:3:8\n\nlet a = [].resize(10, 0) //warning:empty-array-resize\n        ^---------------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w319_empty_array_resize.nut",
    "content": "//-file:declared-never-used\n\nlet a = [].resize(10, 0) //warning:empty-array-resize\n\nlet b = array(10, 0) // ok, already using array()\n\nlet c = [1, 2, 3].resize(10, 0) // ok, non-empty array\n"
  },
  {
    "path": "testData/static_analyzer/w320.diag.txt",
    "content": "WARNING: w320 (callback-should-return-value) Callback passed to 'filter' must return a value.\ntestData/static_analyzer/w320.nut:17:23\n\n  // filter without return\n  let _f1 = arr.filter(function(v) { print(v) })\n                       ^-----------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'reduce' must return a value.\ntestData/static_analyzer/w320.nut:20:23\n\n  // reduce without return\n  let _r1 = arr.reduce(function(acc, v) { print(acc + v) })\n                       ^----------------------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'findindex' must return a value.\ntestData/static_analyzer/w320.nut:23:27\n\n  // findindex without return\n  let _fi1 = arr.findindex(function(v) { print(v) })\n                           ^-----------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'findvalue' must return a value.\ntestData/static_analyzer/w320.nut:26:27\n\n  // findvalue without return\n  let _fv1 = arr.findvalue(function(v) { print(v) })\n                           ^-----------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'sort' must return a value.\ntestData/static_analyzer/w320.nut:29:11\n\n  // sort without return\n  arr.sort(function(a, b) { print(a + b) })\n           ^------------------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'apply' must return a value.\ntestData/static_analyzer/w320.nut:32:12\n\n  // apply without return\n  arr.apply(function(v) { print(v) })\n            ^-----------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'map' must return a value.\ntestData/static_analyzer/w320.nut:35:21\n\n  // table map without return\n  let _tm1 = tbl.map(function(v) { print(v) })\n                     ^-----------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'filter' must return a value.\ntestData/static_analyzer/w320.nut:38:24\n\n  // table filter without return\n  let _tf1 = tbl.filter(function(v) { print(v) })\n                        ^-----------------------\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'map' must return a value.\ntestData/static_analyzer/w320.nut:41:20\n\n  // partial return (not all paths)\n  let _m2 = arr.map(function(v) {\n                    ^\n    if (v > 0)\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'map' must return a value.\ntestData/static_analyzer/w320.nut:47:19\n\n  // function passed as binding\n  let noReturnFn = function(v) { print(v) }\n                   ^-----------------------\n  let _m5 = arr.map(noReturnFn)\n\n\nWARNING: w320 (callback-should-return-value) Callback passed to 'filter' must return a value.\ntestData/static_analyzer/w320.nut:51:18\n\n  // binding with partial return\n  let partialFn = function(v) {\n                  ^\n    if (v > 0)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w320.nut",
    "content": "//-file:declared-never-used\n//-file:named-like-should-return\n//-file:all-paths-return-value\n//-file:result-not-utilized\n//-file:bool-lambda-required\n\nfunction test_warnings() {\n  let arr = [1, 2, 3]\n  let tbl = {a = 1, b = 2}\n\n  // ===== SHOULD WARN =====\n\n  // map without return\n  let _m1 = arr.map(@(v) print(v))\n\n  // filter without return\n  let _f1 = arr.filter(function(v) { print(v) })\n\n  // reduce without return\n  let _r1 = arr.reduce(function(acc, v) { print(acc + v) })\n\n  // findindex without return\n  let _fi1 = arr.findindex(function(v) { print(v) })\n\n  // findvalue without return\n  let _fv1 = arr.findvalue(function(v) { print(v) })\n\n  // sort without return\n  arr.sort(function(a, b) { print(a + b) })\n\n  // apply without return\n  arr.apply(function(v) { print(v) })\n\n  // table map without return\n  let _tm1 = tbl.map(function(v) { print(v) })\n\n  // table filter without return\n  let _tf1 = tbl.filter(function(v) { print(v) })\n\n  // partial return (not all paths)\n  let _m2 = arr.map(function(v) {\n    if (v > 0)\n      return v * 2\n  })\n\n  // function passed as binding\n  let noReturnFn = function(v) { print(v) }\n  let _m5 = arr.map(noReturnFn)\n\n  // binding with partial return\n  let partialFn = function(v) {\n    if (v > 0)\n      return v * 2\n  }\n  let _f5 = arr.filter(partialFn)\n\n\n  // ===== SHOULD NOT WARN =====\n\n  // map with return\n  let _m3 = arr.map(@(v) v * 2)\n\n  // filter with return\n  let _f3 = arr.filter(@(v) v > 1)\n\n  // reduce with return\n  let _r3 = arr.reduce(@(acc, v) acc + v)\n\n  // findindex with return\n  let _fi3 = arr.findindex(@(v) v == 2)\n\n  // findvalue with return\n  let _fv3 = arr.findvalue(@(v) v == 2)\n\n  // sort with return\n  arr.sort(@(a, b) a <=> b)\n\n  // apply with return\n  arr.apply(@(v) v * 2)\n\n  // block body with return on all paths\n  let _m4 = arr.map(function(v) {\n    if (v > 0)\n      return v * 2\n    else\n      return v\n  })\n\n  // each (not in the list, should not warn)\n  arr.each(@(v) print(v))\n\n  // binding with proper return\n  let goodFn = @(v) v * 2\n  let _m6 = arr.map(goodFn)\n}\n"
  },
  {
    "path": "testData/static_analyzer/w321.diag.txt",
    "content": "WARNING: w321 (param-assign-in-lambda) Assignment to parameter 'a' in lambda has no effect. Return the expression instead.\ntestData/static_analyzer/w321.nut:17:29\n\n// reduce with assignment to accumulator\nlet _r1 = arr.reduce(@(a, v) a = max(v, a), 0)\n                             ^------------\n\n\nWARNING: w321 (param-assign-in-lambda) Assignment to parameter 'v' in lambda has no effect. Return the expression instead.\ntestData/static_analyzer/w321.nut:20:23\n\n// map with assignment to parameter\nlet _m1 = arr.map(@(v) v = v * 2)\n                       ^--------\n\n\nWARNING: w321 (param-assign-in-lambda) Assignment to parameter 'v' in lambda has no effect. Return the expression instead.\ntestData/static_analyzer/w321.nut:23:26\n\n// filter with assignment\nlet _f1 = arr.filter(@(v) v = v > 1)\n                          ^--------\n\n\nWARNING: w321 (param-assign-in-lambda) Assignment to parameter 'a' in lambda has no effect. Return the expression instead.\ntestData/static_analyzer/w321.nut:26:33\n\n// table reduce with assignment\nlet _r3 = tbl.reduce(@(a, v, _k) a = a + v, 0)\n                                 ^--------\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w321.nut",
    "content": "//-file:declared-never-used\n//-file:named-like-should-return\n//-file:all-paths-return-value\n//-file:result-not-utilized\n//-file:bool-lambda-required\n//-file:callback-should-return-value\n//-file:param-pos\n\nlet arr = [1, 2, 3]\nlet tbl = {a = 1, b = 2}\n\nfunction max(a, b) { return a > b ? a : b }\n\n// ===== SHOULD WARN =====\n\n// reduce with assignment to accumulator\nlet _r1 = arr.reduce(@(a, v) a = max(v, a), 0)\n\n// map with assignment to parameter\nlet _m1 = arr.map(@(v) v = v * 2)\n\n// filter with assignment\nlet _f1 = arr.filter(@(v) v = v > 1)\n\n// table reduce with assignment\nlet _r3 = tbl.reduce(@(a, v, _k) a = a + v, 0)\n\n\n// ===== SHOULD NOT WARN =====\n\n// block-body function: assignment to param then use is ok\nlet _r2 = arr.reduce(function(a, v) { a = a + v; return a }, 0)\n\n// proper reduce (returns expression)\nlet _r4 = arr.reduce(@(a, v) max(v, a), 0)\n\n// proper map\nlet _m4 = arr.map(@(v) v * 2)\n\n// assignment to local, not parameter\nlet _m5 = arr.map(function(v) {\n  local res = v * 2\n  return res\n})\n\n// assignment to parameter in regular named function (not lambda)\nfunction process(x) {\n  x = x * 2\n  return x\n}\n\n// assignment to outer variable, not parameter\nlocal accumulator = 0\narr.each(function(v) {\n  accumulator = accumulator + v\n})\n"
  },
  {
    "path": "testData/static_analyzer/w322.diag.txt",
    "content": "WARNING: w322 (callback-should-not-return) Callback passed to 'each' should not return a value.\ntestData/static_analyzer/w322.nut:10:9\n\n// each with explicit return value\narr.each(@(v) v * 2)\n         ^---------\n\n\nWARNING: w322 (callback-should-not-return) Callback passed to 'each' should not return a value.\ntestData/static_analyzer/w322.nut:13:9\n\n// each with block body returning value\narr.each(function(v) { return v * 2 })\n         ^---------------------------\n\n\nWARNING: w322 (callback-should-not-return) Callback passed to 'each' should not return a value.\ntestData/static_analyzer/w322.nut:16:9\n\n// table each with return\ntbl.each(@(v) v + 1)\n         ^---------\n\n\nWARNING: w322 (callback-should-not-return) Callback passed to 'each' should not return a value.\ntestData/static_analyzer/w322.nut:19:18\n\n// each with binding that returns\nlet returningFn = function(v) { return v * 2 }\n                  ^---------------------------\narr.each(returningFn)\n\n\n"
  },
  {
    "path": "testData/static_analyzer/w322.nut",
    "content": "//-file:declared-never-used\n//-file:result-not-utilized\n\nlet arr = [1, 2, 3]\nlet tbl = {a = 1, b = 2}\n\n// ===== SHOULD WARN =====\n\n// each with explicit return value\narr.each(@(v) v * 2)\n\n// each with block body returning value\narr.each(function(v) { return v * 2 })\n\n// table each with return\ntbl.each(@(v) v + 1)\n\n// each with binding that returns\nlet returningFn = function(v) { return v * 2 }\narr.each(returningFn)\n\n\n// ===== SHOULD NOT WARN =====\n\n// each with side-effect only (no return value)\narr.each(function(v) { print(v) })\n\n// each with lambda calling void function\narr.each(@(v) print(v))\n\n// lambda with single call expression (side-effect intent)\nlocal tmp = []\narr.each(@(v) tmp.append(v))\n\n// mutate with side-effect only\n//Watched.mutate(function(v) { v.append(1) })\n\n// each with block body, no return\ntbl.each(function(_k, _v) { print(\"ok\") })\n"
  },
  {
    "path": "testData/types/default_values.nut.txt",
    "content": "fn(a = 111)\nfn(a: bool = true)\nfn(x, a = 111)\nfn(x, a: bool = true)\nfn(x: bool, a = 111)\nfn(x: bool, a: bool = true)\nfn(x: bool, a = 111)\nfn(tab: table = {})\nfn(tab: table = {x = 5, y = 6})\nfn(arr: array = [])\nfn(arr: array = [234, null, value])\nfn(expr: int = (0))\nfn(expr: int = (20 + 50 * 10))\nfn(c: int = Color32(123, 45, 45, 23))\nfn(c: string = \"{\")\nfn(c: int = '{')\nfn(c: string = \"]\")\nfn(c: string = \"\\\"\")\nfn(c: int = '\\'')\nfn(c: int = '\"')\nfn(c: string = \"\")\nfn(c1: int = Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66))\nfn([a = 111])\nfn([a: bool = true])\nfn([x, a = 111])\nfn([x, a: bool = true])\nfn([x: bool, a = 111])\nfn([x: bool, a: bool = true])\nfn([x: bool, a = 111])\nfn([tab: table = {}])\nfn([tab: table = {x = 5, y = 6}])\nfn([arr: array = []])\nfn([arr: array = [234, null, value]])\nfn([expr: int = (0)])\nfn([expr: int = (20 + 50 * 10)])\nfn([c: int = Color32(123, 45, 45, 23)])\nfn([c1: int = Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66)])\nfn([c: string = \"{\"])\nfn([c: int = '{'])"
  },
  {
    "path": "testData/types/default_values.out",
    "content": "fn(a = 111)\nfn([a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(a: bool = true)\nfn([a: bool = true])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(x, a = 111)\nfn(x, [a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn(x, a: bool = true)\nfn(x, [a: bool = true])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn(x: bool, a = 111)\nfn(x: bool, [a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn(x: bool, a: bool = true)\nfn(x: bool, [a: bool = true])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn(x: bool, a = 111)\nfn(x: bool, [a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn(tab: table = {})\nfn([tab: table = {}])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(tab: table = {x = 5, y = 6})\nfn([tab: table = {x = 5, y = 6}])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(arr: array = [])\nfn([arr: array = []])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(arr: array = [234, null, value])\nfn([arr: array = [234, null, value]])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(expr: int = (0))\nfn([expr: int = (0)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(expr: int = (20 + 50 * 10))\nfn([expr: int = (20 + 50 * 10)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: int = Color32(123, 45, 45, 23))\nfn([c: int = Color32(123, 45, 45, 23)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: string = \"{\")\nfn([c: string = \"{\"])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: int = '{')\nfn([c: int = '{'])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: string = \"]\")\nfn([c: string = \"]\"])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: string = \"\\\"\")\nfn([c: string = \"\\\"\"])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: int = '\\'')\nfn([c: int = '\\''])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: int = '\"')\nfn([c: int = '\"'])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c: string = \"\")\nfn([c: string = \"\"])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn(c1: int = Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66))\nfn([c1: int = Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([a = 111])\nfn([a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([a: bool = true])\nfn([a: bool = true])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([x, a = 111])\nfn([x, a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([x, a: bool = true])\nfn([x, a: bool = true])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([x: bool, a = 111])\nfn([x: bool, a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([x: bool, a: bool = true])\nfn([x: bool, a: bool = true])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([x: bool, a = 111])\nfn([x: bool, a = 111])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([tab: table = {}])\nfn([tab: table = {}])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([tab: table = {x = 5, y = 6}])\nfn([tab: table = {x = 5, y = 6}])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([arr: array = []])\nfn([arr: array = []])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([arr: array = [234, null, value]])\nfn([arr: array = [234, null, value]])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([expr: int = (0)])\nfn([expr: int = (0)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([expr: int = (20 + 50 * 10)])\nfn([expr: int = (20 + 50 * 10)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([c: int = Color32(123, 45, 45, 23)])\nfn([c: int = Color32(123, 45, 45, 23)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([c1: int = Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66)])\nfn([c1: int = Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66)])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfn([c: string = \"{\"])\nfn([c: string = \"{\"])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfn([c: int = '{'])\nfn([c: int = '{'])\n  functionName: fn\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 1\n  pure: false\n  nodiscard: false\n\n"
  },
  {
    "path": "testData/types/default_values_invalid.nut.txt",
    "content": "fn(a =, 111)\nfn(a: bool = [true)\nfn(x, a = 111})\nfn(x, a: bool = \")\nfn(x: bool, a =( 111)\nfn(x: bool, a: bool, = true)\nfn(x: bool, a = 1}11)\nfn(tab: table = {[})\nfn(tab: table = {x = 5), y = 6})\nfn(arr: array [= [])\nfn(arr: array = [234, null, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{value])\nfn(expr: int = ((((0))))\nfn(expr: int = ,(20 + 50 * 10))\nfn(c: int = Color32(123, 45, 45, 23\\\"),)\nfn(c: int = '{\\')\nfn(c: int = '\")\nfn(c: int = \"\\')\nfn(c1: int := Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66))\nfn([a = 1,11])\nfn([a: bool = [true])\nfn([x, a = 111}])\nfn([x, a: bool = true][)\nfn([x: bool, a = 111][])\nfn([x: bool, a: bool = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[true])\nfn([x: bool, a = [111])\nfn([tab: table = {]}])\nfn([tab: table := {x = 5, y = 6}])\nfn([arr: array = [{]])\nfn([arr: array = [234, null, value]] = null)\nfn([expr: int = ](0)])\nfn([expr: int = (20 + 50 * 10)}])\nfn([c: int = Color32({123, 45, 45, 23)])\nfn([c1: int = Color32(123, 45, 45, 23), c2: int = Color32,(33, 44, 55, 66)])"
  },
  {
    "path": "testData/types/default_values_invalid.out",
    "content": "fn(a =, 111)\nERROR: Expected default value after '='\nat testData/types/default_values_invalid.nut.txt:1:7\n\nfn(a: bool = [true)\nERROR: Unmatched ')' in default value\nat testData/types/default_values_invalid.nut.txt:2:19\n\nfn(x, a = 111})\nERROR: Unmatched '}' in default value\nat testData/types/default_values_invalid.nut.txt:3:14\n\nfn(x, a: bool = \")\nERROR: Unterminated function type string\nat testData/types/default_values_invalid.nut.txt:4:19\n\nfn(x: bool, a =( 111)\nERROR: Unterminated function type string\nat testData/types/default_values_invalid.nut.txt:5:22\n\nfn(x: bool, a: bool, = true)\nERROR: Expected argument name\nat testData/types/default_values_invalid.nut.txt:6:22\n\nfn(x: bool, a = 1}11)\nERROR: Unmatched '}' in default value\nat testData/types/default_values_invalid.nut.txt:7:18\n\nfn(tab: table = {[})\nERROR: Unmatched '}' in default value\nat testData/types/default_values_invalid.nut.txt:8:19\n\nfn(tab: table = {x = 5), y = 6})\nERROR: Unmatched ')' in default value\nat testData/types/default_values_invalid.nut.txt:9:23\n\nfn(arr: array [= [])\nERROR: Expected argument name\nat testData/types/default_values_invalid.nut.txt:10:16\n\nfn(arr: array = [234, null, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{value])\nERROR: Default value too complex. Too many nested structures\nat testData/types/default_values_invalid.nut.txt:11:67\n\nfn(expr: int = ((((0))))\nERROR: Unterminated function type string\nat testData/types/default_values_invalid.nut.txt:12:25\n\nfn(expr: int = ,(20 + 50 * 10))\nERROR: Expected default value after '='\nat testData/types/default_values_invalid.nut.txt:13:16\n\nfn(c: int = Color32(123, 45, 45, 23\\\"),)\nERROR: Unfinished default value, unmatched brackets\nat testData/types/default_values_invalid.nut.txt:14:41\n\nfn(c: int = '{\\')\nERROR: Unterminated function type string\nat testData/types/default_values_invalid.nut.txt:15:18\n\nfn(c: int = '\")\nERROR: Unterminated function type string\nat testData/types/default_values_invalid.nut.txt:16:16\n\nfn(c: int = \"\\')\nERROR: Unterminated function type string\nat testData/types/default_values_invalid.nut.txt:17:17\n\nfn(c1: int := Color32(123, 45, 45, 23), c2: int = Color32(33, 44, 55, 66))\nERROR: Expected ',' or ')'\nat testData/types/default_values_invalid.nut.txt:18:12\n\nfn([a = 1,11])\nERROR: Expected argument name\nat testData/types/default_values_invalid.nut.txt:19:11\n\nfn([a: bool = [true])\nERROR: Unmatched '['\nat testData/types/default_values_invalid.nut.txt:20:21\n\nfn([x, a = 111}])\nERROR: Unmatched '}' in default value\nat testData/types/default_values_invalid.nut.txt:21:15\n\nfn([x, a: bool = true][)\nERROR: Optional block must be the last argument\nat testData/types/default_values_invalid.nut.txt:22:23\n\nfn([x: bool, a = 111][])\nERROR: Optional block must be the last argument\nat testData/types/default_values_invalid.nut.txt:23:22\n\nfn([x: bool, a: bool = [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[true])\nERROR: Default value too complex. Too many nested structures\nat testData/types/default_values_invalid.nut.txt:24:63\n\nfn([x: bool, a = [111])\nERROR: Unmatched '['\nat testData/types/default_values_invalid.nut.txt:25:23\n\nfn([tab: table = {]}])\nERROR: Unmatched ']' in default value\nat testData/types/default_values_invalid.nut.txt:26:19\n\nfn([tab: table := {x = 5, y = 6}])\nERROR: Expected ',' or ')'\nat testData/types/default_values_invalid.nut.txt:27:16\n\nfn([arr: array = [{]])\nERROR: Unmatched ']' in default value\nat testData/types/default_values_invalid.nut.txt:28:20\n\nfn([arr: array = [234, null, value]] = null)\nERROR: Argument after optional block\nat testData/types/default_values_invalid.nut.txt:29:38\n\nfn([expr: int = ](0)])\nERROR: Expected default value after '='\nat testData/types/default_values_invalid.nut.txt:30:17\n\nfn([expr: int = (20 + 50 * 10)}])\nERROR: Unmatched '}' in default value\nat testData/types/default_values_invalid.nut.txt:31:31\n\nfn([c: int = Color32({123, 45, 45, 23)])\nERROR: Unmatched ')' in default value\nat testData/types/default_values_invalid.nut.txt:32:38\n\nfn([c1: int = Color32(123, 45, 45, 23), c2: int = Color32,(33, 44, 55, 66)])\nERROR: Expected argument name\nat testData/types/default_values_invalid.nut.txt:33:59\n\n"
  },
  {
    "path": "testData/types/invalid.nut.txt",
    "content": "x\n1\n(\n)\n[\n]\n...\nint\n-\n,\n.\n|\n(|\n(int\nfunction_name(())\nfunction_name([)\nfunction_name(])\nfunction_name(.)\nfunction_name(,,,,,,,,x)\nfunction_name(x x x)\n1function_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nfunction_name)(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nfunction_name.(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nfunction_name(1arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: 1number, [arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: number, )[arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: number, [[arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: number, ][arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: number, [arg2_name float, arg3_name: float], ...)\nfunction_name(arg1_name: number, [arg2_name: float arg3_name: float], ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float, ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float] ....)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...])\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float],] ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], [...])\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...(\npure_ function_name()\nnodiscard_ function_name()\npure nodiscard_ function_name()\n"
  },
  {
    "path": "testData/types/invalid.out",
    "content": "x\nERROR: Expected '(' after function name\nat testData/types/invalid.nut.txt:1:2\n\n1\nERROR: Expected function name\nat testData/types/invalid.nut.txt:2:1\n\n(\nERROR: Expected type name\nat testData/types/invalid.nut.txt:3:2\n\n)\nERROR: Expected function name\nat testData/types/invalid.nut.txt:4:1\n\n[\nERROR: Expected function name\nat testData/types/invalid.nut.txt:5:1\n\n]\nERROR: Expected function name\nat testData/types/invalid.nut.txt:6:1\n\n...\nERROR: Expected function name\nat testData/types/invalid.nut.txt:7:1\n\nint\nERROR: Expected '(' after function name\nat testData/types/invalid.nut.txt:8:4\n\n-\nERROR: Expected function name\nat testData/types/invalid.nut.txt:9:1\n\n,\nERROR: Expected function name\nat testData/types/invalid.nut.txt:10:1\n\n.\nERROR: Expected function name\nat testData/types/invalid.nut.txt:11:1\n\n|\nERROR: Expected function name\nat testData/types/invalid.nut.txt:12:1\n\n(|\nERROR: Expected type name\nat testData/types/invalid.nut.txt:13:2\n\n(int\nERROR: Expected ')' after type list\nat testData/types/invalid.nut.txt:14:5\n\nfunction_name(())\nERROR: Expected argument name\nat testData/types/invalid.nut.txt:15:15\n\nfunction_name([)\nERROR: Unmatched '['\nat testData/types/invalid.nut.txt:16:16\n\nfunction_name(])\nERROR: Unmatched ']'\nat testData/types/invalid.nut.txt:17:15\n\nfunction_name(.)\nERROR: Expected argument name\nat testData/types/invalid.nut.txt:18:15\n\nfunction_name(,,,,,,,,x)\nERROR: Argument expected before ','\nat testData/types/invalid.nut.txt:19:15\n\nfunction_name(x x x)\nERROR: Expected ':' after argument name\nat testData/types/invalid.nut.txt:20:17\n\n1function_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nERROR: Expected function name\nat testData/types/invalid.nut.txt:21:1\n\nfunction_name)(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nERROR: Expected '(' after function name\nat testData/types/invalid.nut.txt:22:14\n\nfunction_name.(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nERROR: Expected function name after '.'\nat testData/types/invalid.nut.txt:23:15\n\nfunction_name(1arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nERROR: Expected argument name\nat testData/types/invalid.nut.txt:24:15\n\nfunction_name(arg1_name: 1number, [arg2_name: float, arg3_name: float], ...)\nERROR: Expected type name\nat testData/types/invalid.nut.txt:25:26\n\nfunction_name(arg1_name: number, )[arg2_name: float, arg3_name: float], ...)\nERROR: Unexpected characters after function type string\nat testData/types/invalid.nut.txt:26:35\n\nfunction_name(arg1_name: number, [[arg2_name: float, arg3_name: float], ...)\nERROR: Nested optional blocks are not allowed\nat testData/types/invalid.nut.txt:27:35\n\nfunction_name(arg1_name: number, ][arg2_name: float, arg3_name: float], ...)\nERROR: Unmatched ']'\nat testData/types/invalid.nut.txt:28:34\n\nfunction_name(arg1_name: number, [arg2_name float, arg3_name: float], ...)\nERROR: Expected ':' after argument name\nat testData/types/invalid.nut.txt:29:45\n\nfunction_name(arg1_name: number, [arg2_name: float arg3_name: float], ...)\nERROR: Expected ',' or ')'\nat testData/types/invalid.nut.txt:30:52\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float, ...)\nERROR: Unmatched '['\nat testData/types/invalid.nut.txt:31:74\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float] ....)\nERROR: Expected ')' after ellipsis argument\nat testData/types/invalid.nut.txt:32:74\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...])\nERROR: Unmatched ']'\nat testData/types/invalid.nut.txt:33:75\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float],] ...)\nERROR: Unmatched ']'\nat testData/types/invalid.nut.txt:34:71\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], [...])\nERROR: Optional block must be the last argument\nat testData/types/invalid.nut.txt:35:72\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...\nERROR: Expected ')' after ellipsis argument\nat testData/types/invalid.nut.txt:36:75\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...(\nERROR: Expected ')' after ellipsis argument\nat testData/types/invalid.nut.txt:37:75\n\npure_ function_name()\nERROR: Expected '(' after function name\nat testData/types/invalid.nut.txt:38:7\n\nnodiscard_ function_name()\nERROR: Expected '(' after function name\nat testData/types/invalid.nut.txt:39:12\n\npure nodiscard_ function_name()\n\nERROR: Expected '(' after function name\nat testData/types/invalid.nut.txt:40:17\n\n"
  },
  {
    "path": "testData/types/type_suggestions.nut.txt",
    "content": "fn(x: Float)\nfn(x: float|None)\nclosure.fn()\nstring.fn():integer"
  },
  {
    "path": "testData/types/type_suggestions.out",
    "content": "fn(x: Float)\nERROR: Invalid type name 'Float', did you mean 'float'?\nat testData/types/type_suggestions.nut.txt:1:12\n\nfn(x: float|None)\nERROR: Invalid type name 'None', did you mean 'null'?\nat testData/types/type_suggestions.nut.txt:2:17\n\nclosure.fn()\nERROR: Invalid type name 'closure', did you mean 'function'?\nat testData/types/type_suggestions.nut.txt:3:7\n\nstring.fn():integer\nERROR: Invalid type name 'integer', did you mean 'int'?\nat testData/types/type_suggestions.nut.txt:4:20\n\n"
  },
  {
    "path": "testData/types/valid.nut.txt",
    "content": "function_name([arg2_name: float, arg3_name: float])\nfunction_name([arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: string, [arg2_name: int, arg3_name: table], ...: string): any\nFunctionName(arg1_Name: bool|null)\nfunction_name(arg1_name: int, arg2_name: string, arg3_name): float|null\nfunction_name(arg1_name: table, arg2_name: array, arg3_name: class): function|null\nfunction_name(arg1_name, [arg2_name, arg3_name])\nfunction_name([arg1_name: instance, arg2_name: class, arg3_name: int]): table\ninstance.function_name()\n(userpointer|instance).function_name()\n(table|class).function_name()\nfunction_name(...)\nfunction_name(arg1_name: int, ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nstring.function_name(int: float, [string: number, string: generator])\nfunction_name(arg1_name: bool, [arg2_name: string, arg3_name: float])\nfunction_name(arg1_name: int, [arg2_name: int, arg3_name: int])\nfunction_name()\nfunction_name(): int\nfunction_name(arg1_name)\nFunctionName(arg1_Name: int|null)\nFunctionName(arg1_Name: table|array)\nfunction_name([arg2_name: float, arg3_name: float])\nfunction_name([arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: string, [arg2_name: int, arg3_name: table, ...: string]) : any\nFunctionName(arg1_Name: ( null | bool ) )\nfunction_name(arg1_name: int, arg2_name: string, arg3_name: any): float | null\nfunction_name(arg1_name: table, arg2_name: array, arg3_name: class): (function | null)\nfunction_name(arg1_name: any, [arg2_name: any, arg3_name: any])\nfunction_name([arg1_name: instance, arg2_name: class, arg3_name: int]): table\ninstance.function_name()\n(instance|userpointer).function_name()\n ( table | class ) . function_name ( )\nfunction_name(...: any)\nfunction_name(...)\nfunction_name(arg1_name: int, ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nstring.function_name(int: float, [string: number, string: generator])\nfunction_name(arg1_name:bool,[arg2_name:string,arg3_name:float])\n   function_name ( arg1_name :int ,[ arg2_name: int,   arg3_name : int ] )\nfunction_name()\nfunction_name(): int\nfunction_name(arg1_name: any)\nFunctionName(arg1_Name: int|null)\nFunctionName(arg1_Name: (table|array))\npure function_name(x)\n  nodiscard   function_name(x)\npure nodiscard function_name(x)\n nodiscard   pure   function_name(x)\n"
  },
  {
    "path": "testData/types/valid.out",
    "content": "function_name([arg2_name: float, arg3_name: float])\nfunction_name([arg2_name: float, arg3_name: float])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfunction_name([arg2_name: float, arg3_name: float], ...)\nfunction_name([arg2_name: float, arg3_name: float], ...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: string, [arg2_name: int, arg3_name: table], ...: string): any\nfunction_name(arg1_name: string, [arg2_name: int, arg3_name: table], ...: string): any\n  functionName: function_name\n  returnTypeMask: 0xffffffff\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x10\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nFunctionName(arg1_Name: bool|null)\nFunctionName(arg1_Name: bool|null)\n  functionName: FunctionName\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: int, arg2_name: string, arg3_name): float|null\nfunction_name(arg1_name: int, arg2_name: string, arg3_name): float|null\n  functionName: function_name\n  returnTypeMask: 0x5\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 3\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: table, arg2_name: array, arg3_name: class): function|null\nfunction_name(arg1_name: table, arg2_name: array, arg3_name: class): function|null\n  functionName: function_name\n  returnTypeMask: 0x301\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 3\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name, [arg2_name, arg3_name])\nfunction_name(arg1_name, [arg2_name, arg3_name])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name([arg1_name: instance, arg2_name: class, arg3_name: int]): table\nfunction_name([arg1_name: instance, arg2_name: class, arg3_name: int]): table\n  functionName: function_name\n  returnTypeMask: 0x20\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 3\n  pure: false\n  nodiscard: false\n\ninstance.function_name()\ninstance.function_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x8000\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\n(userpointer|instance).function_name()\n(userpointer|instance).function_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x8800\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\n(table|class).function_name()\n(table|class).function_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x4020\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(...)\nfunction_name(...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: int, ...)\nfunction_name(arg1_name: int, ...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nstring.function_name(int: float, [string: number, string: generator])\nstring.function_name(int: float, [string: number, string: generator])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x10\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: bool, [arg2_name: string, arg3_name: float])\nfunction_name(arg1_name: bool, [arg2_name: string, arg3_name: float])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: int, [arg2_name: int, arg3_name: int])\nfunction_name(arg1_name: int, [arg2_name: int, arg3_name: int])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name()\nfunction_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(): int\nfunction_name(): int\n  functionName: function_name\n  returnTypeMask: 0x2\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name)\nfunction_name(arg1_name)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nFunctionName(arg1_Name: int|null)\nFunctionName(arg1_Name: int|null)\n  functionName: FunctionName\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nFunctionName(arg1_Name: table|array)\nFunctionName(arg1_Name: table|array)\n  functionName: FunctionName\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfunction_name([arg2_name: float, arg3_name: float])\nfunction_name([arg2_name: float, arg3_name: float])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfunction_name([arg2_name: float, arg3_name: float], ...)\nfunction_name([arg2_name: float, arg3_name: float], ...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 0\n  argCount: 2\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: string, [arg2_name: int, arg3_name: table, ...: string]) : any\nfunction_name(arg1_name: string, [arg2_name: int, arg3_name: table], ...: string): any\n  functionName: function_name\n  returnTypeMask: 0xffffffff\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x10\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nFunctionName(arg1_Name: ( null | bool ) )\nFunctionName(arg1_Name: bool|null)\n  functionName: FunctionName\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: int, arg2_name: string, arg3_name: any): float | null\nfunction_name(arg1_name: int, arg2_name: string, arg3_name): float|null\n  functionName: function_name\n  returnTypeMask: 0x5\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 3\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: table, arg2_name: array, arg3_name: class): (function | null)\nfunction_name(arg1_name: table, arg2_name: array, arg3_name: class): function|null\n  functionName: function_name\n  returnTypeMask: 0x301\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 3\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: any, [arg2_name: any, arg3_name: any])\nfunction_name(arg1_name, [arg2_name, arg3_name])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name([arg1_name: instance, arg2_name: class, arg3_name: int]): table\nfunction_name([arg1_name: instance, arg2_name: class, arg3_name: int]): table\n  functionName: function_name\n  returnTypeMask: 0x20\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 3\n  pure: false\n  nodiscard: false\n\ninstance.function_name()\ninstance.function_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x8000\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\n(instance|userpointer).function_name()\n(userpointer|instance).function_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x8800\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\n ( table | class ) . function_name ( )\n(table|class).function_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x4020\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(...: any)\nfunction_name(...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(...)\nfunction_name(...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: int, ...)\nfunction_name(arg1_name: int, ...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\nfunction_name(arg1_name: number, [arg2_name: float, arg3_name: float], ...)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0xffffffff\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nstring.function_name(int: float, [string: number, string: generator])\nstring.function_name(int: float, [string: number, string: generator])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0x10\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name:bool,[arg2_name:string,arg3_name:float])\nfunction_name(arg1_name: bool, [arg2_name: string, arg3_name: float])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\n   function_name ( arg1_name :int ,[ arg2_name: int,   arg3_name : int ] )\nfunction_name(arg1_name: int, [arg2_name: int, arg3_name: int])\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 3\n  pure: false\n  nodiscard: false\n\nfunction_name()\nfunction_name()\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(): int\nfunction_name(): int\n  functionName: function_name\n  returnTypeMask: 0x2\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 0\n  argCount: 0\n  pure: false\n  nodiscard: false\n\nfunction_name(arg1_name: any)\nfunction_name(arg1_name)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nFunctionName(arg1_Name: int|null)\nFunctionName(arg1_Name: int|null)\n  functionName: FunctionName\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\nFunctionName(arg1_Name: (table|array))\nFunctionName(arg1_Name: table|array)\n  functionName: FunctionName\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: false\n\npure function_name(x)\npure function_name(x)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: true\n  nodiscard: false\n\n  nodiscard   function_name(x)\nnodiscard function_name(x)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: false\n  nodiscard: true\n\npure nodiscard function_name(x)\npure nodiscard function_name(x)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: true\n  nodiscard: true\n\n nodiscard   pure   function_name(x)\n\npure nodiscard function_name(x)\n  functionName: function_name\n  returnTypeMask: 0x1\n  objectTypeMask: 0xffffffff\n  ellipsisArgTypeMask: 0x0\n  requiredArgs: 1\n  argCount: 1\n  pure: true\n  nodiscard: true\n\n"
  },
  {
    "path": "testRunner.py",
    "content": "#!/usr/bin/env python3\n\nimport tempfile\nfrom os import path\nimport sys\nimport os.path\nfrom pathlib import Path\nimport argparse\nimport subprocess\nfrom subprocess import Popen, PIPE\nimport platform\nimport threading\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\n\nCRED = '\\33[31m'\nCGREEN = '\\33[32m'\nRESET = \"\\033[0;0m\"\nCBOLD = '\\33[1m'\n\nnumOfTests=0\nnumOfFailedTests=0\nverbose=False\nciRun=False\n\nTHREADS = 12\nprintLock = threading.Lock()\n\n\ndef xprint(str, color = ''):\n    global ciRun\n    if (not ciRun):\n        print(color, end='')\n    print(str, end='')\n    if (not ciRun):\n        print(RESET)\n    else:\n        print('') # endline\n\n\ndef computePath(path, *paths):\n    return os.path.normpath(os.path.join(path, *paths))\n\n\ndef compareFilesLineByLine(marker, testFile, actualFile, expectedFile):\n    global numOfFailedTests\n    with open(expectedFile) as expected, open(actualFile) as actual:\n        expectedLines = expected.readlines()\n        actualLines = actual.readlines()\n        differs = len(expectedLines) != len(actualLines)\n        if differs == False:\n            i = 0\n            while i < len(expectedLines):\n                e = expectedLines[i].rstrip()\n                a = actualLines[i].rstrip()\n                i += 1\n                if e != a:\n                    differs = True\n                    break\n\n        if differs == True:\n            xprint(\"\")\n            xprint(f\"\\nFAIL: {testFile}\", CBOLD + CRED)\n            xprint(\"--Actual------------------\", CBOLD + CRED)\n            xprint(\"\".join(actualLines))\n            xprint(\"--Expected----------------\", CBOLD + CRED)\n            xprint(\"\".join(expectedLines))\n            xprint(\"--------------------------\", CBOLD + CRED)\n            xprint(\"\")\n            numOfFailedTests += 1\n            return False\n\n    return True\n\n\ndef updateExpectedFromActualIfNeed(marker, actualFile, expectedFile):\n    if (not path.exists(expectedFile)):\n        xprint(f\"  info: no {marker} expected file, create it\")\n        with open(actualFile) as f:\n            result = f.read()\n        with open(expectedFile, 'w') as f:\n            f.write(result)\n\n\ndef runTestGeneric(compiler, workingDir, dirname, name, kind, suffix, extraargs, stdoutFile):\n    global numOfFailedTests\n    global verbose\n    testFilePath = computePath(dirname, name + '.nut')\n\n    if (not path.exists(testFilePath)):\n        testFilePath = computePath(dirname, name + '.nut.txt')\n\n    testFilePath = testFilePath.replace('\\\\', '/')\n\n    expectedResultFilePath = computePath(dirname, name + suffix)\n    outputDir = computePath(workingDir, dirname)\n\n    os.makedirs(outputDir, exist_ok=True)\n\n    actualResultFilePath = computePath(workingDir, expectedResultFilePath)\n\n    if path.exists(actualResultFilePath):\n        os.remove(actualResultFilePath)\n\n    compilationCommand = [compiler, \"-optCH\"]\n    compilationCommand += extraargs\n\n    if stdoutFile:\n        outredirect = open(actualResultFilePath, 'w+')\n    else:\n        outredirect = subprocess.PIPE\n        compilationCommand += [actualResultFilePath]\n\n    compilationCommand += [testFilePath]\n\n    if verbose:\n        with printLock:\n            xprint(compilationCommand)\n\n    proc = Popen(compilationCommand, stdout=outredirect, stderr=outredirect)\n\n    outs = None\n    errs = None\n    try:\n        outs, errs = proc.communicate(timeout=10)\n    except subprocess.TimeoutExpired:\n        proc.kill()\n        outs, errs = proc.communicate()\n        if stdoutFile and outredirect:\n            outredirect.close()\n        with printLock:\n            xprint(\"\\nTIMEOUT: sq froze on test: {0}\\n\".format(testFilePath), CBOLD + CRED)\n            numOfFailedTests = numOfFailedTests + 1\n        return\n\n    if stdoutFile and outredirect:\n        outredirect.close()\n\n    with printLock:\n        if proc.returncode != 0:\n            xprint(\"\\nCRASH: {0}\".format(testFilePath), CBOLD + CRED)\n            numOfFailedTests = numOfFailedTests + 1\n            if outs != None:\n                xprint(\"--stdout------------------\", CBOLD + CRED)\n                xprint(outs.decode('utf-8'))\n            if errs != None:\n                xprint(\"--stderr------------------\", CBOLD + CRED)\n                xprint(errs.decode('utf-8'))\n            if errs != None or outs != None:\n                xprint(\"--------------------------\", CBOLD + CRED)\n                xprint(\"\")\n        else:\n            testOk = True\n            if (path.exists(expectedResultFilePath)):\n                testOk = compareFilesLineByLine(kind, testFilePath, actualResultFilePath, expectedResultFilePath)\n\n            if (testOk):\n                xprint(f\"PASSED: {testFilePath}\", CBOLD + CGREEN)\n\n            updateExpectedFromActualIfNeed(kind, actualResultFilePath, expectedResultFilePath)\n\n\ndef runDiagTest(compiler, workingDir, dirname, name):\n    runTestGeneric(compiler, workingDir, dirname, name, \"Diagnostics\", '.diag.txt', [\"-diag-file\"], False)\n\ndef runSATest(compiler, workingDir, dirname, name):\n    runTestGeneric(compiler, workingDir, dirname, name, \"Static Analyzer\", '.diag.txt', [\"-sa\", \"-diag-file\"], False)\n\ndef runExecuteTest(compiler, workingDir, dirname, name):\n    runTestGeneric(compiler, workingDir, dirname, name, \"Exec\", '.out', [\"--check-stack\"], True)\n\ndef runParseTypesTest(compiler, workingDir, dirname, name):\n    runTestGeneric(compiler, workingDir, dirname, name, \"Parse Types\", '.out', [\"--parse-types\"], True)\n\ndef runASTTest(compiler, workingDir, dirname, name):\n    runTestGeneric(compiler, workingDir, dirname, name, \"AST\", '.opt.txt', [\"-ast-dump\"], False)\n\n\ndef runTestForData(filePath, compiler, workingDir, testMode):\n    global numOfFailedTests\n    global numOfTests\n\n    with printLock:\n        numOfTests = numOfTests + 1\n\n    basename = os.path.basename(filePath)\n    dirname = os.path.dirname(filePath)\n    index_of_dot = basename.index('.')\n    name = basename[:index_of_dot]\n    suffix = basename[index_of_dot:]\n    if suffix == \".nut\" or suffix == \".nut.txt\":\n        if testMode == 'ast':\n            runASTTest(compiler, workingDir, dirname, name)\n        elif testMode == 'diag':\n            runDiagTest(compiler, workingDir, dirname, name)\n        elif testMode == 'exec':\n            runExecuteTest(compiler, workingDir, dirname, name)\n        elif testMode == 'types':\n            runParseTypesTest(compiler, workingDir, dirname, name)\n        elif testMode == 'sa':\n            runSATest(compiler, workingDir, dirname, name)\n        else:\n            with printLock:\n                xprint(f\"Unknown test mode {testMode}\")\n\n\ndef collectTests(subdir, mode):\n    p = Path(computePath('testData', subdir))\n    return [(str(f), mode) for f in sorted(p.rglob('*')) if f.is_file()]\n\n\ndef checkCompiler(compiler):\n    try:\n        if not path.exists(compiler):\n            xprint('FAIL: compiler executable \\'{0}\\' not found'.format(compiler))\n            exit(1)\n\n        compProc = Popen([compiler, '-v'])\n        compProc.communicate()\n        if compProc.returncode != 0:\n            xprint('FAIL: {0} is not an sq compiler'.format(compiler))\n            exit(1)\n    except:\n        xprint('FAIL: {0} is not an sq compiler'.format(compiler))\n        exit(1)\n\n\ndef main():\n    global numOfFailedTests\n    global verbose, ciRun\n    default_sq = computePath('build', 'bin', 'Debug', 'sq.exe' if platform.system() == 'Windows' else 'sq')\n\n    parser = argparse.ArgumentParser(description='quirrel test runner')\n    parser.add_argument('-sq', '--squirrel', action=\"store\", type=str, default = default_sq, help = \"Path to Quirrel compiler\")\n    parser.add_argument('-wd', '--working-dir', action=\"store\", type=str, default = tempfile.TemporaryDirectory().name, help = \"Directory to store tests data like ast dumps, diganotics dumps and so on\")\n    parser.add_argument('-v', '--verbose', default = False, action=\"store_true\", help = \"Extra output like CLI commands\")\n    parser.add_argument('-ci', '--continious-integration', default = False, action=\"store_true\", help = \"Signals that script is being run under CI\")\n\n    args = parser.parse_args()\n\n    compiler = args.squirrel\n    workingDir = args.working_dir\n    verbose = args.verbose\n    ciRun = args.continious_integration\n\n    if platform.system() == 'Windows' and not compiler.endswith('.exe'):\n        compiler += '.exe'\n\n    checkCompiler(compiler)\n\n    allTests = []\n    allTests += collectTests('exec', 'exec')\n    allTests += collectTests('diagnostics', 'diag')\n    allTests += collectTests('ast', 'ast')\n    allTests += collectTests('static_analyzer', 'sa')\n    allTests += collectTests('types', 'types')\n\n    with ThreadPoolExecutor(max_workers=THREADS) as pool:\n        futures = [pool.submit(runTestForData, f, compiler, workingDir, mode)\n                   for f, mode in allTests]\n        for fut in as_completed(futures):\n            fut.result()\n\n    if numOfFailedTests:\n        xprint(f\"Failed tests: {numOfFailedTests}\", CBOLD + CRED)\n    else:\n        xprint(f\"All tests passed\", CBOLD + CGREEN)\n\n    exit (1 if numOfFailedTests > 0 else 0)\n\n\n\nif __name__ == \"__main__\":\n   main()\n\n"
  }
]