{"id":23409707,"url":"https://github.com/aelhometta/aelhometta","last_synced_at":"2025-04-12T01:17:44.357Z","repository":{"id":217488225,"uuid":"744038516","full_name":"aelhometta/aelhometta","owner":"aelhometta","description":"Archaic attempt at autonomous non-sandboxed distributed artificial life of assembler automaton type.","archived":false,"fork":false,"pushed_at":"2024-06-26T12:56:47.000Z","size":323,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"v1.0.16","last_synced_at":"2025-04-12T01:17:34.649Z","etag":null,"topics":["artificial","assembler","autonomy","cross-platform","distributed","emergence","evolution","input-output","life","mildew","network","non-sandboxed","parallel","peer","publish-subscribe","rust","shell","stochastic","tor","zeromq"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/aelhometta","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aelhometta.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE-GPL-3","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-16T14:09:57.000Z","updated_at":"2024-06-26T12:55:00.000Z","dependencies_parsed_at":"2024-01-17T21:06:05.387Z","dependency_job_id":"a318f7ed-8163-4bff-a806-f0c7880a70ae","html_url":"https://github.com/aelhometta/aelhometta","commit_stats":{"total_commits":2,"total_committers":1,"mean_commits":2.0,"dds":0.0,"last_synced_commit":"6faf634a051093154f1b75ad14ddd0c6e82de766"},"previous_names":["aelhometta/aelhometta"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aelhometta%2Faelhometta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aelhometta%2Faelhometta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aelhometta%2Faelhometta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aelhometta%2Faelhometta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aelhometta","download_url":"https://codeload.github.com/aelhometta/aelhometta/tar.gz/refs/heads/v1.0.16","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248501858,"owners_count":21114684,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artificial","assembler","autonomy","cross-platform","distributed","emergence","evolution","input-output","life","mildew","network","non-sandboxed","parallel","peer","publish-subscribe","rust","shell","stochastic","tor","zeromq"],"created_at":"2024-12-22T16:12:37.314Z","updated_at":"2025-04-12T01:17:44.332Z","avatar_url":"https://github.com/aelhometta.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ælhometta\n\n[![crate](https://img.shields.io/crates/v/aelhometta)](https://crates.io/crates/aelhometta)\n\nArchaic attempt at autonomous non-sandboxed distributed artificial life of assembler automaton type, it features: separation of descriptive and executive data that provides branches and loops without jump instructions, encrypted publish-subscribe interaction with other instances over Tor, input/output through ordinary files associated with external sensors and actuators, and built-in shell.\n\nOf course it is akin to AlChemy\u003csup\u003e[[FON1]](#refFON1), [[FON2]](#refFON2)\u003c/sup\u003e / Avida\u003csup\u003e[[ADA1]](#refADA1), [[OFR1]](#refOFR1)\u003c/sup\u003e / Coreworld\u003csup\u003e[[RAS1]](#refRAS1)\u003c/sup\u003e / Stringmol\u003csup\u003e[[HIC1]](#refHIC1)\u003c/sup\u003e / (Network) Tierra\u003csup\u003e[[RAY1]](#refRAY1), [[RAY3]](#refRAY3)\u003c/sup\u003e / ... / biolife and it, as a project and a concept, may collapse or branch sooner rather than later due to participation of few devices *you* have certain control over, which are periodically online and which are optionally connected, on the one hand, to microphones, cameras, thermometers, receivers, ~~dosimeters~~ etc. (inputs) and, on the other hand, to speakers, monitors, conditioners, transmitters, ~~control rods~~ and so on (outputs). However, an instance can run completely isolated in memory of an offline device with no access to outside world, or switch between offline and online modes.\n\n![demo scast gif](https://raw.githubusercontent.com/aelhometta/visuals/main/aelhometta_demo.gif)\n\n![freqs scast gif](https://raw.githubusercontent.com/aelhometta/visuals/main/aelhometta_freqs.gif)\n\nBy now you probably know the big shining elusive goals of such enterprises better than us, — open-endedness, Cambrian explosion, blah-blah-blah, — the problem is, what if they are incompatible with safety? What if necessary (though in no way sufficient) condition is to allow the interaction of the artificial environment at hand with the real world beyond sandboxing threshold? Are we, shaped by evolution in this world, able to recognise open-endedness if it has not been moulded by the forces of the same world, when some of them do not have even names? If it kills, it will be killed... or rather less adapted variations will be, but more adapted ones will survive.\n\nIf so, then we ought to choose: open-endedness XOR safety. On the other hand, our precious safety may follow from... experience, simply: decades of researches, volumes of reflections, but — without exceptions, since we are still here... yet — in the end, a fizzle. As noted twenty years ago,\n\n\u003e \u003ci\u003e\u0026ldquo;All of this was impressive work, and it pointed the way forward to a consolidation of what these imaginative individuals had done. But the consolidation never happened. At each conference I went to, the larger group of people involved all seemed to want to do things from scratch, in their own way. Each had his or her own way of setting up the issues. There was not nearly enough work that\u003c/i\u003e built on \u003ci\u003ethe promising beginnings of Ray and others. The field never made a transition into anything resembling normal science. And it has now ground to a halt.\u0026rdquo;\u003c/i\u003e\u003csup\u003e[[GOD1]](#refGOD1)\u003c/sup\u003e\n\n**CONTENTS**\n\n* [Features](#features)\n\n* [Deployment](#deployment)\n\n* [Quickstart](#quickstart)\n\n* [Commander and shell](#commander-and-shell)\n\n* [Basic elements of ælhometta](#basic-elements-of-ælhometta)\n\n* [A node](#a-node)\n\n* [A controller](#a-controller)\n\n* [Ancestors...](#ancestors)\n\n* [...and Descendants](#and-descendants)\n\n* [Mutations](#mutations)\n\n* [Networking](#networking)\n\n* [Input/Output](#inputoutput)\n\n* [Typical behaviours](#typical-behaviours)\n\n* [Achievements and mischievements](#achievements-and-mischievements)\n\n* [That stuff (etymology, disclaimers, acknowledgements, license, contacts)](#that-stuff)\n\n* [\"C'est les Autres\"](#cest-les-autres)\n\n* [Bibliography](#bibliography)\n\n## Features\n\n* Nodes, kind of memory units — contain elementary instructions, have opaque addresses, join into chains via pointers to next nodes.\n\n* Controllers, kind of CPUs — chosen randomly at each tick, move along chains of nodes, execute instructions changing their local states and the global state.\n\n* No \"pointer arithmetic\" and thus free \"write protection\" due to opacity of a node address.\nBye-bye brittleness? Hello rigidness! Also, less Euclidicity of a \"space\" ælhometta inhabits: it is neither 1D, nor any nD, connectivity is poor, things do not \"move\" across short or long distances (in fact, there is no metric).\n\n* Separation of descriptive (\"schemes\" akin to chromosomes) and executive (\"constructors\" akin to ribosomes) chains in ancestral entity: one chain describes the scheme and another chain realizes it. This is probably the main deviation from \"traditional\", in these parts of artificial life world, approach, where an \"organism\" usually scans and reproduces its own code... although it resembles (hyper)parasites that had evolved in Tierra\u003csup\u003e[[RAY1]](#refRAY1)\u003c/sup\u003e, and, of course, the original approach of von Neumann has this separation\u003csup\u003e[[NEU1]](#refNEU1)\u003c/sup\u003e.\n\n* (Such separation provides) non-linearity of execution flow without jump instructions, neither by address, nor by template; instead, each node has 2 pointers, one to the main next node, and another to the alternative next node. The choice is made by the controller accordingly to certain flag, but both routes are defined by the scheme from which the executed chain has been constructed.\n\n* Based on the original chain, a new chain can be replicated (linearly copied verbatim) or constructed (non-linearly built taking into account special \"construction\" instructions).\n\n* \"Mortality\" via ring buffers and dangling pointers: when the maximum number of nodes or controllers has been allocated, the newest ones replace the oldest ones, and when a controller moves to non-existent node following the pointer of the previous node, this controller ceases to exist.\n\n* 2 globally accessible arrays — of nodes' opaque addresses and of integers — for communication between controllers. The former contains not all such addresses, but only those transmitted by controllers. The addressing is linear here, thus Euclidicity strikes back.\n\n* Encrypted interaction with other instances over Internet, specifically over [Tor](https://www.torproject.org/), following the [publish-subscribe pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) of [ZeroMQ](https://zeromq.org/). The data being exchanged is an array of 64-bit little endian integers, at least at the level Ælhometta provides; how ælhomettas *interpret* that data is meaningless question until they reach certain level of complexity.\n\n* Input and output to connect with \"real world\" by means of ordinary files containing 64-bit little endian integers as well. Missing link here is a bunch of external applications connecting *files themselves* with real world, of 2 kinds: recorders writing data from sensors to files and players reading data from files to control actuators.\n\n* Lack of ways to tinker with individual nodes and controllers \"manually\", so that you don't play at atoms of a dice and let sister Chance do it.\n\n* Control using interactive shell or run for specified duration.\n\n* State is automatically saved at exit and loaded at start.\n\n* Cross-platform — it is known to work on, and there are precompiled binaries for, the following targets, at least:\n\n    * `x86_64-unknown-linux-gnu`\n\n    * `i686-unknown-linux-gnu`\n\n    * `aarch64-unknown-linux-gnu`\n\n    * `armv7-unknown-linux-gnueabihf`\n\n    * `x86_64-apple-darwin`\n\n    * `aarch64-apple-darwin`\n\n    * `aarch64-linux-android`\n\n    * `armv7-linux-androideabi`\n\n    * `x86_64-pc-windows-msvc`/`-gnu`\n\n    * `i686-pc-windows-msvc`/`-gnu`\n\n* Runs ~~even~~ in text mode.\n\n* Small source, less than 3 times larger than this entire README.\n\n## Deployment\n\ndepends on the target system, where Ælhometta is going to be run. Download the binary [release](https://github.com/aelhometta/aelhometta/releases) or build it from source, which is available [at crates.io](https://crates.io/crates/aelhometta) and [at GitHub](https://github.com/aelhometta/aelhometta).\n\nBinaries are the quickest way to try the thing, while building from source specifically for your device paves the way for optimisations that may be absent from \"generic\" binaries; in particular, *speed* is important, — 10% does not look so small a gain when it becomes the difference between 10 and 11 days, months, years of waiting for (digital) evolution to reach some milestone... or admitting there is none. (Who's gonna wait so long?) Of course, you need certain interest to invest in that tuning.\n\nMost of dependencies-related bothers concern `libzmq` and `libsodium`, the libraries that are required not by Ælhometta directly, but rather by [`emyzelium`](https://crates.io/crates/emyzelium) crate it depends on, which is a thin wrapper around parts of ZeroMQ; such thinness is the reason we call them dependencies of Ælhometta itself hereinafter.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eLinux on x86_64/i686/aarch64/arm[v7]/...\u003c/b\u003e\u003c/summary\u003e\n\nThe simplest way is to download the latest binary [release](https://github.com/aelhometta/aelhometta/releases) that corresponds to your architecture.\n\nNote that it contains dependencies, — `.so` files in `deps/`, — which provide portability: `aelhometta_using_deps.sh` should work whether these libraries are present system-wide or not. See also `*-unknown-linux-gnu`-related part of `build.rs`.\n\nTo install dependencies from the official repository system-wide (on Debian-based distros):\n\n```shell\n$ sudo apt install libzmq3-dev\n```\n\n---\n\nOr build Ælhometta from source: install the same dependencies as above, then [install Rust toolchain](https://www.rust-lang.org/tools/install), download the source e.g. to `~/rust/aelhometta/`, and from there\n\n```shell\n$ cargo build --release\n```\n\n---\n\nNext stop down the rabbit hole is to build from source the `libzmq` dependency of Ælhometta and *its* core dependency that provides security, `libsodium`. This has its own \"costs\" (of toolchain setup and compilation issues... most of the rest of this section belongs to C/C++ world, Rust is mentioned briefly in the end), but allows better device-specific tuning (e.g. `--enable-opt` option of `libsodium`'s `configure`) and lessens the number of shared libraries you have to pack with the executable; usually these 2 suffice, in comparison with additional `libpgm`, `libnorm`, `libcomm_err`, ... from official repositories with \"all-included\" `libzmq`. Evidently, this step is *mandatory* when there are no prebuilt binaries/libraries for the device at hand.\n\nHereinafter we assume that `libsodium` and `libzmq` are *not* installed system-wide, so that they do not interfere with building process as wrong dependencies.\n\n* install build tools:\n\n```shell\n$ sudo apt install cmake\n```\n\n(it will install `make` too as recommended)\n\n**I) `libsodium`**\n\n* download `libsodium-X.Y.Z[-stable].tar.gz` from https://download.libsodium.org/libsodium/releases/, extract its main content to e.g. `~/libsodium/`, and create `build` dir there. You may have to add the content of `src/` dir to `~/libsodium/src/`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eNative build of libsodium\u003c/b\u003e\u003c/summary\u003e\n\n* install compiler(s):\n\n```shell\n$ sudo apt install g++\n```\n\n* from `~/libsodium/build/`, run the usual:\n\n```shell\n$ ../configure\n$ make -j 8\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eCross build of libsodium\u003c/b\u003e\u003c/summary\u003e\n\nAs an example, from `x86_64` host with Debian-based distro to `aarch64` target.\n\n* install toolchain:\n\n```shell\n$ sudo apt install g++-aarch64-linux-gnu\n```\n\n* in `~/libsodium/build/`, create the file `build.sh` (based on [this](https://doc.libsodium.org/installation#cross-compiling-to-arm-microcontrollers)):\n\n```shell\n#!/bin/sh\n\nexport CFLAGS='-Os'\n../configure --host=aarch64-linux-gnu\nmake -j 8\n```\n\nmake it executable via `chmod u+x` and run it.\n\n\u003c/details\u003e\n\n---\n\n**II) `libzmq`**\n\n* download `zeromq-A.B.C.tar.gz` from https://github.com/zeromq/libzmq/releases to e.g. `~/zeromq/`, create `build` dir inside\n\n* create `sysroot` dir in `~/zeromq/build/` and within it\n\n    * place a copy of `~/libsodium/src/libsodium/include/` dir (or symlink to it), with `version.h` file from `~/libsodium/build/src/libsodium/include/sodium/`\n\n    * create `lib` dir, copy into it `libsodium.so`, `libsodium.so.A` etc. — you've built those in **(I)** — from `~/libsodium/build/src/libsodium/.libs/` (or make it the symlink to `.../.libs/`)\n\n* prepare `genvars.cmake` file in `~/zeromq/build/` with the following content:\n\n```shell\nset(BUILD_STATIC OFF CACHE BOOL \"\")\nset(BUILD_TESTS OFF CACHE BOOL \"\")\nset(WITH_LIBBSD OFF CACHE BOOL \"\")\nset(WITH_LIBSODIUM ON CACHE BOOL \"\")\nset(ENABLE_CURVE ON CACHE BOOL \"\")\n```\n\n* prepare toolchain file for CMake, `toolchain.cmake`, in `~/zeromq/build/` (based on [this](https://gist.github.com/peterspackman/8cf73f7f12ba270aa8192d6911972fe8), [that](https://stackoverflow.com/a/6405064), [another one](https://stackoverflow.com/a/15456493), and [CMake documentation](https://cmake.org/cmake/help/latest/))\n\n    * 1st part of `toolchain.cmake`:\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eNative build of libzmq\u003c/b\u003e\u003c/summary\u003e\n\n```shell\nset(CMAKE_FIND_ROOT_PATH ${CMAKE_BINARY_DIR}/sysroot)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eCross build of libzmq\u003c/b\u003e\u003c/summary\u003e\n\n(Again, from `x86_64` to `aarch64`.)\n\n```shell\nset(TOOLCHAIN_PREFIX aarch64-linux-gnu)\n\nset(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)\nset(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)\n\nset(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX};${CMAKE_BINARY_DIR}/sysroot)\n```\n\n\u003c/details\u003e\n\n*   * 2nd part of `toolchain.cmake`:\n\n```shell\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n\nset(CMAKE_CXX_FLAGS \"-static-libgcc -static-libstdc++\")\n\nset(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_BINARY_DIR}/sysroot/lib/pkgconfig)\n\nset(CMAKE_SKIP_BUILD_RPATH true)\n```\n\nCheckpoint: the structure of the build tree should be\n\n```\n~/zeromq/build/\n|--sysroot/\n|  |--include/\n|  |--lib/\n|--genvars.cmake\n|--toolchain.cmake\n```\n\n* Change dir to `~/zeromq/build/` and run\n\n```shell\n$ cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -C genvars.cmake ..\n$ cmake --build . --config Release -j 8\n```\n\n---\n\n**Remark on cleaning.** Reset build dir to its initial state with a script such as (note `bash` instead of `sh`)\n\n```shell\n#!/bin/bash\n\nshopt -s extglob\nrm -rf !(\"sysroot\"|\"genvars.cmake\"|\"toolchain.cmake\")\n```\n\n---\n\n**Remark on `x86_64`-to-`i686` cross builds.** The toolchain is `g++[-9]-multilib`; if `g++-multilib` conflicts with something pertaining to ARM cross-tools, remove it, but keep its \"numbered\" version, e.g. `g++-9-multilib`. To `CFLAGS` and `CMAKE_CXX_FLAGS` variables add `-m32`. Also, you may need to add `/usr/include/asm` symlink to `/usr/include/asm-generic/`.\n\n---\n\n**Remark on building `libsodium` via `Zig`.** One more option, [install Zig](https://ziglang.org/download/) and follow [these instructions](https://libsodium.gitbook.io/doc/installation#compiling-and-cross-compiling-with-zig).\n\n---\n\nAssuming **(I)** and **(II)** were successful, you then place obtained shared libraries, `.so` files/symlinks of `libsodium` and `libzmq`, where Rust toolchain will be able to \"pick up\" them — into `~/rust/aelhometta/target/TARGET/release/deps/` (here `TARGET` is, well, target such as `aarch64-unknown-linux-gnu`). `libsodium.so.M` and `libzmq.so` symlinks suffice.\n\nAnd finally, from `~/rust/aelhometta`\n\n```shell\n$ cargo build --release [--target i686-unknown-linux-gnu]\n```\n\nor, if Cargo cannot choose proper linker on its own,\n\n```shell\n$ RUSTFLAGS=\"-C linker=aarch64-linux-gnu-g++\" cargo build --release --target aarch64-unknown-linux-gnu\n```\n\nSince the Ælhometta executable that comes out of this is \"tuned\" to the built versions of the libraries, they must be shipped with it. As an example, see Linux-targeted binary releases: there is `deps` dir with `libsodium.so.M` and `libzmq.so.N`, and the script that runs the executable tells dynamic linker/loader to look for them in that dir. In the simplest case when you run the executable from the same dir in which it resides,\n\n```shell\n$ LD_LIBRARY_PATH=deps:$LD_LIBRARY_PATH ./aelhometta\n```\n\nis enough.\n\n**Remark on symlinks.** Use them, if you go through many iterations of building process, to avoid copying, again and again, of an updated library to the build tree of a dependent program. For instance, make `~/zeromq/build/sysroot/lib/` the symlink to `~/libsodium/build/src/libsodium/.libs/`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003emacOS on x86_64/aarch64\u003c/b\u003e\u003c/summary\u003e\n\nis a case unsurprisingly similar to the Linux one, except for `brew` instead of `apt`, `zeromq` instead of `libzmq`, and few other distinctions.\n\nBegin with the latest binary [release](https://github.com/aelhometta/aelhometta/releases) for your architecture.\n\n`.dylib` files in `deps/` provide portability: `aelhometta_using_deps.sh` works whether these libraries are present system-wide or not.\n\nTo install dependencies system-wide, install the Homebrew package manager first, following the instructions at https://brew.sh/. Inter alia, Xcode Command Line Tools will be installed. Then\n\n```shell\n$ brew install zeromq\n```\n\n---\n\nOr build Ælhometta from source: install the same dependencies as above, then [install Rust toolchain](https://www.rust-lang.org/tools/install), download the source e.g. to `~/rust/aelhometta/`, and from there\n\n```shell\n$ cargo build --release\n```\n\n(1st time it may fail due to absence of `cc`, but macOS should then offer to install the toolchain in popup window.)\n\n---\n\nYou can also build from source the `libzmq` dependency of Ælhometta and *its* core dependency that provides security, `libsodium`. For example, when `$ brew install zeromq` fails (should we say breaks? spills?), or when you need better device-specific tuning (e.g. `--enable-opt` option of `libsodium`'s `configure`).\n\nIn fact, on old versions of macOS, this way is *much faster* than `$ brew install zeromq` — we're talking *minutes* vs. *hours* here — because the latter installs 20 or so dependencies, most of which are built from source as well.\n\nHere we consider mostly native build process, from macOS on MacBook to macOS on MacBook, save perhaps different arch (see remark at the end). Of course, there are cross alternatives, [QuickEmu](https://github.com/quickemu-project/quickemu) being one of them (take into account [this manual](https://github.com/quickemu-project/quickemu/wiki/03-Create-macOS-virtual-machines), [adding `ram=\"\u003csomething\u003eG\"` to `macos-\u003cversion\u003e.conf` along with decreasing 8 in `if [ \"${RAM_VM//G/}\" -lt 8 ]; then` line of `/usr/bin/quickemu`](https://github.com/quickemu-project/quickemu/issues/1191#issuecomment-2104059516), and [`--extra_args \"-cpu host\"` argument of `quickemu` call](https://github.com/GNS3/gns3-server/issues/1639)).\n\nFor the sake of simplicity we assume that `libsodium` and `libzmq` are *not* installed system-wide; if they are, they may interfere with building process as wrong dependencies.\n\n* install build tools:\n\n```shell\n$ brew install cmake pkg-config\n```\n\n**I) `libsodium`**\n\n* download `libsodium-X.Y.Z[-stable].tar.gz` from https://download.libsodium.org/libsodium/releases/, extract its main content to e.g. `~/libsodium/`. You may have to add the content of `src/` dir to `~/libsodium/src/`\n\n* from `~/libsodium/`, run the usual:\n\n```shell\n$ configure\n$ make -j 8\n```\n\n**II) `libzmq`**\n\n* download `zeromq-A.B.C.tar.gz` from https://github.com/zeromq/libzmq/releases to e.g. `~/zeromq/`, create `build` dir inside\n\n* create `sysroot` dir in `~/zeromq/build/` and within it\n\n    * place the `include` symlink to `~/libsodium/src/libsodium/include/` dir\n\n    * place the `lib` symlink to `~/libsodium/src/libsodium/.libs/` dir\n\n* prepare `genvars.cmake` file in `~/zeromq/build/` with the following content:\n\n```shell\nset(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/sysroot CACHE PATH \"\")\n\nset(BUILD_STATIC OFF CACHE BOOL \"\")\nset(BUILD_TESTS OFF CACHE BOOL \"\")\nset(WITH_LIBSODIUM ON CACHE BOOL \"\")\nset(ENABLE_CURVE ON CACHE BOOL \"\")\n```\n\nCheckpoint: the structure of the build tree should be\n\n```\n~/zeromq/build/\n|--sysroot/\n|  |--include/\n|  |--lib/\n|--genvars.cmake\n```\n\n* Change dir to `~/zeromq/build/` and run\n\n```shell\n$ cmake -C genvars.cmake ..\n$ cmake --build . --config Release -j 8\n```\n\nAssuming **(I)** and **(II)** were successful, you then place the symlink to the built shared library `libzmq.dylib` where Rust toolchain will be able to \"pick up\" it — into `~/rust/aelhometta/target/release/deps/`.\n\nAnd finally, from `~/rust/aelhometta/`,\n\n```shell\n$ cargo build --release\n```\n\nThe Ælhometta executable you obtain this way is \"tuned\" to the built versions of the libraries, `libsodium.M.dylib` and `libzmq.N.dylib`, so they must be present somewhere near, and you load it with `DYLD_LIBRARY_PATH` pointing to their location. As an example, see macOS binary release. In particular, when you run the executable from the same dir in which it resides, and `.dylib`s are in `deps` subdir:\n\n```shell\n$ DYLD_LIBRARY_PATH=deps:$DYLD_LIBRARY_PATH ./aelhometta\n```\n\n---\n\n**Remark on building from `x86_64` to `aarch64` or vice versa.** Almost the same story, but the script for building `libsodium` better take form of a file, say, `build.sh` inside `~/libsodium/`, with\n\n```shell\n#!/bin/sh\nexport CC=\"cc --target=aarch64-apple-darwin\"\nexport CFLAGS=\"--target=aarch64-apple-darwin\"\n../configure --host=aarch64-apple-darwin\nmake -j 8\n```\n\n(without this duplication of `--target=...`, `.dylib` files are absent or \"hollow\"), and similarly `libzmq` is built by\n\n```shell\n$ cmake -DCMAKE_C_FLAGS=\"--target=aarch64-apple-darwin\" -DCMAKE_CXX_FLAGS=\"--target=aarch64-apple-darwin\" -C genvars.cmake ..\n$ cmake --build . --config Release -j 8\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAndroid on armv7/aarch64\u003c/b\u003e\u003c/summary\u003e\n\nCurrently, Ælhometta on such systems runs as native executable in [Termux](https://termux.dev/en/), so install it first and right away update its packages via `$ pkg update \u0026\u0026 pkg upgrade`. Please [remember that](https://wiki.termux.com/wiki/Internal_and_external_storage) executables should be inside `~` of Termux (= `/data/data/com.termux/files/home`), not anywhere on internal memory or external SD; `$ termux-setup-storage` will provide access to the part of external SD under `Android/data/com.termux/files`, which you can use to bring Ælhometta's binary to, for example, `~/aelhometta/` via `$ cp` within Termux itself.\n\nRooting is not required for this.\n\nDependencies:\n\n```shell\n$ pkg install libzmq\n```\n\nYou can get the latest binary [release](https://github.com/aelhometta/aelhometta/releases) (which includes dependencies, `.so` files in `deps/`) for `armv7` or `aarch64` accordingly (hint: use `$ lscpu` in Termux).\n\n---\n\nAlternatively, build from source; the rest of this section describes how.\n\n1) **Native build.** Use Rust package for Termux, *not* the script from https://sh.rustup.rs:\n\n```shell\n$ pkg install rust\n```\n\nThe rest of the building process is the same as in Linux case, except for `$ pkg install libzmq` instead of `$ sudo apt install libzmq3-dev`.\n\n2) **Cross build.** You need another `x86_64` or `i686` device with Linux. There,\n\n* [download](https://developer.android.com/ndk/downloads) the latest Android *N*DK for Linux and extract it to e.g. `~/android-ndk-r26d/`. SDK/Studio would be redundant. **Be careful to retain symlinks** in `.zip` of NDK during extraction, or else [it will not work](https://github.com/android/ndk/issues/1738) — `C compiler cannot create executables` errors of `configure` appear; produced by `clang` invocation, they kind of mislead... `no input files`, `posix_spawn failed: exec format error` etc. [This comment](https://github.com/android/ndk/issues/1738#issuecomment-1207370493) suggests using command line `unzip` instead of built-in extractors of file managers with GUI\n\n* [install Rust toolchain](https://www.rust-lang.org/tools/install)\n\n* get Ælhometta's source\n\n* get `.deb` file of `libzmq` package from https://packages.termux.dev/apt/termux-main/pool/main/ and browse it as archive in Midnight Commander (or `$ ar x package.deb \u0026\u0026 tar -x -f data.tar.xz`). You need `libzmq.so` from `usr/lib/`, copy it to `.../aelhometta/target/TARGET/release/deps/`\n\n* finally, from source dir,\n\n```shell\n$ RUSTFLAGS=\"-C linker=$HOME/android-ndk-r26d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++\" cargo build --release --target aarch64-linux-android\n```\n\n(or similar for `armv7[a]-linux-androideabi` instead of `aarch64-linux-android`) to obtain the binary in `target/TARGET/release`\n\n---\n\n[`cross` crate](https://github.com/cross-rs/cross) is an alternative to Android NDK, it requires some [dependencies](https://github.com/cross-rs/cross#dependencies) in turn, [Docker Engine](https://docs.docker.com/engine/install/ubuntu/) in particular. Then you do not specify `RUSTFLAGS` and replace `cargo build ...` with `cross build ...`\n\n---\n\nNote Termux-specific library path, hardcoded into the binary, in `build.rs`. There is also the option to link statically.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eCross build of libzmq for Android from source\u003c/b\u003e\u003c/summary\u003e\n\nis simplified by Android-oriented build scripts *already included* into `libzmq` source release, so that you need to provide only general parameters. In particular, `libsodium` is built along the way. For the sake of definiteness, here we assume Debian as the host system and `aarch64` as the target system.\n\n* get [Android NDK](https://developer.android.com/ndk/downloads) for Linux (see **(2)** above)\n\n* download `libsodium-X.Y.Z[-stable].tar.gz` from https://download.libsodium.org/libsodium/releases/ and extract its main content to e.g. `~/libsodium/`\n\n* download `zeromq-A.B.C.tar.gz` from https://github.com/zeromq/libzmq/releases and extract to e.g. `~/zeromq/`\n\n* go to `~/zeromq/builds/android/` and look through `README.md`. Accordingly, create `build_aarch64.sh` with\n\n```shell\n#!/bin/sh\n\n# export MIN_SDK_VERSION=21\n\nexport NDK_VERSION=android-ndk-r26d\nexport ANDROID_NDK_ROOT=$HOME/${NDK_VERSION}\n\nexport CURVE=libsodium\nexport LIBSODIUM_ROOT=$HOME/libsodium\n\n./build.sh arm64\n```\n\nthen make it executable via `chmod u+x ...` and run\n\n* obtain built `libzmq.so` (both linking and runtime dependency), `libsodium.so` and `libc++_shared.so` (runtime dependencies) from `/zeromq/builds/android/prefix/arm64/lib/`\n\n\u003c/details\u003e\n\n---\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eWindows on x86_64/i686\u003c/b\u003e\u003c/summary\u003e\n\nThe latest binary [release](https://github.com/aelhometta/aelhometta/releases) contains the executable and the `.dll` dependencies.\n\n---\n\nOr build from source, in which case comes first the captivating task to produce linking and runtime ZeroMQ libraries from [`libzmq` latest release](https://github.com/zeromq/libzmq/releases) by means of some C/C++ toolchain, [CMake](https://cmake.org/), and [Sodium](https://doc.libsodium.org/)... if you do not obtain them, prebuilt, from somewhere else.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eNative build (Windows)\u003c/b\u003e\u003c/summary\u003e\n\n* install [Build Tools for Visual Studio](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) including CMake; the Studio itself is not required\n\n* prepare `genvars.cmake` file with the following content:\n\n```shell\nset(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/sysroot CACHE PATH \"\")\n\nset(BUILD_STATIC OFF CACHE BOOL \"\")\nset(BUILD_TESTS OFF CACHE BOOL \"\")\nset(WITH_LIBSODIUM ON CACHE BOOL \"\")\nset(ENABLE_CURVE ON CACHE BOOL \"\")\n```\n\n* download `zeromq-A.B.C.zip` from https://github.com/zeromq/libzmq/releases to e.g. `C:/src/zeromq-X.Y.Z/`, create `build` dir in it, and go into that `build/`; there, place `genvars.cmake` and create `sysroot` dir with `include` and `lib` subdirs\n\n* download `libsodium-X.Y.Z[-stable]-msvc.zip` from https://download.libsodium.org/libsodium/releases/; extract `include/` and `x64/Release/v.../dynamic` contents into `build/sysroot/include/` and `build/sysroot/lib/` dirs respectively\n\n* run the \"Tools-enhanced\" Command Prompt, corresponding to your host and target, e.g. `x64 Native Tools Command Prompt` (see VS-related shortcuts in Start Menu). Inside such prompt, change dir to `C:/src/zeromq-Z.Y.Z/build/` and from there:\n\n```shell\n\u003e cmake -C genvars.cmake ..\n\u003e cmake --build . --config Release -j 8\n```\n\n(Note: \"bare\" Command Prompt is not enough here.)\n\n* rename `build/lib/libzmq-....lib` to `zmq.lib`\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eCross build (Ubuntu to Windows)\u003c/b\u003e\u003c/summary\u003e\n\n* install CMake and [MinGW-w64](https://www.mingw-w64.org/):\n\n```shell\n$ sudo apt install cmake mingw-w64\n```\n\n* prepare toolchain file for CMake, `toolchain.cmake`, with the following content:\n\n```shell\nset(CMAKE_SYSTEM_NAME Windows)\nset(CMAKE_SYSTEM_VERSION 10.0) # 6.1 -\u003e Windows 7, 6.2 -\u003e Windows 8, 6.3 -\u003e Windows 8.1, 10.0 -\u003e Windows 10\nset(TOOLCHAIN_PREFIX ARCH-w64-mingw32)\n\nset(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)\nset(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)\nset(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)\n\nset(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX};${CMAKE_BINARY_DIR}/sysroot)\n\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n\nset(CMAKE_CXX_FLAGS \"-static-libgcc -static-libstdc++\")\n\nset(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_BINARY_DIR}/sysroot/lib/pkgconfig)\n```\n\nwhere `ARCH` is either `x86_64` or `i686`\n\n* prepare `genvars.cmake` file with\n\n```shell\nset(BUILD_STATIC OFF CACHE BOOL \"\")\nset(BUILD_TESTS OFF CACHE BOOL \"\")\nset(ZMQ_CV_IMPL none CACHE STRING \"\")\nset(WITH_LIBBSD OFF CACHE BOOL \"\")\nset(WITH_LIBSODIUM ON CACHE BOOL \"\")\nset(ENABLE_CURVE ON CACHE BOOL \"\")\n```\n\n* download `zeromq-A.B.C.tar.gz` from https://github.com/zeromq/libzmq/releases to e.g. `~/zeromq-X.Y.Z/`, create `build` dir in it, and go into that `build/`; there, place `toolchain.cmake`, `genvars.cmake`, and create `sysroot` dir\n\n* download `libsodium-X.Y.Z[-stable]-mingw.tar.gz` from https://download.libsodium.org/libsodium/releases/ and extract `libsodium-win...` content (`bin/`, `include/`, `lib/`) into `build/sysroot/`\n\n* at last, from `build/`:\n\n```shell\n$ cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -C genvars.cmake ..\n$ cmake --build . --config Release -j 8\n```\n\n\u003c/details\u003e\n\n---\n\nNow `zmq.lib` (native) / `libzmq.dll.a` (cross) — the *linking* library — should appear in `build/lib/`; and `libzmq-....dll` (native) / `libzmq.dll` (cross) — the *runtime* library — in `build/bin/`.\n\nThen, — assuming that [Rust toolchain is installed](https://www.rust-lang.org/tools/install) and Ælhometta's source is downloaded to `.../aelhometta/`, — copy **linking** library to `.../aelhometta/target/TARGET/release/deps/` (where `TARGET` is either `x86_64-pc-windows-msvc` (native) / `x86_64-pc-windows-gnu` (cross) or `i686-pc-windows-...`). \n\nIf the compilation is a cross one, add required targets:\n\n```shell\n$ rustup target add x86_64-pc-windows-gnu i686-pc-windows-gnu\n```\n\nProduce the binary:\n\n```shell\n$ cargo build --release [--target ARCH-pc-windows-gnu]\n```\n\nfrom Ælhometta's source dir.\n\n---\n\nLastly, before running the binary, you need to place the following `.dll`-s in the dir with it:\n\n* `libzmq.dll` — from the output of `libzmq` building process described above\n\n* `libsodium-MN.dll` — from [Sodium release](https://download.libsodium.org/libsodium/releases/), which you also have got during a building process\n\nAdditionally, in case of cross build: \n\n* `libwinpthread-1.dll` and `libgcc_s_seh-1.dll` (64-bit) / `libgcc_s_[dw2|sjlj]-1.dll` (32-bit) — from wherever, e.g. from `/usr/x86_64-w64-mingw32/lib/` and `/usr/lib/gcc/x86_64-w64-mingw32/9.3-posix` or [WinLibs](https://winlibs.com/) toolchain for MinGW-w64 \n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eSomething else\u003c/b\u003e\u003c/summary\u003e\n\nIf there are no prebuilt binaries and emulation via e.g. [QEMU](https://www.qemu.org/) is not an option, what remains is to build from source. [Install Rust toolchain](https://www.rust-lang.org/tools/install), download Ælhometta's source to `.../aelhometta/`, and from there\n\n```shell\n$ cargo build --release\n```\n\nshould proceed almost to the end... when linking stage fails with `-lzmq not found`-like error. Well, now you need `libzmq`, both linking- and runtime-dependencies. Search at your OS repositories, Internet, try to build *it*, in turn, from source (see Linux case).\n\nThis is not impossible, because all cases above were here before. The more platforms are covered, the more hookable ones for whom they are native will be hooked and make the first tiny step that follows:\n\n\u003c/details\u003e\n\n## Quickstart\n\nBy now, after [Deployment](#deployment), you have Ælhometta's executable and dependencies on the target system. On Linux and macOS (and Android) you can also run the `aelhometta_using_deps.sh` script from binary release to make the executable rely on shared libraries in `deps/` instead of system ones, — the result should be the same. For the sake of definiteness, we assume that you run the executable itself.\n\nSince the state is saved in a file whose size can reach hundreds of MB, consider making a symbolic link to the binary, or placing that binary, at another location, perhaps a ramdisk, and running it from there:\n\n```shell\nuser@pc:/mnt/ramdisk/aelhom$ ./aelhometta\n```\n\nor *calling* it from there when symlinks are impossible (e.g. on Windows or Android):\n\n```shell\nuser@pc:/mnt/bigdisk/aelhom$ ~/rust/aelhometta/target/release/aelhometta\n```\n\nAnyway, then you see the *shell*, not of your OS (prompt `$`), but of Ælhometta itself (prompt `Æ`):\n\n```\nLoading Ælhometta... Cannot load Ælhometta: Cannot open 'aelhometta.bin': No such file or directory (os error 2)\nUsing new default one\nLoading Commander... Cannot load Commander: Cannot read from 'commander.json': No such file or directory (os error 2)\nUsing new default one\n\nLastick 1969.12.31 Wed 23:59:59.000 UTC - Age 0 : Nodes 0 | Controllers 0 | Limit =2^22 : Memory ~ 72 MiB\n\"?\" — see the list of available commands\nÆ █\n```\n\nWe are now at what may be called *Abiohazard Level 0*... since nothing has happened yet. Which is dull, so let us go further.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAbiohazard Level 1\u003c/b\u003e\u003c/summary\u003e\n\nwhere ælhometta is contained in the memory of your computer, does not reach other computers and does not interact with outside world.\n\nType in the following commands:\n\n```\nÆ anc b 5\nÆ r\n```\n\n(which is the same as\n\n```\nÆ ancestor b 5\nÆ run\n```\n\nbut with aliases). That is, we introduce an *ancestor* — of type `B`, with *spacity* 5 — and let the environment *tick* on its own. At each tick, a controller is chosen randomly from the set of all controllers, processes the content of the node it currently \"looks\" at, and moves to the next node.\n\nThe charts on the right visualise relative frequencies of executed commands and other instructions. In the beginning, `NextOptuid` should be the most frequent one.\n\nWait for half a minute or so, then press (almost) any key to stop ticking. There should be many more *nodes* and *controllers*, like this:\n\n```\n[0:00:29] Age 1934061 : Nodes 3645220 | Controllers 14159\n[0:00:30] Age 1965719 : Nodes 3702543 | Controllers 14346\n\nLastick 2024.01.16 Tue 12:00:30.292 UTC - Age 1974509 : Nodes 3720924 | Controllers 14407 | Limit 4194304=2^22 : Memory ~ 192 MiB\nÆ █\n```\n\nObserve more statistics:\n\n```\nÆ stat cgen\nÆ stat ctick\nÆ stat chan\nÆ stat cont\nÆ stat run\n```\n\nBy now, content statistics (`Æ stat cont`) mostly contains 0s, because only a fraction of all available commands and instructions are present in ancestor B and its exact replicas-descendants. Let's introduce random mutations, or *glitches*:\n\n```\nÆ glitch back 0.001\nÆ glitch repl 0.03\nÆ glitch cons 2.5e-2\n```\n\nThen again\n\n```\nÆ r\n```\n\nAfter a while, stop and compare new content statistics to the old one.\n\n---\n\nTo see how the structure of chains has changed in details, pick up random controller's uid — `CTRL-UID` (8 hexadecimal digits) — by\n\n```\nÆ rand ctrl\n```\n\nand see that controller's state:\n\n```\nÆ sct CTRL-UID\n```\n\nThe start node of the chain to which that controller is attached is given under `ChainStart`, we denote it by `NODE-UID`. Follow the chain from the start:\n\n```\nÆ ss NODE-UID\n```\n\nDisappointment: the sequence will be almost the same as that of the original entity, described in [Ancestors](#ancestors). Has evolution stuck?\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAbiohazard Level 2\u003c/b\u003e\u003c/summary\u003e\n\nwhere ælhometta interacts with other computers (or rather ælhomettas on them), but not (directly) with outside world.\n\nAssuming 2 ælhomettas running on 2 devices are at Abiohazard Level 1 already, you need additionally\n\n* from your side:\n\n    * 40-character Curve public and secret keys in Z85 format\n    * 56-character onion address and port (0–65535) of Tor hidden service running on your device\n\n* from other device's, or its owner's, side:\n\n    * 40-character Curve public and secret keys in Z85 format\n    * 56-character onion address and port (0–65535) of Tor hidden service running on that device\n\nHere's how to do it quickly:\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eObtain key pair in Python\u003c/b\u003e\u003c/summary\u003e\n\n```shell\n$ pip3 install -U pyzmq\n```\n\n```python\nimport zmq\npublic, secret = zmq.curve_keypair()\nprint(\"Public key:\", public.decode(\"ascii\"))\nprint(\"Secret key:\", secret.decode(\"ascii\"))\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eObtain key pair in Termux on Android\u003c/b\u003e\u003c/summary\u003e\n\n```shell\n$ pkg install libzmq\n$ curve_keygen\n```\n\n\u003c/details\u003e\n\n---\n\nIf on Linux, [set up Your Onion Service](https://community.torproject.org/onion-services/setup/), skipping Step 1, because you do not need a web server. Verify that Tor service runs via `$ systemctl status tor@default` and obtain onion address from `hostname` file in the dir specified with `HiddenServiceDir`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eOn macOS\u003c/b\u003e\u003c/summary\u003e\n\nInstall Tor:\n\n```shell\n$ brew install tor\n```\n\nGo to `/usr/local/etc/tor/` and make the copy of `torrc.sample` named `torrc`. Open `torrc` in any text editor, uncomment and change two `HiddenService`-related lines to something like:\n\n```\nHiddenServiceDir /usr/local/var/lib/tor/hidd_aelhom_srv1/\nHiddenServicePort 60847\n```\n\nNow add `lib/tor` directory subtree to `/usr/local/var/` if it is not already there. And then\n\n```shell\n$ brew services start tor\n```\n\nSoon `.../hidd_aelhom_srv1/` is created by Tor service (verify that it runs via `$ brew services info tor`). The `hostname` file within contains onion address. Backup other files too, privately.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eIn Termux on Android\u003c/b\u003e\u003c/summary\u003e\n\n```shell\n$ pkg install tor\n$ pkg install termux-services\n```\n\nOpen `/data/data/com.termux/files/usr/etc/tor/torrc` and edit the `HiddenService`-related lines:\n\n```\nHiddenServiceDir /data/data/com.termux/files/usr/var/lib/tor/hidd_aelhom_srv1/\nHiddenServicePort 60847\n```\n\nStart Tor service:\n\n```shell\n$ sv-enable tor\n$ sv up tor\n```\n\n(there is no `systemctl` or `service`). Wait for `.../hidd_aelhom_srv1/` dir to be created by the service (verify that it runs via `$ sv status tor`) and obtain the onion address from `hostname` file. Keep the copies of other files as well, privately.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eOn Windows\u003c/b\u003e\u003c/summary\u003e\n\n[Tor Expert Bundle](https://www.torproject.org/download/tor/) for Windows should suffice. Unpack its content, run Command Prompt as administrator, and, from `.../bundle/tor/`,\n\n```shell\n\u003e tor --service install\n```\n\nThis, inter alia, introduces `tor` subdir of `C:/Windows/ServiceProfiles/LocalService/AppData/Roaming/` dir. Create `torrc` file there with the content such as\n\n```\nHiddenServiceDir C:/Windows/ServiceProfiles/LocalService/AppData/Roaming/tor/hidden_service1\nHiddenServicePort 60847\n```\n\nFrom that administrator's command prompt,\n\n```shell\n\u003e tor --service stop\n\u003e tor --service start\n```\n\nSoon the `HiddenServiceDir`-specified dir appears, with some files inside. In particular, `hostname` contains the onion address. (Other files are important too, keep their copies privately.)\n\n\u003c/details\u003e\n\n---\n\nAs usual, a secret key must be known only to its owner.\n\nDefault port is `60847` (`0xEDAF`).\n\nWhen these strings and numbers have been established, on your device do\n\n```\nÆ peer secret MySecretKeyMySecretKeyMySecretKeyMySecre\nÆ peer port 60847\nÆ peer share size 10000\nÆ peer share interval 2000000\nÆ peer expose\n```\n\nOther participant, on their device, does\n\n```\nÆ peer secret TheirSecretKeyTheirSecretKeyTheirSecretK\nÆ peer port 60847\nÆ peer share size 20000\nÆ peer share interval 1000000\nÆ peer expose\n```\n\nNow both of you have to *subscribe* to each other's *publication*. You do\n\n```\nÆ peer connect TheirPublicKeyTheirPublicKeyTheirPublicK TheirOnionAddressTheirOnionAddressTheirOnionAddressTheir 60847\n```\n\nAnd they do\n\n```\nÆ peer connect MyPublicKeyMyPublicKeyMyPublicKeyMyPubli MyOnionAddressMyOnionAddressMyOnionAddressMyOnionAddress 60847\n```\n\nDo not forget to run both instances:\n\n```\nÆ r\n```\n\nIn a few seconds, if connection is established, your ælhometta will have access to arrays of 64-bit integers transmitted by their ælhometta. Check it on your side with\n\n```\nÆ peer\n```\n\n— there should be 1 other peer, its `Share size` should be non-zero, and its `Last update` should be some recent instant (typically few seconds in the past). To check the data received,\n\n```\nÆ peer ether TheirPublicKeyTheirPublicKeyTheirPublicK 0 100\n```\n\nWhether your and their ælhomettas actually *use* the integer values they exchange is a different question (hint: probably they do not, in the beginning).\n\n**Remark 1.** It is possible for \"other\" device to be... your device again, i.e. both ælhomettas run on the same computer. Only assign different `HiddenServicePort`-s in `/etc/tor/torrc` to corresponding hidden services.\n\n**Remark 2.** Some peers are already out there, although \"24/7 online\" is not guaranteed... at all. Try to connect to *them*:\n\n```\nÆ peer connect USBD7[O^8L[}saCh+6U#}6wie4oAedZ4#W4!b%LI t3kauc3flp2bpv3mv7vtnedfu6zrho3undncccj35akpuyjqqydwvfyd 60847\n\nÆ peer connect \u0026i!VkHl[]m.c!^j0D%i)\u00264#[u5b(a=QCdZ9C0$p{ yhel64h6cjab75tcpncnla2rdhqmxut2vtitywhbu7bpjh4hfhp6hnid 60847\n```\n\nThese two are just demo ones, maintained by us for the sake of network functionality testing. Someday, more may be listed in [Networking](#networking).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAbiohazard Level 3\u003c/b\u003e\u003c/summary\u003e\n\nwhere ælhometta interacts with other ælhomettas *and* with outside world.\n\nSo, your ælhometta runs at Abiohazard Level 2. We are going to add **audio** interaction with its surroundings, assuming that the device it runs on has at least a speaker and a microphone.\n\nWe also need 2 intermediate applications, in essence a player and a recorder. In view of very low requirements to their functionality, our \"player\" will be called *buzzer* and our \"recorder\" will be called *hearer*.\n\n---\n\n* The buzzer emits certain number of clear tones (sinusoidal waves) of different frequencies, each tone with its own volume, through the speaker. With certain time interval (e.g. 2 seconds) the volumes are read from the file `buzz.i64` and adjusted. For the sake of simplicity, only the lowest byte of an int64 value is used, others are assumed to be 0. That is, if the byte content read from the file is\n\n`2A 00 00 00  00 00 00 00  98 00 00 00  00 00 00 00 ... `\n\nthen 1st tone will be played with volume `2Ah` = 42 (out of 256), the 2nd tone — with volume `98h` = 152, and so on. Next time, the content read is\n\n`01 00 00 00  00 00 00 00  E7 00 00 00  00 00 00 00 ... `\n\nand volumes change: 1st tone becomes almost muted (volume 1/256), 2nd tone becomes louder (volume 231/256).\n\n---\n\n* The hearer records, from the microphone, samples of certain duration (e.g. half of a second), performs some spectral analysis, and writes the calculated levels pertaining to predefined bands of frequencies to the file `hear.i64`, overwriting previous levels. (Note: for now, it is irrelevant whether these bands have any relation to the frequencies of the buzzer.) As before, we assume 1-byte resolution.\n\nFor example, someone plays trombone near the microphone. In the sound recorded, low frequencies have larger amplitudes, while amplitudes of high frequencies are small. Therefore, the hearer writes to `hear.i64` data such as\n\n`DE 00 00 00  00 00 00 00  ...  20 00 00 00  00 00 00 00`\n\nThen they put trombone away and begin to whistle. Now the spectrum is mirrored: low frequencies carry less energy, high ones carry more,\n\n`14 00 00 00  00 00 00 00  ...  B3 00 00 00  00 00 00 00`\n\n---\n\nLook for quick-and-dirty Python implementation of such applications in [Input/Output](#inputoutput), or write them yourself, or use the functionality of more sophisticated [Digital audio editors](https://en.wikipedia.org/wiki/Comparison_of_digital_audio_editors).\n\nLet there be 12 frequencies of the buzzer and 14 bands of the hearer. Put the buzzer and the hearer to the dir with Ælhometta's executable and start them (the buzzer is silent, because `buzz.i64` does not exist yet.)\n\nAdd the mapping *from the file* `hear.i64` *to the range* of 14 integer channels of ælhometta, beginning with the 50th one:\n\n```\nÆ iomap in add 50 14 1500000 ./hear.i64\n```\n\nAnalogously, add the mapping *from the range* of 12 integer channels, beginning with the 70th one, *to the file*:\n\n```\nÆ iomap out add 70 12 1000000 ./buzz.i64\n```\n\nAnd then run,\n\n```\nÆ r\n```\n\nIf integer channels 70–81 contain large enough numbers, you should hear some... buzz. When these integers change, the buzz changes as well, with some delay. On the other hand,\n\n```\nÆ eth int 50 14\n```\n\nshould result in something similar to\n\n```\n          50        184=B8h\n          51        255=FFh\n          52        103=67h\n          53        67=43h\n          54        31=1Fh\n          55        48=30h\n          56        =29h\n          57        21=15h\n          58        9=9h\n          59        9=9h\n          60        10=Ah\n          61        6=6h\n          62        2=2h\n          63        0=0h\n```\n\nAn obvious \"dirty trick\" to skip waiting for \"evolution\" to fill buzzer-related integer channels with non-zero values is to \"short-circuit\" them with hearer-related channels: remove the \"out\" mapping above via\n\n```\nÆ iomap out del 0\n```\n\nand replace it with\n\n```\nÆ iomap out add 50 12 1000000 ./buzz.i64\n```\n\n**Behold!** in case you have included hearer's channels to what your ælhometta shares as a peer, anyone who subscribes to it will receive (very coarse) spectrum of the soundscape around your device, turning it into a [bug](https://en.wikipedia.org/wiki/Covert_listening_device).\n\n\u003c/details\u003e\n\n---\n\nFinally,\n\n```\nÆ q\n```\n\nsaves ælhometta's and commander's states to the current dir, and exits the shell (`qq` exits without saving anything).\n\nWhen you run the program next time, everything is restored:\n\n```\nLoading Ælhometta... OK\nLoading Commander... OK\n\nLastick 2024.01.16 Tue 23:57:21.584 UTC - Age 1974509 : Nodes 3720924 | Controllers 14407 | Limit 4194304=2^22 : Memory ~ 192 MiB\n\"?\" — see the list of available commands\nÆ █\n```\n\n---\n\n...Rest assured that it has been indeed only a \u003ci\u003equick\u003c/i\u003e\u003cb\u003e\u003ci\u003estart\u003c/i\u003e\u003c/b\u003e.\n\n## Commander and shell\n\nThe commander keeps few settings related to the format of data displayed while ælhometta runs — `Æ sets` shows them, `Æ set ...` sets them), — and shell history (`Æ history ...` displays recent or entire history). The shell itself is a basic command line interface.\n\nPut differently, commander and shell are *front-end* in comparison to *back-end* of ælhometta. While the shell awaits your input,\n\n```\nÆ █\n```\n\n— ælhometta is paused, there are no ticks.\n\nSettings of commander have no effect on how ælhometta behaves, except speed: when `show_ticks` is `true`, screen output of every tick slows it down significantly (2 times or even more). \n\n`Æ help`, or `Æ ?` for short, provides information about all commands or about given one. For instance,\n\n```\nÆ ? peer\n```\n\ndisplays descriptions and parameters of all subcommands concerning network configuration.\n\nThe state of commander is saved to `commander.json`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAvailable shell commands\u003c/b\u003e\u003c/summary\u003e\n\nMost of them have shorter aliases.\n\n* `quit` or `exit` or `end` or `bye` (and save state)\n* `quitquit` or ... `byebye` (do not save state)\n* `help`\n* `=` (repeat last command),\n* `ancestor` (introduce one, with parameters)\n* `run` (until keypress, show updated counters every second)\n* `tick` (one step of a controller)\n* `glitch` (probabilites and counters of mutations)\n* `shownode` (single node)\n* `showctrl` (state of controller)\n* `showseq` (forward sequence of nodes)\n* `prevnodes` (nodes that have given next one)\n* `backtrace` (backward sequence of nodes)\n* `ether` (2 global arrays of optuids and integers)\n* `random` (uid of random entity),\n* `statistics`\n* `cleanse` (part or all of state)\n* `commandswitch` (use to NOP commands)\n* `changelim` (adjust maximum number of entities)\n* `peer` (networking)\n* `iomap` (I/O),\n* `showsizes` (predefined sizes of some arrays)\n* `settings` (view commander settings)\n* `set` (change commander settings)\n* `history` (of commands)\n* `about` (regarding the program in general)\n\n\u003c/details\u003e\n\n---\n\n### Chart of frequencies\n\nYou have probably noticed it, because it occupies the right part of the screen and slightly changes each second... It, too, displays statistics, — of executed commands, construction instructions, and the ratio of main/alternative branch choices, — but over short interval of immediate past instead of over entire past, which `Æ stat run` does. The example in synopsis shows that the most frequent [Command](#command) during the last 16 seconds was `NextOptuid`.\n\nTo choose command (or construction instruction) and see its full name and exact count of occurrences over time window, press ← → (or ↑ ↓) while `run`ning. Any other key will stop `run`ning and return you to shell prompt `Æ`.\n\nAdjust the appearance of this window via `show_freqs`, `freqs_window_margin`, `freqs_comm_str_len`, and `freqs_cons_str_len` settings of commander. `freqs_interval` specifies the duration, in seconds, of the interval; default is 16.\n\nAs glitches introduce other commands and they percolate into chains of nodes, their frequencies increase. Moreover, some evolutionary shifts are expected to change the distribution so that one or another group of commands dominates, hinting at what \"species\" is more successful. The opposite implication is not guaranteed: e.g. distributions of chemical elements in mice and men are not very different, as well as distributions of these elements inside [geosphere](https://en.wikipedia.org/wiki/Geosphere) (inclusively interpreted) 10 million years ago and today.\n\n---\n\nIn the shell mode, exit status of the application is either 0 (success) or 2 (critical error). As for 1,\n\n### Run for specified duration without shell\n\nMost of the time, your ælhometta will run without any interference from you, hours after hours, maybe months after months, until you interrupt its silent course by pressing (almost) any key.\n\n![routine scast gif](https://raw.githubusercontent.com/aelhometta/visuals/main/aelhometta_routine_freqs.gif)\n\nFor the sake of resiliency, however, we recommend to backup the state regularly.\n\nThese approaches combine when you run the application with single argument instead of no arguments, that argument being the requested duration of running in seconds:\n\n```shell\n$ ./aelhometta 43200\n```\n\nThere is no shell in this mode. As soon as the duration ends (12 hours in this example) *or* (almost) any key is pressed, the application exits and saves the state. In the latter case, exit status is set to 1.\n\nTo run Ælhometta indefinitely with backup once per hour, place such call into a loop:\n\n```shell\n#!/bin/sh\n\nwhile true; do\n    ./aelhometta 3600\n    if [ $? = 1 ]; then\n        echo \"Halt due to keypress\"\n        break\n    fi\ndone\n```\n\nBe aware that this loop will continue in case of the application's critical error (exit status 2).\n\nTo run Ælhometta for one day each week, place the `/path/aelhometta 86400` call into `/etc/cron.weekly/`.\n\nWhatever the scenario of this kind is, it may help to imagine your character in the scenario being — absent, far away, gone, you name it, except for brief appearance in the beginning. Which is how the things are going to be anyway...\n\n### Run remotely\n\nBeside [SSH](https://en.wikipedia.org/wiki/Secure_Shell) access to remote computer where Ælhometta has been installed, you need a \"persistent detached terminal\", provided by *terminal multiplexer* like [Byobu](https://en.wikipedia.org/wiki/Byobu_(software)) or [tmux](https://en.wikipedia.org/wiki/Tmux) or [GNU Screen](https://en.wikipedia.org/wiki/GNU_Screen); install it there as well.\n\nSimply run Ælhometta in virtual terminal (preferably with regular backup as described above) and detach from that terminal; later, attach to it again.\n\nX11 connection or forwarding is not needed.\n\n---\n\nOnly now we proceed behind the curtain of superficially observable behaviour...\n\n## Basic elements of ælhometta\n\n...Perhaps the better way to acquaint yourself with it is to simply read through `src/aelhometta.rs`. The namesake structure verbatim from there:\n\n```rust\npub struct Ælhometta {\n    // Serialisable part\n    max_num_chains_binlog: u8,\n\n    new_node_uid: Uid,\n    nodes: HashMap\u003cUid, Node\u003e,\n    nodes_historing: Vec\u003cOptuid\u003e,\n    i_nodes_historing: usize,\n\n    new_controller_uid: Uid,\n    controllers: HashMap\u003cUid, Controller\u003e,\n    controllers_historing: Vec\u003cOptuid\u003e,\n    i_controllers_historing: usize,\n\n    commandswitch: u128,\n\n    ether_optuids: Vec\u003cOptuid\u003e,\n    ether_integers: Vec\u003cInteger\u003e,\n\n    age: u128,\n    ut_last_tick: i64,\n    \n    spaces_count: u128,\n    branches_main_count: u128,\n    branches_alt_count: u128,\n    commands_count: HashMap\u003cCommand, u128\u003e,\n    constructions_count: HashMap\u003cConstruction, u128\u003e,\n\n    glitch_background_prob: f64,\n    glitch_background_count: u128,\n    glitch_replicate_prob: f64,\n    glitch_replicate_count: u128,\n    glitch_construct_prob: f64,\n    glitch_construct_count: u128,\n\n    // Peer-related\n    share_size: usize,\n    share_interval: i64,\n\n    ut_last_share: i64,\n    shares_count: u128,\n\n    secretkey: String,\n    port: u16,\n    torproxy_port: u16,\n    torproxy_host: String,\n\n    exposed: bool,\n\n    other_peers: Vec\u003cOtherPeer\u003e,\n\n    whitelist: HashSet\u003cString\u003e,\n\n    in_permitted_before_num: u64,\n    in_attempted_before_num: u64,\n\n    ut_last_disconnect: i64,\n    ut_last_permit: i64,\n    ut_last_attempt: i64,\n\n    // IO-related\n    output_mappings: Vec\u003cIntegersFileMapping\u003e,\n    input_mappings: Vec\u003cIntegersFileMapping\u003e,\n\n    // Non-serialisable part\n    max_num_chains: usize,\n    max_num_chains_binmask: usize,\n\n    rng: ThreadRng,\n\n    efunguz: Option\u003cEfunguz\u003e,\n}\n```\n\nwhere\n\n```rust\npub type Uid = u32;\npub type Optuid = Option\u003cUid\u003e;\n\npub type Integer = i64;\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eNodes\u003c/b\u003e\u003c/summary\u003e\n\nSingle-linked units of information. See [A node](#a-node).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eControllers\u003c/b\u003e\u003c/summary\u003e\n\nAutomata that move along chains of nodes and act accordingly to the content of these nodes. See [A controller](#a-controller).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003e2 Ethers\u003c/b\u003e\u003c/summary\u003e\n\nGlobal arrays of opaque node addresses and integer values, accessible to all controllers.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003ePeer configuration\u003c/b\u003e\u003c/summary\u003e\n\nSpecifies network identity of ælhometta and its interaction with other ælhomettas across the network (Tor, to be more precise). See [Networking](#networking).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eI/O configuration\u003c/b\u003e\u003c/summary\u003e\n\nMaps continuous ranges of integers ether from (input) and to (output) files controlled by other applications. Those applications, in turn, connect the files with sensors and actuators in outside world. See [Input/Output](#inputoutput).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eMiscellaneous\u003c/b\u003e\u003c/summary\u003e\n\n`i`-th bit of `commandswitch`, when `0`, NOPs [Command](#command) with index `i`, i.e. replaces its execution by... nothing (considered successful). Since `GetExecFromOptuid` and `SetOptuidFromExec` commands deviate from descriptive/executive separation principle, they are NOPped by default (and you can change that).\n\n`age` increments each tick.\n\n`ut_last_tick`, as well as other `ut_...`s, is measured in microseconds since Unix epoch.\n\n`spaces_count`, `branches...count`, `commands_count` keeps track of how many times each respective content has been executed. `constructions_count` counts `Construction` instructions that have occured while executing `Construct` commands.\n\n---\n\nThe state of ælhometta is saved to `aelhometta.bin`, see `src/aelhometta/serbin.rs`. This serialisation, though binary and with tricks such as [LEB128](https://en.wikipedia.org/wiki/LEB128), is not minimal in size; classical ZIP, for instance, nearly halves it.\n\n\u003c/details\u003e\n\n## A node\n\n```rust\npub struct Node {\n    b_content: u8,\n    b_next: Uid,\n    b_altnext: Uid\n}\n```\n\nA node has *content*, which describes what the controller should do, and 2 pointers: *(main) next node* and *alternative next node*, which describe to what node the controller moves after this one.\nThe value of such pointer (it may be empty) is also called *optuid* (optional unique identifier).\n\nThe content is represented as standard byte, see `impl ToBits\u003cu8\u003e for Content` and `impl OtBits\u003cu8\u003e for Content` in `src/aelhometta.rs`.\n\nThere are 4 types of content:\n\n### Space\n\n[NOP](https://en.wikipedia.org/wiki/NOP_(code)), placeholder, does nothing. But it can be replaced with something.\n\n### Branch\n\nThis type of node is the only one providing non-linearity of execution path, if `GetExecFromOptuid` and `SetOptuidFromExec` commands are NOPped (which is the default).\n\nIf the `success` flag is `true`, execution pointer moves to the main next node.\n\nIf the `success` flag is `false`, execution pointer moves to the alternative next node.\n\n### Command\n\nSpecifies an action that controller should perform. May change controller's state — registers, flags, arrays of pointers, integers, and so on (see [A controller](#a-controller)); may also change the state of the entire ælhometta.\n\nIf a command fails (e.g. division by 0, overflow, index out of bounds), the `success` flag will be set to `false`. However, some \"junk\" may be present where result should have been, and what is \"failure\" and what is not depends. `Test...` commands affect `success` flag too.\n\n\"Uncrashability\" principle (single chemical reaction cannot crash the universe) permeates what commands do and is familiar to everyone in the trade.\n\nAgain, `src/aelhometta/tick.rs` provides more complete picture. The following list heavily relies on self-explanatory property of... words.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAvailable commands\u003c/b\u003e\u003c/summary\u003e\n\n* Nullary operators with integer result placed in the integer register:\n\n    * `RandomContent` (\"valid\" integer representing one of `Content` variants)\n    * `RandomInteger` (all 64 bits are random)\n    * `ZeroInteger`\n\n* Unary operators on integer register replacing its value with the result:\n\n    * `Abs`\n    * `BitNot`\n    * `Decrement`\n    * `Increment`\n    * `Negate`\n    * `ShiftDown`\n    * `ShiftUp`\n    * `Sign`\n    * `Square`\n\n* Binary operators on integer register as the 1st operand and selected integer as the 2nd one, the result goes to integer register:\n\n    * `Add`\n    * `BitAnd`\n    * `BitOr`\n    * `BitXor`\n    * `Divide`\n    * `Multiply`\n    * `Remainder`\n    * `Subtract`\n\n* Convert integer register to index of selected element in certain array...\n\n    * `IntegerToDataOptuidIndex`\n    * `IntegerToIntegerChannel`\n    * `IntegerToIntegerIndex`\n    * `IntegerToOptuidChannel`\n    * `IntegerToOptuidIndex`\n    * `IntegerToPeer`\n\n* ...and back:\n\n    * `DataOptuidIndexToInteger`\n    * `IntegerChannelToInteger`\n    * `IntegerIndexToInteger`\n    * `OptuidChannelToInteger`\n    * `OptuidIndexToInteger`\n    * `PeerToInteger`\n\n* Convert integer register to success flag and vice versa (usual int ↔ bool semantics):\n\n    * `IntegerToSuccess`\n    * `SuccessToInteger`\n\n* Operations with node pointed to by `data_optuids[i_data_optuid]`:\n\n    * `Insert`\n    * `Read`\n    * `Remove`\n    * `Skip`\n    * `Write`\n\n* Tests, affecting `success` flag:\n\n    * `TestDataOptuid` (true if `data_optuids[i_data_optuid]` points to existing node)\n    * `TestIntegerNegative`\n    * `TestIntegerNonZero`\n    * `TestIntegerPositive`\n\n* Creation of a new chain and, if it is active, of a controller attached to it:\n\n    * `Construct`\n    * `NewChainAddInteger`\n    * `NewChainAddIntegerChannel`\n    * `NewChainAddOptuid`\n    * `NewChainAddOptuidChannel`\n    * `NewChainDetach`\n    * `NewChainInitActive`\n    * `NewChainInitPassive`\n    * `Replicate`\n\n`Construct` and `Replicate` work with `data_optuids[i_data_optuid]` of a controller, consequtively reading the node where it points and advancing it to the next node. In a sense, they are \"shortcuts\", since they cut some corners of Ælhometta's artificial biochemistry.\n\n`NewChainAdd...` actually add respective element to the *controller* attached to the active chain being created.\n\nA new chain is not empty, it has `Space` node at the beginning.\n\n* Move to next/previous element of corresponding array:\n\n    * `NextDataOptuid`\n    * `NextInteger`\n    * `NextIntegerChannel`\n    * `NextOptuid`\n    * `NextOptuidChannel`\n    * `NextPeer`\n    * `PreviousDataOptuid`\n    * `PreviousInteger`\n    * `PreviousIntegerChannel`\n    * `PreviousOptuid`\n    * `PreviousOptuidChannel`\n    * `PreviousPeer`\n\n* Read/write \"optuids ether\" — global array of (some) optuids accessible to all controllers of ælhometta, with destination/source respectively being currently selected optuid of a controller, and the index of ether's element being provided by `optuid_channels[i_optuid_channel]`:\n\n    * `ReceiveOptuid`\n    * `TransmitOptuid`\n\n* Read/write \"integers ether\". Destination/source is integer register, ether's element is given by `integer_channels[i_integer_channel]`, and the ether is that of other peer when `i_peer` is not 0. In the latter case, the ether is read-only (only `Receive...` works) since it has been obtained from other peer via publish-subcribe pattern:\n\n    * `ReceiveInteger`\n    * `TransmitInteger`\n\n* Exchange data between integer register and integers array, and between advancing and non-advancing optuids arrays:\n\n    * `GetIntegerFromIntegers`\n    * `SetDataOptuidFromOptuid`\n    * `SetIntegersFromInteger`\n    * `SetOptuidFromDataOptuid`\n\n* Restart controller:\n\n    * `Restart`\n\n* Copy selected optuid to exec optuid (this command is unique in \"forcing\" the optuid of next execution node regardless of current node's main and alternative pointers) and vice versa. These two are NOPped by default:  \n\n    * `GetExecFromOptuid`\n    * `SetOptuidFromExec`\n\nNote that it is impossible to convert Optuid to Integer and vice versa, in accordance with \"opaque addressing\" principle.\n\nAlso, note redundancy. For example, `NextIntegerChannel` does almost what `IntegerChannelToInteger`, `Increment`, `IntegerToIntegerChannel` do.\n\n\u003c/details\u003e\n\n### Construction\n\nComes into play only when a controller constructs an executive (active) chain, — when `Construct` command is executed, which works with the stack of nodes' uids.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eAvailable construction instructions\u003c/b\u003e\u003c/summary\u003e\n\n* `AltNext` turns on \"alternative next\" mode until `NextToStored` instruction, which will then set the alternative next pointer of currently added node instead of the main one and revert to \"main mode\"\n* `Discard` removes topmost uid from the stack\n* `NextToStored` sets main or alternative next node pointer of the currently added node to the topmost uid of the stack\n* `Restore` changes \"construction pointer\" from currently added node to the topmost uid of the stack\n* `Store` pushes the uid of the currently added node to the stack\n* `Swap` swaps 2 topmost uids on the stack\n* `Terminus` interrupts the `Construct` (but not `Replicate`) command at currently added node\n\n\u003c/details\u003e\n\n---\n\nStill we lack any quantification or algebraisation of the intricate ways in which the choice of encoding by natural numbers affects the evolutionary perspectives of such system... For example, variants of `enum Command` are numbered in alphabetical order: `ReceiveOptuid` is `52`, `Remainder` is `53`, similarly, `AltNext` is `0` and `Terminus` is `6`; why not contrariwise? This is so arbitrary, so torn away from underlying levels, as if chemistry were decoupled from physics, that evolution may be too weak to fill the gap... with what? Even that is *innominabilis* today.\n\n**Remark.** There were an older version of Ælhometta without automatic conversion between `Content` and `Integer`, with 2 respective registers instead of 1 `Integer` now. That approach implied too much opacity of the numerical level as seen from the instruction level, and was abandoned. We leave its resurgence as \"an exercise to the reader\" (see also [Panmutations](#panmutations)).\n\n## A controller\n\nExecutive entity. CPU is another analogy.\n\nAgain, verbatim from the source:\n\n```rust\npub struct Controller {\n    chain_start_optuid: Optuid,\n\n    exec_optuid: Optuid,\n\n    data_optuids: Vec\u003cOptuid\u003e,\n    i_data_optuid: usize,\n\n    new_chain_optuid: Optuid,\n    new_controller: Option\u003cBox\u003cSelf\u003e\u003e,\n\n    registers: Registers,\n    flags: Flags,\n\n    optuids: Vec\u003cOptuid\u003e,\n    i_optuid: usize,\n\n    integers: Vec\u003cInteger\u003e,\n    i_integer: usize,\n\n    optuid_channels: Vec\u003cusize\u003e,\n    i_optuid_channel: usize,\n\n    i_peer: usize,\n\n    integer_channels: Vec\u003cusize\u003e,\n    i_integer_channel: usize,\n\n    generation: u128,\n    ticks: u128\n}\n```\n\nFor now, plural in `Registers` and `Flags` is redundant, because\n\n```rust\npub struct Registers {\n    integer: Integer\n}\n\npub struct Flags {\n    success: bool\n}\n```\n\n`exec_optuid` is basically the instruction pointer, `chain_start_optuid` keeps its initial value for the sake of `Restart` command. Controller \"dies\" as soon as `exec_optuid` becomes `None` or points to non-existing node.\n\n`new_chain_optuid` and `new_controller` are used for replication of a passive/descriptive chain and construction of an active/executive chain (one with a controller attached to it).\n\n`data_optuids[i_data_optuid]` advances automatically to the next node at read/write operations realised by `Read`, `Write`, and `Insert` commands, which use this optuid. `Construct` and `Replicate` commands advance it too, \"until the end\".\n\n`i_data_optuid`, `i_optuid`, `i_integer`, `i_optuid_channel`, and `i_integer_channel` are indices of currently selected elements of respective arrays: `data_optuids[]` etc.\n\n`i_peer`, when 0, means \"this one\", otherwise it means other peers, enumerated from 1. It affects interpretation of `integer_channels`, e.g. `Transmit` command works only for this peer.\n\n`generation` is set once at the creation of a controller to `generation` of the constructing controller + 1. `ticks` is 0 at controller's creation and increments at each its... tick.\n\n## Ancestors...\n\nThe simpler one, **ancestor B**, consists of \n\n* *Constructor's scheme chain*\n\n```\nConstruction(Store),\n\n// Replicate scheme\nCommand(SetDataOptuid),\nCommand(NextOptuid),\nCommand(NewChainInitPassive),\nCommand(PreviousOptuid),\nCommand(Skip),\nCommand(Replicate),\nCommand(NewChainDetach),\n\n// Build constructor from scheme\nCommand(SetDataOptuid),\nCommand(NextOptuid),\nCommand(NextOptuid),\nCommand(NewChainInitActive),\nCommand(Skip),\nCommand(Construct),\nCommand(PreviousOptuid),\nCommand(NewChainAddOptuid),\nCommand(NewChainDetach),\n\nConstruction(NextToStored),\nConstruction(Discard)\n```\n\n* *Constructor's executive chain*, which is almost the same as the scheme, except for the absence of Construction nodes and, \u003cu\u003eaccordingly to instructions from these nodes\u003c/u\u003e, the last node pointing to the implicit 1st `Space` node: this chain is a loop. (Well, not exactly: from 1st generation onward. In 0th generation, which is the ancestor itself, the loop is open.)\n\n* *Constructor's controller* attached to constructor's executive chain.\n\nNote the classical double interpretation of data: first is linear verbatim copying, second is non-linear construction that expands the meaning of special (`Construction:...`) units. Will an evolution keep the separation line between them clear?\n\n*Spacity* parameter that you provide at introducing this ancestor — as in `Æ anc b 5` — is the number of `Space`-s (5 in this case) inserted before every non-`Construction` node. They are *nothing* for mutations to replace with *something* without the need to destroy the original sequence of actions.\n\nThis ancestor utilises only a small fraction of available `Content`-s. There is also slightly more complicated, with larger assortment of `Content`-s, **ancestor A**: in addition to constructor, it has *jumbler* that scans the same scheme constructor uses and randomly changes it (by replacements, insertions, deletions). In other words, jumbler interiorises mutations. However, in Ælhometta, the standard way to introduce [Mutations](#mutations) is \"external\" and more global at that.\n\nSee also `src/aelhometta/ancestors.rs`.\n\n## ...and Descendants\n\nThe following chains have been extracted at random from an ælhometta with mutations and tiny input mapping from microphone, during 3 days of running. Maximum allowed number of nodes is 2\u003csup\u003e24\u003c/sup\u003e=16777216, same for controllers (although there never have been more than 3×10\u003csup\u003e5\u003c/sup\u003e of the latter).\n\n### After ~3×10\u003csup\u003e8\u003c/sup\u003e ticks\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEvolved chain, example 1\u003c/b\u003e\u003c/summary\u003e\n\n```\nSpace\nCommand:NextDataOptuid\nSpace\nSpace\nCommand:ZeroInteger\nSpace\nCommand:NewChainAddOptuidChannel\nSpace\nCommand:Abs\nCommand:Remove\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Write\nCommand:PreviousIntegerChannel\nCommand:NewChainAddOptuid\nCommand:NextPeer\nCommand:Construct\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nCommand:IntegerIndexToInteger\nCommand:SetIntegersFromInteger\nCommand:ZeroInteger\nSpace\nCommand:NextIntegerChannel\nCommand:OptuidChannelToInteger\nCommand:Construct\nSpace\nCommand:Read\nCommand:Negate\n×\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEvolved controller chain, example 1\u003c/b\u003e\u003c/summary\u003e\n\n```\nSpace\nSpace\nSpace\nSpace\nSpace\nCommand:BitNot\nSpace\nCommand:IntegerToOptuidChannel\nCommand:OptuidChannelToInteger\nCommand:SetOptuidFromExec\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Subtract\nCommand:GetIntegerFromIntegers\nCommand:NewChainAddOptuid\nCommand:NextPeer\nCommand:Construct\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nCommand:GetExecFromOptuid\nCommand:BitAnd\nCommand:ZeroInteger\nSpace\nCommand:GetExecFromOptuid\nCommand:Write\nCommand:PreviousDataOptuid\nSpace\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Write\nCommand:IntegerToIntegerIndex\nCommand:NewChainAddOptuid\nCommand:ShiftUp\nCommand:Construct\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nSpace\nCommand:SetIntegersFromInteger\nCommand:ZeroInteger\nSpace\nCommand:GetExecFromOptuid\nCommand:Increment\nCommand:PreviousOptuidChannel\nSpace\nCommand:GetIntegerFromIntegers\nCommand:NextIntegerChannel\nCommand:TestIntegerNegative\nCommand:NewChainInitActive\nCommand:TestIntegerNonZero\nCommand:BitOr\nCommand:NewChainAddOptuid\nCommand:GetExecFromOptuid\nCommand:NewChainAddOptuid\nCommand:SetIntegersFromInteger\nCommand:PreviousDataOptuid\nCommand:Restart\nCommand:RandomInteger\nCommand:NewChainAddOptuidChannel\nCommand:NewChainAddInteger\nCommand:BitNot\nCommand:IntegerToDataOptuidIndex\nCommand:RandomContent\nSpace\nCommand:IntegerToIntegerIndex\nCommand:Remainder\nCommand:Remove\nSpace\nCommand:TransmitOptuid\nCommand:OptuidIndexToInteger\nCommand:OptuidChannelToInteger\nCommand:PreviousOptuid\nCommand:Skip\nCommand:Replicate\nCommand:Divide\nSpace\n×\n```\n\u003c/details\u003e\n\n### After ~4×10\u003csup\u003e8\u003c/sup\u003e ticks\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEvolved chain, example 2\u003c/b\u003e\u003c/summary\u003e\n\n```\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:BitNot\nCommand:Skip\nCommand:NewChainAddOptuid\nCommand:NextPeer\nCommand:Construct\nCommand:NewChainDetach\nCommand:Write\nCommand:BitAnd\nCommand:Add\nSpace\nCommand:Write\nCommand:Read\nSpace\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Write\nCommand:Remainder\nCommand:NewChainAddOptuid\nCommand:Divide\nCommand:Construct\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nSpace\nCommand:Read\nCommand:NewChainDetach\nCommand:Read\nCommand:ZeroInteger\nCommand:Increment\nCommand:PreviousOptuidChannel\nSpace\nBranch\nCommand:RandomContent\nCommand:TestIntegerNegative\nCommand:Construct\nSpace\nCommand:BitOr\nCommand:TestIntegerNegative\nCommand:PreviousInteger\nCommand:Remove\nCommand:OptuidChannelToInteger\nCommand:PreviousDataOptuid\nCommand:NextOptuidChannel\nCommand:SetIntegersFromInteger\nCommand:NewChainAddOptuidChannel\nCommand:NewChainAddOptuidChannel\nCommand:NewChainInitPassive\nCommand:IntegerToDataOptuidIndex\nCommand:Write\nSpace\nCommand:IntegerToIntegerIndex\nCommand:Restart\nCommand:Remove\nSpace\nCommand:Decrement\nCommand:TransmitOptuid\nCommand:OptuidIndexToInteger\nCommand:TestIntegerPositive\nCommand:NextDataOptuid\nCommand:Abs\nCommand:Divide\nSpace\n×\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEvolved controller chain, example 2\u003c/b\u003e\u003c/summary\u003e\n\n```\nSpace\nCommand:OptuidIndexToInteger\nSpace\nCommand:NextInteger\nSpace\nSpace\nCommand:NewChainAddOptuid\nCommand:PreviousDataOptuid\nCommand:OptuidChannelToInteger\nCommand:IntegerToSuccess\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Write\nCommand:Replicate\nCommand:NewChainAddOptuid\nCommand:Construct\nCommand:NewChainDetach\nCommand:TestDataOptuid\nCommand:SetOptuidFromExec\nCommand:TestIntegerNegative\nCommand:IntegerToPeer\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nCommand:Increment\nCommand:PreviousDataOptuid\nCommand:SetDataOptuidFromOptuid\nCommand:TestIntegerNonZero\nCommand:Write\nCommand:GetIntegerFromIntegers\nCommand:NewChainAddOptuid\nCommand:Divide\nCommand:Construct\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nCommand:IntegerToDataOptuidIndex\nCommand:RandomContent\nSpace\nSpace\nCommand:SetOptuidFromExec\nCommand:Construct\nCommand:ShiftDown\nSpace\nCommand:NextIntegerChannel\nCommand:TestIntegerNonZero\nCommand:NewChainInitActive\nSpace\nCommand:BitOr\nCommand:Construct\nCommand:Decrement\nCommand:Remove\nCommand:SetIntegersFromInteger\n×\n```\n\u003c/details\u003e\n\n### After ~5×10\u003csup\u003e8\u003c/sup\u003e ticks\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEvolved chain, example 3\u003c/b\u003e\u003c/summary\u003e\n\n```\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nSpace\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:IntegerToIntegerIndex\nCommand:TestIntegerPositive\nCommand:NewChainAddOptuid\nCommand:Construct\nCommand:NewChainDetach\nCommand:PreviousInteger\nCommand:PreviousOptuid\nCommand:BitAnd\nCommand:TestDataOptuid\nCommand:GetExecFromOptuid\nCommand:Write\nCommand:Increment\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Subtract\nCommand:ReceiveInteger\nCommand:NewChainAddOptuid\nCommand:Divide\nCommand:PreviousInteger\nCommand:NewChainDetach\nSpace\nCommand:PreviousIntegerChannel\nCommand:ZeroInteger\nSpace\nCommand:GetExecFromOptuid\nCommand:NextPeer\nCommand:IntegerToOptuidIndex\nSpace\nCommand:NextOptuid\nCommand:Subtract\nCommand:Add\nCommand:NewChainInitActive\nCommand:Add\nCommand:BitOr\nCommand:PeerToInteger\nCommand:GetExecFromOptuid\nCommand:Remove\nCommand:NewChainInitActive\nCommand:NewChainAddOptuidChannel\nCommand:PreviousInteger\nCommand:BitXor\nCommand:SetIntegersFromInteger\nCommand:NewChainAddInteger\nCommand:DataOptuidIndexToInteger\nCommand:Subtract\nCommand:PreviousIntegerChannel\nSpace\nCommand:Write\nCommand:Remainder\nCommand:OptuidIndexToInteger\nSpace\n×\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEvolved controller chain, example 3\u003c/b\u003e\u003c/summary\u003e\n\n```\nSpace\nSpace\nSpace\nSpace\nCommand:Insert\nCommand:Write\nCommand:IntegerIndexToInteger\nCommand:OptuidChannelToInteger\nCommand:PeerToInteger\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:Write\nCommand:NewChainAddOptuid\nCommand:Multiply\nCommand:Construct\nCommand:NewChainDetach\nCommand:GetExecFromOptuid\nCommand:SetDataOptuidFromOptuid\nCommand:BitAnd\nCommand:ReceiveInteger\nCommand:Insert\nCommand:GetExecFromOptuid\nCommand:NewChainAddOptuid\nCommand:PreviousDataOptuid\nCommand:SetDataOptuidFromOptuid\nCommand:NewChainInitActive\nCommand:NextOptuid\nCommand:SetOptuidFromDataOptuid\nCommand:NewChainAddOptuid\nCommand:IntegerToPeer\nCommand:IntegerIndexToInteger\nCommand:BitOr\nCommand:Subtract\nCommand:PreviousPeer\nCommand:ZeroInteger\nCommand:PreviousOptuidChannel\nCommand:BitXor\nCommand:IntegerToIntegerChannel\nCommand:Restart\nSpace\nCommand:NextDataOptuid\nCommand:Multiply\nCommand:Increment\nCommand:SetIntegersFromInteger\nCommand:BitOr\nCommand:PeerToInteger\nCommand:GetExecFromOptuid\nCommand:Remove\nCommand:Write\nCommand:IntegerToDataOptuidIndex\nCommand:NewChainInitActive\nCommand:PreviousInteger\nCommand:BitXor\n×\n```\n\u003c/details\u003e\n\n**Remark.** It is quite possible for the first chain of a pair to belong to a controller as well, rather than to a scheme. To be sure, check for `Construction`-s: they can appear in a chain built by `Replicate`, and they cannot appear in a chain built by `Construct`.\n\n---\n\nEnjoy the mess and repetitiveness of evolution... Well, what evolutionary conclusions can we draw of this sample? At first, there seems to be a lot of junk, but is it really junk? can it be removed without significant changes in \"phenotype\"? or does it interact with parts not shown here in nontrivial ways? In particular, numerical operations (`Add`, `Divide`, `ShiftUp`) are interspersed everywhere.\n\n`Construct` and `Replicate` commands, with `NewChainInit...` and `NewChainDetach`, indicate the ability to procreate. Without states of controllers and chains their `Optuid`-s and `DataOptuid`-s point to, we cannot say how \"vital\" their children will be.\n\nLoops in original ancestors, and non-linearities of execution path in general, have mostly been lost along the evolution road, except for occasional `Branch` (chain 2).\n\n`Construction` instructions remain very rare.\n\nThere is some access to global arrays — `TransmitOptuid`, `ReceiveInteger` commands — but, again, without the rest it is hard to say whether this access is meaningful, at least are there `ReceiveOptuid`, `TransmitInteger` counterparts somewhere else.\n\nHow many eons away is this from the level of *E.coli*\u003csup\u003e[[GLA1]](#refGLA1)\u003c/sup\u003e?..\n\n## Mutations\n\nHere we call them *glitches*.\n\n* *Background* glitch occurs at each tick with specified probability and randomly changes the content of random node of entire ælhometta\n\n* *Replication* glitch occurs at replication for each replicated node with specified probability and changes its content randomly as well\n\n* *Construction* glitch occurs at construction for each read node with specified probability, changing its content randomly\n\nTo be more precise, \"randomly\" means equiprobably.\n\nBy default, all three probabilities are 0. We've shown how to adjust them in [Quickstart](#quickstart). To see their values and the counts of corresponding glitches that have occured is even simpler:\n\n```\nÆ glitch\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eExample of content statistics \u003ci\u003ewithout\u003c/i\u003e glitches (or jumblers)\u003c/b\u003e\u003c/summary\u003e\n\n```\nCommand:Remainder                                  0      0.000 %\nCommand:Remove                                     0      0.000 %\nCommand:Replicate                              38860      1.012 %\nCommand:Restart                                    0      0.000 %\nCommand:SetDataOptuid                          77720      2.023 %\nCommand:SetInteger                                 0      0.000 %\nCommand:SetOptuid                                  0      0.000 %\nCommand:ShiftUp                                    0      0.000 %\nCommand:ShiftDown                                  0      0.000 %\nCommand:Sign                                       0      0.000 %\nCommand:Skip                                   77720      2.023 %\nCommand:Square                                     0      0.000 %\nCommand:Subtract                                   0      0.000 %\nCommand:SuccessToInteger                           0      0.000 %\nCommand:TestDataOptuid                             0      0.000 %\nCommand:TestIntegerNegative                        0      0.000 %\nCommand:TestIntegerNonZero                         0      0.000 %\nCommand:TestIntegerPositive                        0      0.000 %\nCommand:TransmitInteger                            0      0.000 %\nCommand:TransmitOptuid                             0      0.000 %\nCommand:Write                                      0      0.000 %\nCommand:ZeroInteger                                0      0.000 %\nConstruction:AltNext                               0      0.000 %\nConstruction:Discard                           22393      0.583 %\nConstruction:NextToStored                      22393      0.583 %\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eExample of content statistics \u003ci\u003ewith\u003c/i\u003e glitches\u003c/b\u003e\u003c/summary\u003e\n\n```\nCommand:Remainder                                937      0.022 %\nCommand:Remove                                   274      0.007 %\nCommand:Replicate                              42305      1.009 %\nCommand:Restart                                  268      0.006 %\nCommand:SetDataOptuid                          84855      2.023 %\nCommand:SetInteger                              1065      0.025 %\nCommand:SetOptuid                                516      0.012 %\nCommand:ShiftUp                                  528      0.013 %\nCommand:ShiftDown                               1311      0.031 %\nCommand:Sign                                   42646      1.017 %\nCommand:Skip                                   43337      1.033 %\nCommand:Square                                   270      0.006 %\nCommand:Subtract                                1010      0.024 %\nCommand:SuccessToInteger                         558      0.013 %\nCommand:TestDataOptuid                           782      0.019 %\nCommand:TestIntegerNegative                      523      0.012 %\nCommand:TestIntegerNonZero                      1332      0.032 %\nCommand:TestIntegerPositive                      665      0.016 %\nCommand:TransmitInteger                         1202      0.029 %\nCommand:TransmitOptuid                          1798      0.043 %\nCommand:Write                                   1135      0.027 %\nCommand:ZeroInteger                             1315      0.031 %\nConstruction:AltNext                             258      0.006 %\nConstruction:Discard                             281      0.007 %\nConstruction:NextToStored                        225      0.005 %\n```\n\u003c/details\u003e\n\nSee also the comparison of [ancestors](#ancestors) and [descendants](#and-descendants) above.\n\n### Panmutations\n\nMutations are limited in that they cannot change the set of available commands, how commands work, general structure of ælhometta... all these things are \"above\" (\u003cu\u003eπανω\u003c/u\u003e απο) them. For now, the only potential source of such \u003cu\u003epan\u003c/u\u003emutations is... *you*, as a programmer, irritated by our design choices and anxious to rewrite some especially crappy parts of Ælhometta. *Welcome!* at least as long as **[Networking](#networking) and [I/O](#inputoutput) protocols remain compatible**, because then your ÆlhomettaPlus and all other versions panmutated differently by fellow rewriters will consolidate into an abiosphere.\n\nIn time, perhaps, ælhomettas will obtain means to panmutate themselves, e.g. rewriting and recompiling their source through specialised I/O... and, which is where the present overtakes, through tools such as [Copilot](https://en.wikipedia.org/wiki/GitHub_Copilot).\n\n### Mεταmutations\n\nOne well-known question troubling these waters is, \"What is it that mutates/evolves over time?\", the gimmick being the (lack of) boundaries between what does and what does not. On the one hand, ælhometta changes (including panmutations); on the other hand, you, an (external?) observer, change too, since it affects you, and the hardware on which it runs when you decide to upgrade to increase speed or throw away if it has not satisfied your expectations, and all other ælhomettas it interacts with, and their owners, and the global economy when many people spend electricity to run ælhomettas, and so forth... up to what, everything? but we ought to be careful with what we mean by such conclusion, otherwise it does not make much sense. Rather than interpretations, we are interested in what we can do on the levels accessible to us so that other levels of a heterarchy get... interesting.\n\n## Networking\n\nEach Ælhometta instance is a potential peer, identified from the outside by its *public key*, *onion address*, and *port*. To confirm the \"right\" to use the public key, the corresponding *secret key* must be specified.\n\nThe peers exchange data following the [publish-subscribe pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern): each ælhometta shares some continuous subset of its integer channels, from the beginning of their array (because channels with small indices seem to be used more often as evolution unfolds), and every other ælhometta that has subscribed to it receives this subset (if there is no whitelist filter at publisher side). We anticipate complaints against this pattern being too \"passive\": one ælhometta cannot say anything to another ælhometta until the latter one initiates listening.\n\nThe following structure (from `src/aelhometta.rs`) represents another peer from \"point of view\" of your peer:\n\n```rust\npub struct OtherPeer {\n    publickey: String,\n    onion: String,\n    port: u16,\n    ether_integers: Vec\u003cInteger\u003e,\n    limit: usize,\n    ut_last_update: i64,\n    updates_count: u128,\n    description: String\n}\n```\n\nInherently, there is no central server, rather every peer is a server for peers \"interested\" in the data it provides. Neither this is torrent-like, because a tracker is absent: you must know exactly the (public key, onion, port) identity of a peer to subscribe to it.\n\nThe underlying messaging library is [ZeroMQ](https://zeromq.org/), thus both [Curve](https://rfc.zeromq.org/spec/26/) keys, public and secret ones, are 40-character [Z85](https://rfc.zeromq.org/spec/32/) strings. Obtain them via a call to `zmq_curve_keypair()` from original [libzmq](https://github.com/zeromq/libzmq) or via its wrapper from numerous language bindings. [Quickstart](#quickstart) shows how to do it in Python.\n\nNetwork identities and data flow are provided by [onion services](https://community.torproject.org/onion-services/overview/) (v3) of [Tor](https://www.torproject.org/). `tor@default` service has to run on the system to keep your instance of Tor connected to the rest of Tor infrastructure.\n\nNote that public key of ZeroMQ is not related to public key of onion service. There is double encryption/authentication here, which is probably redundant...\n\n---\n\nAfter `Æ peer expose` your peer starts publishing data every `interval` microseconds, first `size` integers from your ælhometta's integers ether (0th, 1st, (`size` - 1)th).\n\nSubscription to other peer can be stopped at any time:\n\n```\nÆ peer disconnect TheirPublicKeyTheirPublicKeyTheirPublicK\n```\n\nAt that, indices of all subsequent peers decrement. If ælhometta has tuned to such indices (`i_peer` of its controllers), the tuning will probably be lost. It seems safer to add peers than to remove them.\n\nYou can stop the entire network activity, both transmitting and receiving, whenever you want:\n\n```\nÆ peer repose\n```\n\nLast data obtained from each other peer is kept, though, as long as you do not initiate a disconnection.\n\nThere is no requirement to transmit *and* receive, but the secret key has to be specified even if you need only to receive. As long as `interval` equals 0, there will be no transmission. On the other hand, if `interval` \u003e 0 and `size` = 0, your peer will transmit empty shares (usable as keepalives).\n\nYou can restrict peers that are able to subscribe to your peer by adding them to *whitelist* (if it is empty, all others are allowed):\n\n```\nÆ peer whitelist add TheirPublicKeyTheirPublicKeyTheirPublicK\n```\n\nIf circumstances change, any such key (and corresponding peer) can be deleted from whitelist via `Æ peer whitelist del ...`. Or restrictions can be removed altogether via `Æ peer whitelist clear`.\nPlain `Æ peer whitelist` shows all whitelisted public keys.\n\nWithout whitelist, anyone in the world who knows the public key, the onion address, and the port, is able to subscribe; there is no way to predict how many subscribers your ælhometta will have at certain time in the future, so the Internet traffic may vary.\n\n**Remark.** To imitate *effectively* empty whitelist (everyone is forbidden to subscribe), add to your whitelist a single, random public key that is not used anywhere else. Only this \"phantom\" peer will be able to subscribe, and good luck to any real peer trying to guess the corresponding secret key among approx. 2\u003csup\u003e256\u003c/sup\u003e possible ones...\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eKnown peers out there\u003c/b\u003e\u003c/summary\u003e\n\nPublic key | Onion | Port | Description | Share size\n-----------|-------|------|-------------|-----------\n`USBD7[O^8L[}saCh+6U#}6wie4oAedZ4#W4!b%LI` | `t3kauc3flp2bpv3mv7vtnedfu6zrho3undncccj35akpuyjqqydwvfyd` | `60847` | Maintained by us for testing. Online rather than offline | 1000–10000\n`\u0026i!VkHl[]m.c!^j0D%i)\u00264#[u5b(a=QCdZ9C0$p{` | `yhel64h6cjab75tcpncnla2rdhqmxut2vtitywhbu7bpjh4hfhp6hnid` | `60847` | Maintained by us for testing. Offline rather than online | 1000–10000\n\n\u003c/details\u003e\n\n---\n\nPlease be careful: you interact with *any* other peer at your own risk. One of security concerns is **size limit** — you probably do not want to spend traffic, depleting a tariff of your provider, to receive several gigabytes of someone's generously shared... zeros (`00 00 ... 00`) and then crash with \"Out of memory!\" To amend the latter problem, consider `Æ peer limit ...` for untrusted peers, which discards the rest of received data beyond specified size.\n\nAnother concern is how the data received from untrusted sources affects your ælhometta, what ideas it can develop... in whose interests it will operate...\n\n### Transferring network identity\n\nThat is, at moving your ælhometta to another computer.\n\nBeside `aelhometta.bin` (and `commander.json`), you need to keep the content of Tor hidden service dir, which itself is inside `/var/lib/tor/` on Linux. 3 essential files there are `hostname`, `hs_ed25519_public_key`, `hs_ed25519_secret_key`. This structure must be recreated on the next computer, along with `/etc/tor/torrc` or at least its `HiddenServicePort` and `HiddenServiceDir` settings.\n\nMake sure that the ælhometta has become online on the new place (others receive its shares *and* it receives others' shares), *then* remove it from the old one or do not expose it to the network from there, so that Tor will not be confused by two onions with the same identity.\n\n## Input/Output\n\nRanges of integer channels can be mapped *from* (input) or *to* (output) files with verbatim — little endian, 8-byte — representations of the integers. The programs working with such files can be completely independent of Ælhometta, except for some synchronisation of \"tempo\" (`interval`, in microseconds).\n\nOutput files are truncated and overwritten at each update.\n\nSize of an input file must be no less than 8 times the length of the range of integer channels to which it is mapped, otherwise updates do not happen.\n\n```rust\npub struct IntegersFileMapping {\n    start: usize,\n    length: usize,\n    interval: i64,\n    filepath: String,\n    ut_last_update: i64,\n    updates_count: u128\n}\n```\n\nAll output mappings are synchronised with corresponding files before all input mappings — with theirs\u003csup\u003e[[BUZ1]](#refBUZ1)\u003c/sup\u003e.\n\nWe have considered the usage of `iomap` command in [Quickstart](#quickstart). There, external programs to analyse (input, \"hearer\") and synthesise (output, \"buzzer\") sound were black boxes: from ælhometta's point of view, they only have to write and read, respectively, files whose sizes are 8 times the lengths of mapped ranges. Let us shed light into blackness... one of many possible ways to do it, e.g. in Python:\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eaelhom_hearer.py\u003c/b\u003e\u003c/summary\u003e\n\n```python\nimport numpy as np\nimport sounddevice as sd\n\nNUM_BANDS = 14\nMIN_FREQUENCY = 100\nMAX_FREQUENCY = 6000\nDESTINATION_FILEPATH = \"./hear.i64\"\nSAMPLE_RATE = 32768\nUPDATE_RATE = 2.0\n\nBASIC_FREQUENCIES = [int(MIN_FREQUENCY * np.power(2.0, i * np.log2(MAX_FREQUENCY / MIN_FREQUENCY) / (NUM_BANDS - 1))) for i in range(NUM_BANDS)] # in Hz\nNUM_REC_SAMPLES = int(SAMPLE_RATE / UPDATE_RATE)\n\nprint(\"Basic frequencies (Hz):\", BASIC_FREQUENCIES)\nprint(\"Press Ctrl+C to exit...\")\n\nsamples = np.zeros(SAMPLE_RATE)\n\nupdates = 0\n\ntry:\n\twhile True:\n\t\trecording = sd.rec(NUM_REC_SAMPLES, samplerate=SAMPLE_RATE, channels=1, dtype='int16', blocking=True).flatten()\n\n\t\tif NUM_REC_SAMPLES \u003c SAMPLE_RATE:\n\t\t\tsamples = np.concatenate((samples[NUM_REC_SAMPLES:], recording))\n\t\telse:\n\t\t\tsamples = recording[(NUM_REC_SAMPLES - SAMPLE_RATE):]\n\n\t\tspectrum = np.absolute(np.fft.rfft(samples)[1:])\n\t\tbegin = 0\n\t\tbandspectrum = np.zeros(NUM_BANDS)\n\t\tfor i in range(NUM_BANDS):\n\t\t\tend = BASIC_FREQUENCIES[i]\n\t\t\t# bandspectrum[i] = np.sum(spectrum[begin:end])\n\t\t\t# bandspectrum[i] = np.average(spectrum[begin:end])\n\t\t\tbandspectrum[i] = np.max(spectrum[begin:max(begin + 1, end)])\n\t\t\tbegin = end\n\n\t\tbandspectrum /= max(np.max(bandspectrum), 1e-8)\n\n\t\tupdates += 1\n\t\tstatus_str = f\"[{updates}] Bandspectrum: \"\n\n\t\tbs = bytes()\n\t\tfor i in range(NUM_BANDS):\n\t\t\ti64 = int(0xFF * bandspectrum[i]) # only lowest byte of 8\n\t\t\tbs += i64.to_bytes(8, byteorder=\"little\")\n\t\t\tstatus_str += f\"{i64:02X} \"\n\t\t\n\t\twith open(DESTINATION_FILEPATH, \"wb\") as f:\n\t\t\tf.write(bs)\n\n\t\tprint(status_str, end=\"\\r\", flush=True)\n\nexcept KeyboardInterrupt:\n\tprint(\"Done.\")\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eaelhom_buzzer.py\u003c/b\u003e\u003c/summary\u003e\n\n```python\nimport numpy as np\nimport pygame as pg\n\nimport time\n\nNUM_BANDS = 12\nMIN_FREQUENCY = 150\nMAX_FREQUENCY = 5000\nSOURCE_FILEPATH = \"./buzz.i64\"\nSAMPLE_RATE = 4\nUPDATE_RATE = 1.0\nIDLE_RATE = 100.0\n\nBASIC_FREQUENCIES = [int(MIN_FREQUENCY * np.power(2.0, i * np.log2(MAX_FREQUENCY / MIN_FREQUENCY) / (NUM_BANDS - 1))) for i in range(NUM_BANDS)] # in Hz\n\nprint(\"Basic frequencies (Hz):\", BASIC_FREQUENCIES)\n\npg.mixer.init(frequency=SAMPLE_RATE, channels=1)\npg.mixer.set_num_channels(NUM_BANDS)\n\npitches = [pg.sndarray.make_sound(np.array(32767.0 * np.sin(np.linspace(0.0, 2.0 * np.pi * f, SAMPLE_RATE) + np.random.random() * 2.0 * np.pi), dtype='int16')) for f in BASIC_FREQUENCIES] # clear tones\n\nvolumes = [0.0 for i in range(NUM_BANDS)]\n\nfor p in pitches:\n\tp.set_volume(0.0)\n\tp.play(-1)\n\nt_last_update = - 1.0 / UPDATE_RATE - 1.0 # ensure immediate update\nprint(\"Press Ctrl+C to exit...\")\n\nupdates = 0\n\ntry:\n\twhile True:\n\t\tt = time.time()\n\t\tif t - t_last_update \u003e= 1.0 / UPDATE_RATE:\n\t\t\tupdates += 1\n\n\t\t\tstatus_str = f\"[{updates}] Volumes: \"\n\n\t\t\ttry:\n\t\t\t\twith open(SOURCE_FILEPATH, \"rb\") as f:\n\t\t\t\t\tfcontent = f.read(NUM_BANDS \u003c\u003c 3) # 64-bit integers\n\t\t\t\t\tif len(fcontent) == NUM_BANDS \u003c\u003c 3:\n\t\t\t\t\t\tfor i in range(NUM_BANDS):\n\t\t\t\t\t\t\ti64 = int.from_bytes(fcontent[(i \u003c\u003c 3):((i + 1) \u003c\u003c 3)], byteorder=\"little\", signed=True)\n\t\t\t\t\t\t\tvol = abs(i64) \u0026 0xFF # only lowest byte matters\n\t\t\t\t\t\t\tvolumes[i] = vol / 0xFF\n\t\t\t\t\t\t\tstatus_str += f\"{vol:02X} \"\n\n\t\t\t\tfor i in range(NUM_BANDS):\n\t\t\t\t\tpitches[i].set_volume(volumes[i])\n\n\t\t\texcept FileNotFoundError:\n\t\t\t\tstatus_str += \"source file not found\"\n\n\t\t\tt_last_update = t\n\n\t\t\tprint(status_str, end=\"\\r\", flush=True)\n\t\t\n\t\ttime.sleep(1.0 / IDLE_RATE)\n\nexcept KeyboardInterrupt:\n\tprint(\"Done.\")\n\npg.mixer.stop()\n```\n\u003c/details\u003e\n\nBefore using them, — `$ python3 aelhom_hearer.py` and `$ python3 aelhom_buzzer.py`, — you need to install Python packages they rely on:\n\n```shell\n$ pip3 install -U numpy pygame sounddevice\n```\n\n---\n\n**Remark 1.** If there are severe restrictions on noise level in the environment at hand (e.g. constant buzz drives you crazy), you can virtualise the buzzer by mixing its output directly with the samples that the hearer analyses, instead of producing actual sounds via speakers:\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eaelhom_hearer_buzzer.py\u003c/b\u003e\u003c/summary\u003e\n\n```python\nimport numpy as np\nimport sounddevice as sd\n\nHEAR_NUM_BANDS = 14\nHEAR_MIN_FREQUENCY = 100\nHEAR_MAX_FREQUENCY = 6000\n\nBUZZ_NUM_BANDS = 12\nBUZZ_MIN_FREQUENCY = 150\nBUZZ_MAX_FREQUENCY = 5000\n\nBUZZ_VOLUME = 1.0 / BUZZ_NUM_BANDS\n\nHEAR_FILEPATH = \"./hear.i64\"\nBUZZ_FILEPATH = \"./buzz.i64\"\n\nSAMPLE_RATE = 32768\nUPDATE_RATE = 2.0\n\nHEAR_BASIC_FREQUENCIES = [int(HEAR_MIN_FREQUENCY * np.power(2.0, i * np.log2(HEAR_MAX_FREQUENCY / HEAR_MIN_FREQUENCY) / (HEAR_NUM_BANDS - 1))) for i in range(HEAR_NUM_BANDS)] # in Hz\nBUZZ_BASIC_FREQUENCIES = [int(BUZZ_MIN_FREQUENCY * np.power(2.0, i * np.log2(BUZZ_MAX_FREQUENCY / BUZZ_MIN_FREQUENCY) / (BUZZ_NUM_BANDS - 1))) for i in range(BUZZ_NUM_BANDS)] # in Hz\n\nNUM_REC_SAMPLES = int(SAMPLE_RATE / UPDATE_RATE)\n\nprint(\"Buzz basic frequencies (Hz):\", BUZZ_BASIC_FREQUENCIES)\nprint(\"Hear basic frequencies (Hz):\", HEAR_BASIC_FREQUENCIES)\n\nsamples = np.zeros(SAMPLE_RATE)\n\npitches = [np.array(32767.0 * np.sin(np.linspace(0.0, 2.0 * np.pi * f, SAMPLE_RATE) + np.random.random() * 2.0 * np.pi), dtype='float64') for f in BUZZ_BASIC_FREQUENCIES] # clear tones\nvolumes = [0.0 for i in range(BUZZ_NUM_BANDS)]\n\nupdates = 0\n\nprint(\"Press Ctrl+C to exit...\")\n\ntry:\n\twhile True:\n\t\trecording = sd.rec(NUM_REC_SAMPLES, samplerate=SAMPLE_RATE, channels=1, dtype='int16', blocking=True).flatten()\n\n\t\tif NUM_REC_SAMPLES \u003c SAMPLE_RATE:\n\t\t\tsamples = np.concatenate((samples[NUM_REC_SAMPLES:], recording))\n\t\telse:\n\t\t\tsamples = recording[(NUM_REC_SAMPLES - SAMPLE_RATE):]\n\n\t\tstatus_str = f\"[{updates}] Volumes:\"\n\n\t\ttry:\n\t\t\twith open(BUZZ_FILEPATH, \"rb\") as fh:\n\t\t\t\tfcontent = fh.read(BUZZ_NUM_BANDS \u003c\u003c 3) # 64-bit integers\n\t\t\t\tif len(fcontent) == BUZZ_NUM_BANDS \u003c\u003c 3:\n\t\t\t\t\tfor i in range(BUZZ_NUM_BANDS):\n\t\t\t\t\t\ti64 = int.from_bytes(fcontent[(i \u003c\u003c 3):((i + 1) \u003c\u003c 3)], byteorder=\"little\", signed=True)\n\t\t\t\t\t\tvol = abs(i64) \u0026 0xFF # only lowest byte matters\n\t\t\t\t\t\tvolumes[i] = vol / 0xFF\n\t\t\t\t\t\tstatus_str += f\" {vol:02X}\"\n\t\texcept FileNotFoundError:\n\t\t\tstatus_str += \" buzz file not found\"\n\n\t\tsamples_with_buzz = samples + BUZZ_VOLUME * sum([volumes[fr] * pitches[fr] for fr in range(BUZZ_NUM_BANDS)])\n\n\t\tspectrum = np.absolute(np.fft.rfft(samples_with_buzz)[1:])\n\t\tbegin = 0\n\t\tbandspectrum = np.zeros(HEAR_NUM_BANDS)\n\t\tfor i in range(HEAR_NUM_BANDS):\n\t\t\tend = HEAR_BASIC_FREQUENCIES[i]\n\t\t\t# bandspectrum[i] = np.sum(spectrum[begin:end])\n\t\t\t# bandspectrum[i] = np.average(spectrum[begin:end])\n\t\t\tbandspectrum[i] = np.max(spectrum[begin:max(begin + 1, end)])\n\t\t\tbegin = end\n\n\t\tbandspectrum /= max(np.max(bandspectrum), 1e-8)\n\n\t\tupdates += 1\n\t\tstatus_str += f\" █ Bandspectrum:\"\n\n\t\tbs = bytes()\n\t\tfor i in range(HEAR_NUM_BANDS):\n\t\t\ti64 = int(0xFF * bandspectrum[i]) # only lowest byte of 8\n\t\t\tbs += i64.to_bytes(8, byteorder=\"little\")\n\t\t\tstatus_str += f\" {i64:02X}\"\n\t\t\n\t\twith open(HEAR_FILEPATH, \"wb\") as f:\n\t\t\tf.write(bs)\n\n\t\tprint(status_str, end=\"\\r\", flush=True)\n\nexcept KeyboardInterrupt:\n\tprint(\"Done.\")\n```\n\u003c/details\u003e\n\nBe aware that such tricks break feedback loops, and sooner or later Ælhometta has to be actually heard for its own good.\n\n---\n\n**Remark 2.** With some redirection, the hearer is able to analyse e.g. demodulated radio signals. (We assume Linux here.) Plug in a receiver like [RTL-SDR](https://www.rtl-sdr.com/), run [GQRX](https://www.gqrx.dk/), tune to a radio station or just any interesting frequency, adjust proper demodulation mode, and turn UDP on (port 7355 by default). Then run the following bash script (`socat` ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faelhometta%2Faelhometta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faelhometta%2Faelhometta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faelhometta%2Faelhometta/lists"}