From db20ace6435eb9aa3aba524381f12c8d1aff4979 Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Sun, 31 May 2026 16:23:13 +0800 Subject: [PATCH 1/2] emscripten: Docker-based one-stop web build and polished demo Rework the emscripten build into a reproducible flow inside a pinned container: etc/emscripten/build-in-docker.sh builds the image, runs the wasm build, and assembles a self-contained web-example/ that can be copied to any static host. Replaces the previous mix of shell, Ruby and Node helpers. The toolchain is pinned to emsdk 3.1.23 because both halves of the REPL are sensitive to the exact version: GASMAN's conservative GC, and xterm-pty's emscriptenHack() patching emscripten's TTY device so tcsetattr() reaches the line discipline. 3.1.23 is the version that works with the pinned xterm-pty 0.9.4; a newer emsdk leaves tcsetattr unhonoured and double- echoes typed input. See the Dockerfile for the full rationale. Build robustness fixes, independent of the toolchain version: - configure zlib with --static (newer wasm-ld rejects its shared .so test targets; GAP only needs libz.a); - remove the generated src/c_*.c and ffdata.* before the native build so reruns regenerate them instead of failing; - assemble-website.sh copies the data tree resiliently (some packages ship dangling .dSYM symlinks that aborted the copy and left lib/, grp/ uncopied, causing startup 404s), drops pkg/log/ test logs, ships gap.worker.js only if the build produced one, and asserts lib/init.g landed in the output. Also fix the outdated documentation links in the demo page and refresh startup_manifest.json. AI assistance: Claude Code (Opus 4.8) was used to make these changes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 11 + etc/emscripten/Dockerfile | 50 + etc/emscripten/README.md | 127 +- etc/emscripten/assemble-website.sh | 64 + etc/emscripten/build-in-docker.sh | 80 ++ etc/emscripten/build.sh | 152 ++- etc/emscripten/build_startup_manifest.js | 71 - etc/emscripten/generate_gap_fs_json.py | 25 +- etc/emscripten/run-web-demo.sh | 13 - etc/emscripten/serve.py | 35 + etc/emscripten/server.rb | 15 - etc/emscripten/startup_manifest.json | 1521 ++++++++++++++++++++++ etc/emscripten/web-template/gap-fs.js | 51 +- etc/emscripten/web-template/index.html | 181 ++- 14 files changed, 2189 insertions(+), 207 deletions(-) create mode 100644 etc/emscripten/Dockerfile create mode 100755 etc/emscripten/assemble-website.sh create mode 100755 etc/emscripten/build-in-docker.sh delete mode 100755 etc/emscripten/build_startup_manifest.js delete mode 100755 etc/emscripten/run-web-demo.sh create mode 100755 etc/emscripten/serve.py delete mode 100755 etc/emscripten/server.rb create mode 100644 etc/emscripten/startup_manifest.json diff --git a/.gitignore b/.gitignore index 5d67442b54..ca50cf4952 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,17 @@ /libgap*.dll* /libgap*.so* +# emscripten / wasm build outputs (etc/emscripten/build.sh and friends) +/native-build/ +/extern/emscripten/ +/web-example/ +/packages.tar.gz +/gap.html +/gap.js +/gap.wasm +/gap.worker.js +/gap-fs.json + /bin/gap*.sh /bin/*-*/ # Compiling the `xgap` package creates the file `xgap.sh` diff --git a/etc/emscripten/Dockerfile b/etc/emscripten/Dockerfile new file mode 100644 index 0000000000..9025dbaaa3 --- /dev/null +++ b/etc/emscripten/Dockerfile @@ -0,0 +1,50 @@ +# Build environment for compiling GAP to WebAssembly via Emscripten. +# +# Pinned to emsdk 3.1.23 for reproducibility. Both pieces of the in-browser +# REPL are sensitive to the exact toolchain version: +# +# - GASMAN, GAP's conservative garbage collector, scans the stack including +# pointers held in wasm registers, reached via emscripten_scan_registers() +# (see src/gasman.c). That path is now compiled correctly regardless of +# version, so the GC itself is no longer the constraint. +# +# - The terminal uses xterm-pty, whose emscriptenHack() monkey-patches +# emscripten's internal TTY device so GAP's tcsetattr() (turning off echo +# and canonical mode) reaches the line discipline. That patch is tied to +# emscripten's TTY internals: on 3.1.47 the ioctl no longer reaches +# xterm-pty, echo stays on, and every typed line is echoed twice. +# +# 3.1.23 is the version where the pinned xterm-pty (0.9.4) works. Bump both +# together and re-test the REPL -- including that typed input is not +# double-echoed -- before changing this. + +FROM emscripten/emsdk:3.1.23 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + autoconf \ + automake \ + libtool \ + make \ + python3 \ + ca-certificates \ + curl \ + bison \ + byacc \ + m4 \ + && rm -rf /var/lib/apt/lists/* + +# Allow running as a non-root host UID without breaking the emscripten cache. +RUN mkdir -p /emsdk/upstream/emscripten/cache \ + && chmod -R 0777 /emsdk/upstream/emscripten/cache + +# Cache the GAP package distribution tarball so container runs don't +# re-download it from GitHub each time. The URL pins to the "latest" +# release on the PackageDistro side, so this snapshot drifts as upstream +# tags new releases — rebuild the image (--no-cache) to refresh. +ARG GAP_PACKAGES_URL=https://github.com/gap-system/PackageDistro/releases/download/latest/packages.tar.gz +RUN curl --fail --location --silent --show-error \ + --output /opt/gap-packages.tar.gz \ + "$GAP_PACKAGES_URL" \ + && chmod 0644 /opt/gap-packages.tar.gz + +WORKDIR /gap diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index 5946302efe..083de668b6 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -1,26 +1,127 @@ -Code to allow building gap to WASM using Emscripten. +# GAP in the browser -Files: +Build GAP as a WebAssembly module and serve it as a self-contained website. +The terminal interface uses [xterm-pty](https://github.com/mame/xterm-pty), +so the resulting page behaves like a normal GAP REPL. -- `build.sh`: Run as `etc/emscripten/build.sh` from a fresh copy of GAP. +## Quick start -- `web-template`: Uses 'xterm-pty' to create a "nice" interface to the Wasm GAP. +From a fresh GAP checkout, with either Docker or Podman installed: -- `build_startup_manifest.js`: Run it in the web root directory to build `startup_manifest.json` that contains resources to preload. +```sh +etc/emscripten/build-in-docker.sh +cd web-example +../etc/emscripten/serve.py +``` + +Then open . The first build takes 10–30 minutes; the +docker image, the GAP package distribution, and the GMP/zlib builds are all +cached for subsequent runs. + +To pick up newer GAP packages from upstream, force a fresh image build: + +```sh +docker build --no-cache -t gap-emscripten-build:3.1.23 etc/emscripten/ +``` + +On Apple Silicon (and other non-amd64 hosts), the build runs `linux/amd64` +under emulation, since `emscripten/emsdk:3.1.23` is amd64-only on Docker +Hub. `build-in-docker.sh` pins the platform explicitly so the layer cache +holds across runs; set `BUILD_PLATFORM` to override. + +The output directory `web-example/` is fully self-contained — copy it to any +static host (see "Hosting" below for the headers it needs). + +## Building without Docker + +If you already have emsdk 3.1.23 sourced in your shell, you can run the +underlying build directly: + +```sh +etc/emscripten/build.sh +etc/emscripten/assemble-website.sh +``` + +emsdk 3.1.23 is the version we test against, paired with xterm-pty 0.9.4. +GAP relies on ASYNCIFY together with GASMAN's conservative GC, which scans +wasm registers via `emscripten_scan_registers()` (see `src/gasman.c`); and +the terminal relies on xterm-pty's `emscriptenHack()` patching emscripten's +TTY device so `tcsetattr()` reaches the line discipline. Both are sensitive +to the toolchain version (a newer emsdk leaves `tcsetattr` unhonoured, so +typed input is echoed twice), so re-test the REPL when changing emsdk. -See 'run-web-demo.sh' as an example on how to set up a working website. +## Hosting -Note that this demo uses xterm-pty, a library which provides a terminal interface -for emscripten-compiled programs. This uses a javascript feature called -"SharedArrayBuffer", which requires some headers are returned by the server: +The xterm-pty terminal uses `SharedArrayBuffer`, which browsers only allow +when the page is served with these two headers: ``` Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp ``` -For more details, see for [this article](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer). +`serve.py` is a 20-line stdlib-only Python server that adds them. For +GitHub Pages and other static hosts that don't let you set headers, +`web-template/coi-serviceworker.js` is included as a workaround (it +re-fetches resources through a service worker that adds the headers). + +## Files + +| File | Role | +| ---- | ---- | +| `build-in-docker.sh` | One-stop entry point. Builds the image, runs `build.sh` inside, then `assemble-website.sh`. | +| `Dockerfile` | Pinned `emscripten/emsdk:3.1.23` with autotools, python3, bison/byacc/m4, and a baked-in copy of the GAP package distribution tarball at `/opt/gap-packages.tar.gz`. | +| `build.sh` | Configures and builds GMP, zlib, and GAP itself for wasm. | +| `assemble-website.sh` | Copies the build outputs and data directories (`pkg`, `lib`, `grp`, …) into `web-example/`. | +| `generate_gap_fs_json.py` | Reads file paths on stdin, writes `gap-fs.json` (the manifest of every file in the virtual FS). | +| `startup_manifest.json` | List of files to fetch eagerly at startup, captured from a real GAP run. Anything not in this list is fetched lazily on first read. See "Updating the startup manifest" below for how to refresh it. | +| `serve.py` | Local server that adds the COOP/COEP headers. | +| `web-template/` | Static UI: `index.html`, the worker scripts, the FS init shim, and the COOP/COEP service worker for hosts where you can't set headers. | + +## Updating the startup manifest + +`startup_manifest.json` lists files (relative to the GAP root) that the FS +init shim downloads up front instead of lazily. The current list was +captured from a real GAP run reaching its prompt, so it includes both +the core library bootstrap (`lib/init.g`, `lib/read*.g`, …) and any +default-loaded packages. Entries that no longer exist in the build are +silently ignored, so it is safe to leave stale entries in place; it is +also safe to leave the list empty (every file becomes lazy). + +The manifest is a startup-time optimisation, not a correctness mechanism: +a wrong list never breaks the build, it only makes startup slower (files +GAP needs but the manifest omits get fetched lazily, one round-trip each) +or wastes bandwidth (files in the manifest that GAP doesn't actually +read are downloaded anyway). So it's worth refreshing when something +changes the set of files read at startup — most importantly when the +default loaded packages change, but also after large library reshuffles. + +To regenerate it after such changes: + +1. Build the website (`build-in-docker.sh`) and serve it (`serve.py`). +2. **Empty the served manifest before capturing.** Replace + `web-example/startup_manifest.json` with `[]` (or delete it). + Otherwise the existing entries are eagerly pre-fetched at startup, + appear in `fetchedUrls`, and you'll just round-trip the old list. + Editing the served file is enough — no rebuild is needed. +3. Open the page and wait for the GAP prompt to appear. Every file that + GAP actually reads now goes through the lazy `XHR` path and gets + captured. +4. Open devtools and read the captured URLs from the page's JS console: + `window.fetchedUrls` is an array of every unique URL the worker + requested. Chrome/Firefox provide a `copy()` console helper: + `copy(JSON.stringify(fetchedUrls))` puts the JSON on your clipboard. +5. Strip non-GAP-FS entries (`gap.js`, `gap.wasm`, `gap-fs.json`, the + xterm CDN URLs) and write the result to + `etc/emscripten/startup_manifest.json` (so it's checked in and gets + picked up by the next `assemble-website.sh`). A `jq` filter that + keeps just GAP filesystem paths: + + ```sh + jq '[.[] | select(test("^(pkg|lib|grp|tst|doc|hpcgap|dev|benchmark)/"))]' \ + fetched-urls.json > etc/emscripten/startup_manifest.json + ``` -The file "coi-serviceworker.js" works around this problem on Github pages. This won't -work locally, so "server.rb" is a simple ruby script, which just starts a web-server -which returns the required headers. \ No newline at end of file +The bookkeeping lives in `web-template/gap-fs.js` (wraps `fetch` and +`XMLHttpRequest.open` to report URLs to the main thread) and +`web-template/index.html` (accumulates them onto `window.fetchedUrls`). diff --git a/etc/emscripten/assemble-website.sh b/etc/emscripten/assemble-website.sh new file mode 100755 index 0000000000..12e6f6a83b --- /dev/null +++ b/etc/emscripten/assemble-website.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# +# Assemble a self-contained website from a completed wasm build. +# Outputs ./web-example/ relative to the GAP source root. +# +# Run after etc/emscripten/build.sh (or have build-in-docker.sh call it). + +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +ROOT_DIR=$(cd "$SCRIPT_DIR/../.." && pwd) +OUT_DIR="$ROOT_DIR/web-example" + +cd "$ROOT_DIR" + +for f in gap.js gap.wasm gap-fs.json; do + if [[ ! -f $f ]]; then + echo "Error: missing build output '$f'. Run etc/emscripten/build.sh first." >&2 + exit 1 + fi +done + +# Always start from a clean output directory. Merging into a previous +# web-example/ confuses cp when a tree has changed shape between runs +# (e.g. pkg/X switching between a symlink and a real directory). +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" + +cp "$SCRIPT_DIR"/web-template/* "$OUT_DIR"/ +cp "$SCRIPT_DIR"/startup_manifest.json "$OUT_DIR"/ +cp gap.js gap.wasm gap-fs.json "$OUT_DIR"/ +# Emscripten only emits a separate gap.worker.js for pthread builds; this +# single-threaded ASYNCIFY build doesn't use one (newer emscripten inlines +# the worker regardless). Copy it only if it was produced. +if [[ -f gap.worker.js ]]; then + cp gap.worker.js "$OUT_DIR"/ +fi +cp LICENSE COPYRIGHT "$OUT_DIR"/ + +# Data directories. These are referenced by gap-fs.json and either eagerly +# loaded (if listed in startup_manifest.json) or lazily fetched on first +# read by Emscripten's createLazyFile. +# +# -L dereferences symlinks so the output tree is self-contained (a setup +# where pkg/X is a symlink into a separate checkout still works). Some +# packages ship dangling symlinks as build artefacts (e.g. pkg/vole's +# rust/target/*.dSYM); cp prints those and exits non-zero but still copies +# everything else, so we don't let that abort the run. The assertion below +# catches a genuinely incomplete copy. +for d in pkg lib grp tst doc hpcgap dev benchmark; do + cp -RL "$d" "$OUT_DIR"/ 2>/dev/null || true +done + +# pkg/log holds package test logs (.log/.err/.out) that are never read at +# runtime; keep them out of the shipped site. +rm -rf "$OUT_DIR/pkg/log" + +# The library bootstrap must be present, or GAP 404s during startup. +if [[ ! -f "$OUT_DIR/lib/init.g" ]]; then + echo "Error: lib/init.g missing from $OUT_DIR after copy." >&2 + exit 1 +fi + +echo "Assembled website at $OUT_DIR" diff --git a/etc/emscripten/build-in-docker.sh b/etc/emscripten/build-in-docker.sh new file mode 100755 index 0000000000..ac7a7aa604 --- /dev/null +++ b/etc/emscripten/build-in-docker.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# +# One-stop shop: build GAP for the web inside a pinned container. +# +# Usage (run from the GAP source tree): +# etc/emscripten/build-in-docker.sh +# +# Output: ./web-example/ with a self-contained website. Copy it anywhere +# and serve with COOP/COEP headers (etc/emscripten/serve.py is one option). + +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +ROOT_DIR=$(cd "$SCRIPT_DIR/../.." && pwd) + +RUNTIME="${CONTAINER_RUNTIME:-}" +if [[ -z "$RUNTIME" ]]; then + if command -v podman >/dev/null 2>&1; then + RUNTIME=podman + elif command -v docker >/dev/null 2>&1; then + RUNTIME=docker + else + echo "Error: neither podman nor docker found in PATH." >&2 + echo "Install one, or set CONTAINER_RUNTIME explicitly." >&2 + exit 1 + fi +fi + +IMAGE_TAG="gap-emscripten-build:3.1.23" + +# Pin the platform. emscripten/emsdk:3.1.23 is amd64-only on Docker Hub, so on +# Apple Silicon (or any non-amd64 host) the runtime would otherwise renegotiate +# the platform on every build -- that mismatch invalidates the FROM layer's +# cache and cascades through the whole image, defeating the layer cache even +# with --layers. Override with BUILD_PLATFORM if needed. +PLATFORM="${BUILD_PLATFORM:-linux/amd64}" + +echo ">> Using container runtime: $RUNTIME (platform: $PLATFORM)" +echo ">> Building image $IMAGE_TAG (cached after first run)" + +# --layers is the podman/buildah flag for "use the layer cache"; older +# podman versions default it to false. Docker has caching on by default +# and rejects the flag, so only pass it for podman. +declare -a BUILD_ARGS=(--platform "$PLATFORM") +if [[ "$RUNTIME" != "docker" ]]; then + BUILD_ARGS+=(--layers) +fi +"$RUNTIME" build "${BUILD_ARGS[@]}" -t "$IMAGE_TAG" -f "$SCRIPT_DIR/Dockerfile" "$SCRIPT_DIR" + +# Run as the host user where possible so build outputs are not root-owned. +declare -a USER_ARGS=() +if [[ "$RUNTIME" == "docker" ]]; then + USER_ARGS=(--user "$(id -u):$(id -g)" -e HOME=/tmp) +else + # Rootless podman maps host UID to container root by default. + USER_ARGS=(--userns=keep-id) +fi + +echo ">> Building GAP inside container" +"$RUNTIME" run --platform "$PLATFORM" --rm \ + -v "$ROOT_DIR:/gap" \ + -w /gap \ + "${USER_ARGS[@]}" \ + "$IMAGE_TAG" \ + bash etc/emscripten/build.sh + +echo ">> Assembling website" +bash "$SCRIPT_DIR/assemble-website.sh" + +cat </dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) -if ! command -v emmake &> /dev/null; then - echo Please install, and source, emscripten - echo This script was tested with version 3.1.23 - echo See https://emscripten.org/docs/getting_started/downloads.html for install instructions +if ! command -v emmake >/dev/null 2>&1; then + echo "Please install and source emscripten." >&2 + echo "This script is tested with emsdk 3.1.23." >&2 + echo "See https://emscripten.org/docs/getting_started/downloads.html" >&2 exit 1 -fi; +fi # Build the configure script if this is a fresh git checkout if [[ ! -f ./configure ]]; then ./autogen.sh fi -# First build a standard GAP install, for some files -# we will need during building +# First build a standard GAP install: we need ffgen and gap-nocomp on the +# host to generate sources that the wasm build cannot run itself. +# +# We copy those generated sources (build/c_*.c, build/ffdata.*) into src/ +# further down, so the wasm build picks them up as overrides. GAP's +# Makefile.rules, however, also treats src/c_oper1.c, src/ffdata.c etc. as +# overrides during THIS native build -- so leftovers from a previous run +# would stop the native build regenerating them in native-build/build/, and +# the copy below would then fail. Remove any leftovers so the native build +# regenerates them cleanly (keeps the script idempotent across re-runs). +rm -f src/c_oper1.c src/c_type1.c src/ffdata.c src/ffdata.h ( mkdir -p native-build cd native-build if [[ ! -f config.status ]]; then ../configure fi - make -j8 + make -j"$JOBS" ) AUX_BUILD=$PWD/extern/emscripten/build AUX_PREFIX=$PWD/extern/emscripten/install -mkdir -p "$AUX_BUILD" -mkdir -p "$AUX_PREFIX" +mkdir -p "$AUX_BUILD" "$AUX_PREFIX" +# A 32-bit build is required by GAP's small-integer representation, so we +# pin --build to i686-pc-linux-gnu. This may need revisiting if GAP ever +# moves to a 64-bit-friendly small-integer encoding. ( mkdir -p "$AUX_BUILD/gmp" - cd "$AUX_BUILD/gmp" && + cd "$AUX_BUILD/gmp" if [[ ! -f config.status ]]; then CC_FOR_BUILD=/usr/bin/gcc ABI=standard \ - emconfigure $BASEDIR/extern/gmp/configure \ - --build i686-pc-linux-gnu --host none \ - --disable-assembly --enable-cxx \ - --prefix=$AUX_PREFIX - fi && - emmake make -j8 && + emconfigure "$BASEDIR/extern/gmp/configure" \ + --build i686-pc-linux-gnu --host none \ + --disable-assembly --enable-cxx \ + --prefix="$AUX_PREFIX" + fi + emmake make -j"$JOBS" emmake make install ) ( mkdir -p "$AUX_BUILD/zlib" - cd "$AUX_BUILD/zlib" && + cd "$AUX_BUILD/zlib" if [[ ! -f Makefile ]]; then - emconfigure $BASEDIR/extern/zlib/configure --prefix=$AUX_PREFIX - fi; - emmake make -j8 && + # --static: skip the shared library. Newer emscripten's wasm-ld + # rejects linking zlib's .so test programs (examplesh) with + # "unknown file type: libz.so"; GAP only needs the static libz.a. + emconfigure "$BASEDIR/extern/zlib/configure" --static --prefix="$AUX_PREFIX" + fi + emmake make -j"$JOBS" emmake make install ) -# There are two problems with building GAP -# 1) GAP builds some executables (ffgen and gap-nocomp), which it wants to -# execute while building. We get these files from 'native-build'. -# 2) 'configure' gets confused by some of the LDFLAGS we need, so we have to pass -# them in to 'make' +# Two quirks of building GAP under emscripten: +# 1) GAP runs ffgen and gap-nocomp during the build. We copy the host-built +# versions in from native-build/ further down. +# 2) configure rejects some LDFLAGS we need at link time, so we pass them +# only at make-time. # -# These options are: -# -sASYNCIFY -- we don't care about ASYNC, but this forces the compiler to output -# all variables onto the stack, which is required for GASMAN -# Note we could use 'ALLOW_MEMORY_GROWTH', both we don't currently, we instead set -# a big memory window. -# -O2 : Some optimisation -# EXEEXT=.html -- this is actually a GAP makefile option, it lets us make the -# output 'gap.html', which makes emscripten output a html page we can load -# --pre-js lazy_fs.js : Prepend lazy_fs.js that is generated for lazy loading - -# Run configure if we don't have a makefile, or someone configured this -# GAP for standard building (emscripten builds will use 'emcc') -if [[ ! -f GNUmakefile ]] || ! grep '/emcc' GNUmakefile > /dev/null; then +# Link-time flags worth noting: +# -sASYNCIFY forces variables onto the stack (required by GASMAN). +# -O2 enables some optimisation. +# EXEEXT=.html a GAP makefile knob that produces gap.html, the html +# shim emscripten generates for loading the wasm module. + +if [[ ! -f GNUmakefile ]] || ! grep -q '/emcc' GNUmakefile; then + # Wipe any in-tree state from a prior native (or mismatched) build. + # Stale build/deps/*.d files reference build/ffdata.h, which under + # emcc would be regenerated by a non-executable JS shim; stale .o + # files have the wrong architecture. Configure regenerates build/. + rm -rf build ffgen emconfigure ./configure ABI=32 \ - --with-gmp=$AUX_PREFIX \ - --with-zlib=$AUX_PREFIX \ - LDFLAGS="-s ASYNCIFY=1 -O2" -fi; + --with-gmp="$AUX_PREFIX" \ + --with-zlib="$AUX_PREFIX" \ + LDFLAGS="-s ASYNCIFY=1 -O2" +fi -# Get full required packages -emmake make bootstrap-pkg-full +# Provide the GAP package distribution without re-downloading it on every +# build. Preference order: +# 1. An existing pkg/ directory. +# 2. packages.tar.gz already on the host (carried in the source mount). +# 3. The tarball baked into the docker image at /opt/gap-packages.tar.gz. +# 4. As a last resort, GAP's own bootstrap-pkg-full target downloads it. +# Skipping straight to tar avoids `bootstrap-pkg-full`, which calls +# curl -L -O unconditionally and overwrites packages.tar.gz on every run. +if [[ ! -d pkg ]]; then + if [[ ! -f packages.tar.gz && -f /opt/gap-packages.tar.gz ]]; then + cp /opt/gap-packages.tar.gz packages.tar.gz + fi + if [[ -f packages.tar.gz ]]; then + mkdir pkg + (cd pkg && tar xzf ../packages.tar.gz) + else + emmake make bootstrap-pkg-full + fi +fi -# Copy in files from native_build +# Copy host-built generated sources into place cp native-build/build/c_*.c native-build/build/ffdata.* src/ -# Dynamically find and append ALL required files to the JS array -# The flag -type f is safe because the only symbolic link is 'tst/mockpkg/Makefile.gappkg', -# which is safe to ignore -find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/generate_gap_fs_json.py - -if [ $? -ne 0 ]; then - echo "Build aborted: generate_gap_fs_json.py failed." - exit 1 -fi +# Build the file list that will be served. -L follows symlinks so that +# users' local development setups (e.g. replacing pkg/foo with a symlink +# to a git checkout under git/foo) are picked up; -type f then drops any +# symlinks themselves. +find -L pkg lib grp tst doc hpcgap dev benchmark -type f ! -path 'pkg/log/*' \ + | python3 etc/emscripten/generate_gap_fs_json.py -# The EXEEXT is usually for windows, but here it lets us set GAP's extension, -# which lets us produce a html page to run GAP in. -emmake make -j8 LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" +emmake make -j"$JOBS" \ + LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" \ + EXEEXT=".html" diff --git a/etc/emscripten/build_startup_manifest.js b/etc/emscripten/build_startup_manifest.js deleted file mode 100755 index edb8594b10..0000000000 --- a/etc/emscripten/build_startup_manifest.js +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env node -"use strict"; - -const http = require('http'); -const fs = require('fs'); -const path = require('path'); - -const PORT = 9999; -const BASE_DIR = process.cwd(); -const LOG_FILE = path.join(BASE_DIR, 'startup_manifest.json'); - -const requestedFiles = new Set(); -fs.writeFileSync(LOG_FILE, '[\n]'); - -const server = http.createServer((req, res) => { - let urlPath = req.url.split('?')[0]; - if (urlPath === '/') { - urlPath = '/index.html'; - } - - let localDiskPath = urlPath; - try { - localDiskPath = decodeURIComponent(urlPath); - } catch (e) {} - - const filePath = path.join(BASE_DIR, localDiskPath); - - fs.readFile(filePath, (err, data) => { - if (err) { - console.error(`[404] Ignored missing file: ${localDiskPath}`); - res.writeHead(404); - res.end(`404: File not found`); - return; - } - - const ignored = ['/favicon.ico', '/index.html', '/startup_manifest.json', 'coi-serviceworker.js', 'gap-worker.js', 'gap-fs.js', 'gap.js', 'gap.wasm', 'gap-fs.json']; - if (!ignored.includes(localDiskPath)) { - let manifestPath = localDiskPath.startsWith('/') ? localDiskPath.substring(1) : localDiskPath; - - if (!requestedFiles.has(manifestPath)) { - requestedFiles.add(manifestPath); - - const manifest = Array.from(requestedFiles); - fs.writeFileSync(LOG_FILE, JSON.stringify(manifest, null, 4)); - - console.log(`[Loaded & Logged] ${manifestPath} (Total: ${requestedFiles.size})`); - } - } - - let contentType = 'application/octet-stream'; - if (urlPath.endsWith('.html')) contentType = 'text/html'; - else if (urlPath.endsWith('.js')) contentType = 'text/javascript'; - else if (urlPath.endsWith('.wasm')) contentType = 'application/wasm'; - else if (urlPath.endsWith('.css')) contentType = 'text/css'; - - res.writeHead(200, { - 'Content-Type': contentType, - 'Cross-Origin-Opener-Policy': 'same-origin', - 'Cross-Origin-Embedder-Policy': 'require-corp', - 'Access-Control-Allow-Origin': '*' - }); - - res.end(data); - }); -}); - -server.listen(PORT, '0.0.0.0', () => { - console.log(`\n Tracker running at http://localhost:${PORT}/`); - console.log(`Serving files from: ${BASE_DIR}`); - console.log(`Logging valid loaded files to: ${LOG_FILE}\n`); -}); diff --git a/etc/emscripten/generate_gap_fs_json.py b/etc/emscripten/generate_gap_fs_json.py index dbf5447bba..917f0a2a38 100755 --- a/etc/emscripten/generate_gap_fs_json.py +++ b/etc/emscripten/generate_gap_fs_json.py @@ -1,18 +1,11 @@ -import sys -import json -import os - -def main(): - paths = [line.strip() for line in sys.stdin if line.strip()] +#!/usr/bin/env python3 +"""Read a list of file paths from stdin (one per line) and write them as a +JSON array to gap-fs.json in the current directory.""" - try: - with open('gap-fs.json', 'w', encoding='utf-8') as f: - json.dump(paths, f, separators=(',', ':')) - - print(f"Successfully wrote {len(paths)} files to gap-fs.json", file=sys.stderr) - except Exception as e: - print(f"Failed to write gap-fs.json: {e}", file=sys.stderr) - sys.exit(1) +import json +import sys -if __name__ == "__main__": - main() +paths = [line.strip() for line in sys.stdin if line.strip()] +with open("gap-fs.json", "w", encoding="utf-8") as f: + json.dump(paths, f, separators=(",", ":")) +print(f"wrote {len(paths)} files to gap-fs.json", file=sys.stderr) diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh deleted file mode 100755 index a82eb948a9..0000000000 --- a/etc/emscripten/run-web-demo.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -eux - -echo This script assumes you have already run 'build.sh' - -mkdir -p web-example -cp etc/emscripten/web-template/* web-example/ -cp gap.js gap.wasm gap.worker.js gap-fs.json web-example/ - -cp -r pkg lib grp tst doc hpcgap dev benchmark web-example/ -cd web-example -../etc/emscripten/server.rb diff --git a/etc/emscripten/serve.py b/etc/emscripten/serve.py new file mode 100755 index 0000000000..7d089f0c54 --- /dev/null +++ b/etc/emscripten/serve.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +"""Serve the current directory with the COOP/COEP headers required by +xterm-pty's SharedArrayBuffer usage. Run from the assembled web-example/ +(or any directory containing the gap.* artifacts). + + ./serve.py # listens on 8080 + ./serve.py 9000 # listens on 9000 +""" + +from __future__ import annotations + +import http.server +import socketserver +import sys + + +class CrossOriginIsolatedHandler(http.server.SimpleHTTPRequestHandler): + def end_headers(self): + self.send_header("Cross-Origin-Opener-Policy", "same-origin") + self.send_header("Cross-Origin-Embedder-Policy", "require-corp") + super().end_headers() + + +def main() -> None: + port = int(sys.argv[1]) if len(sys.argv) > 1 else 8080 + with socketserver.TCPServer(("", port), CrossOriginIsolatedHandler) as httpd: + print(f"Serving on http://localhost:{port}/ (Ctrl-C to stop)") + try: + httpd.serve_forever() + except KeyboardInterrupt: + print() + + +if __name__ == "__main__": + main() diff --git a/etc/emscripten/server.rb b/etc/emscripten/server.rb deleted file mode 100755 index 642c9ad167..0000000000 --- a/etc/emscripten/server.rb +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env ruby -# Taken from https://github.com/mame/xterm-pty/ - -require "webrick" - -class Server < WEBrick::HTTPServer - def service(req, res) - super - res["Cross-Origin-Opener-Policy"] = "same-origin" - res["Cross-Origin-Embedder-Policy"] = "require-corp" - end -end - -Server.new(Port: 8080, DocumentRoot: ".").start - diff --git a/etc/emscripten/startup_manifest.json b/etc/emscripten/startup_manifest.json new file mode 100644 index 0000000000..3ab701c269 --- /dev/null +++ b/etc/emscripten/startup_manifest.json @@ -0,0 +1,1521 @@ +[ + "lib/init.g", + "lib/kernel.g", + "lib/global.g", + "lib/system.g", + "lib/read1.g", + "lib/hpc/thread1.g", + "lib/filter.g", + "lib/oper.g", + "lib/oper1.g", + "lib/type.g", + "lib/type1.g", + "lib/methsel.g", + "lib/methsel2.g", + "lib/function.g", + "lib/cache.gd", + "lib/object.gd", + "lib/variable.g", + "lib/package.gd", + "lib/coll.gd", + "lib/list.gd", + "lib/wpobj.gd", + "lib/arith.gd", + "lib/ffe.gd", + "lib/domain.gd", + "lib/string.g", + "lib/cyclotom.g", + "lib/set.gd", + "lib/record.gd", + "lib/random.gd", + "lib/cache.gi", + "lib/coll.gi", + "lib/flag.g", + "lib/boolean.g", + "lib/ffe.g", + "lib/arith.gi", + "lib/list.g", + "lib/wpobj.g", + "lib/permutat.g", + "lib/trans.g", + "lib/pperm.g", + "lib/filter.gi", + "lib/object.gi", + "lib/listcoef.gd", + "lib/info.gd", + "lib/files.gd", + "lib/streams.gd", + "lib/record.gi", + "lib/matobj1.gd", + "lib/vecmat.gd", + "lib/vec8bit.gd", + "lib/mat8bit.gd", + "lib/global.gd", + "lib/info.gi", + "lib/global.gi", + "lib/options.gd", + "lib/options.gi", + "lib/attr.gd", + "lib/attr.gi", + "lib/string.gd", + "lib/userpref.g", + "lib/cmdledit.g", + "lib/cmdleditx.g", + "lib/objset.g", + "lib/float.gd", + "lib/macfloat.g", + "lib/hpc/tasks.g", + "lib/error.g", + "lib/session.g", + "lib/read2.g", + "lib/process.gd", + "lib/files.gi", + "lib/streams.gi", + "lib/process.gi", + "lib/read3.g", + "lib/type.gd", + "lib/tuples.gd", + "lib/rvecempt.gd", + "lib/extaset.gd", + "lib/extlset.gd", + "lib/extrset.gd", + "lib/extuset.gd", + "lib/dict.gd", + "lib/bitfields.gd", + "lib/mapping.gd", + "lib/mapphomo.gd", + "lib/relation.gd", + "lib/magma.gd", + "lib/mgmideal.gd", + "lib/mgmhom.gd", + "lib/mgmadj.gd", + "lib/mgmcong.gd", + "lib/semicong.gd", + "lib/semigrp.gd", + "lib/smgideal.gd", + "lib/monoid.gd", + "lib/grp.gd", + "lib/invsgp.gd", + "lib/addmagma.gd", + "lib/addcoset.gd", + "lib/semiring.gd", + "lib/ring.gd", + "lib/matrix.gd", + "lib/matint.gd", + "lib/matblock.gd", + "lib/ideal.gd", + "lib/module.gd", + "lib/basis.gd", + "lib/basismut.gd", + "lib/vspc.gd", + "lib/vspchom.gd", + "lib/zlattice.gd", + "lib/algebra.gd", + "lib/mgmring.gd", + "lib/algfp.gd", + "lib/alglie.gd", + "lib/algsc.gd", + "lib/alghom.gd", + "lib/liefam.gd", + "lib/algrep.gd", + "lib/lierep.gd", + "lib/integer.gd", + "lib/gaussian.gd", + "lib/numtheor.gd", + "lib/dlog.gd", + "lib/primality.gd", + "lib/contfrac.gd", + "lib/ringsc.gd", + "lib/ringhom.gd", + "lib/combinat.gd", + "lib/ratfun.gd", + "lib/fampred.g", + "lib/list.gi", + "lib/set.gi", + "lib/wpobj.gi", + "lib/random.gi", + "lib/field.gd", + "lib/zmodnz.gd", + "lib/zmodnze.gd", + "lib/cyclotom.gd", + "lib/fldabnum.gd", + "lib/padics.gd", + "lib/ringpoly.gd", + "lib/upoly.gd", + "lib/polyfinf.gd", + "lib/polyrat.gd", + "lib/polyconw.gd", + "lib/algfld.gd", + "lib/meataxe.gd", + "lib/unknown.gd", + "lib/word.gd", + "lib/wordass.gd", + "lib/matobj2.gd", + "lib/matobjplist.gd", + "lib/matobjnz.gd", + "lib/rws.gd", + "lib/rwspcclt.gd", + "lib/rwsgrp.gd", + "lib/rwspcgrp.gd", + "lib/groebner.gd", + "lib/pcgs.gd", + "lib/pcgsind.gd", + "lib/pcgspcg.gd", + "lib/pcgsmodu.gd", + "lib/pcgsperm.gd", + "lib/pcgsspec.gd", + "lib/grppc.gd", + "lib/grppcnrm.gd", + "lib/grptbl.gd", + "lib/grpperm.gd", + "lib/grpprmcs.gd", + "lib/stbcbckt.gd", + "lib/ghom.gd", + "lib/ghompcgs.gd", + "lib/gprd.gd", + "lib/ghomperm.gd", + "lib/gpprmsya.gd", + "lib/addgphom.gd", + "lib/grpnames.g", + "lib/grpnames.gd", + "lib/quotsys.gd", + "lib/pquot.gd", + "lib/oprt.gd", + "lib/partitio.gd", + "lib/stbc.gd", + "lib/clas.gd", + "lib/clashom.gd", + "lib/permdeco.gd", + "lib/csetgrp.gd", + "lib/factgrp.gd", + "lib/grpreps.gd", + "lib/grppcrep.gd", + "lib/onecohom.gd", + "lib/grppccom.gd", + "lib/twocohom.gd", + "lib/grppcext.gd", + "lib/grppcfp.gd", + "lib/randiso.gd", + "lib/schur.gd", + "lib/schursym.gd", + "lib/grplatt.gd", + "lib/oprtglat.gd", + "lib/grppclat.gd", + "lib/grppcaut.gd", + "lib/straight.gd", + "lib/memory.gd", + "lib/grpfp.gd", + "lib/grpfree.gd", + "lib/sgpres.gd", + "lib/tietze.gd", + "lib/ghomfp.gd", + "lib/dt.g", + "lib/integer.gi", + "lib/grpnice.gd", + "lib/morpheus.gd", + "lib/grpmat.gd", + "lib/fitfree.gd", + "lib/grpffmat.gd", + "lib/grpramat.gd", + "grp/basic.gd", + "grp/classic.gd", + "grp/conformal.gd", + "grp/perf.gd", + "grp/suzuki.gd", + "grp/ree.gd", + "grp/simple.gd", + "grp/imf.gd", + "grp/glzmodmz.gd", + "grp/clasmax.grp", + "lib/orders.gd", + "lib/trans.gd", + "lib/pperm.gd", + "lib/fastendo.gd", + "lib/fpsemi.gd", + "lib/fpmon.gd", + "lib/rwssmg.gd", + "lib/kbsemi.gd", + "lib/tcsemi.gd", + "lib/adjoin.gd", + "lib/semirel.gd", + "lib/semitran.gd", + "lib/reesmat.gd", + "lib/semiquo.gd", + "lib/semipperm.gd", + "lib/pager.gd", + "lib/helpbase.gd", + "lib/helpview.gd", + "lib/helpt2t.gd", + "lib/helpdef.gd", + "lib/ctbl.gd", + "lib/ctblfuns.gd", + "lib/ctblmaps.gd", + "lib/ctblauto.gd", + "lib/ctbllatt.gd", + "lib/ctblsymm.gd", + "lib/ctblsolv.gd", + "lib/ctblpope.gd", + "lib/ctblmoli.gd", + "lib/ctblmono.gd", + "lib/ctblgrp.gd", + "lib/tom.gd", + "lib/proto.gd", + "lib/gasman.gd", + "lib/memusage.gd", + "lib/read4.g", + "lib/profile.g", + "lib/newprofile.g", + "lib/methwhy.g", + "lib/pager.gi", + "lib/helpbase.gi", + "lib/helpview.gi", + "lib/helpt2t.gi", + "lib/helpdef.gi", + "lib/reread.g", + "lib/package.gi", + "lib/string.gi", + "lib/test.gd", + "lib/test.gi", + "lib/galois.gd", + "lib/galois.gi", + "lib/transatl.g", + "lib/obsolete.g", + "lib/obsolete.gd", + "lib/read.g", + "lib/read5.g", + "lib/type.gi", + "lib/rvecempt.gi", + "lib/ratfun1.gi", + "lib/matrix.gi", + "lib/matint.gi", + "lib/matblock.gi", + "lib/tuples.gi", + "lib/domain.gi", + "lib/mapping1.gi", + "lib/mapping.gi", + "lib/mapprep.gi", + "lib/mapphomo.gi", + "lib/relation.gi", + "lib/magma.gi", + "lib/mgmideal.gi", + "lib/mgmhom.gi", + "lib/mgmadj.gi", + "lib/mgmcong.gi", + "lib/semigrp.gi", + "lib/semicong.gi", + "lib/smgideal.gi", + "lib/monoid.gi", + "lib/grp.gi", + "lib/invsgp.gi", + "lib/addmagma.gi", + "lib/addcoset.gi", + "lib/ring.gi", + "lib/ideal.gi", + "lib/module.gi", + "lib/modfree.gi", + "lib/modulrow.gi", + "lib/modulmat.gi", + "lib/basis.gi", + "lib/basismut.gi", + "lib/vspc.gi", + "lib/vspcrow.gi", + "lib/vspcmat.gi", + "lib/vspchom.gi", + "lib/zlattice.gi", + "lib/mgmring.gi", + "lib/algebra.gi", + "lib/idealalg.gi", + "lib/alghom.gi", + "lib/algfp.gi", + "lib/alglie.gi", + "lib/algliess.gi", + "lib/algsc.gi", + "lib/algmat.gi", + "lib/liefam.gi", + "lib/algrep.gi", + "lib/lierep.gi", + "lib/numtheor.gi", + "lib/dlog.gi", + "lib/primality.gi", + "lib/contfrac.gi", + "lib/ringsc.gi", + "lib/ringhom.gi", + "lib/combinat.gi", + "lib/ratfun.gi", + "lib/ratfunul.gi", + "lib/ringpoly.gi", + "lib/upoly.gi", + "lib/upolyirr.gi", + "lib/polyfinf.gi", + "lib/polyrat.gi", + "lib/polyconw.gi", + "lib/listcoef.gi", + "lib/algfld.gi", + "lib/groebner.gi", + "lib/unknown.gi", + "lib/field.gi", + "lib/fieldfin.gi", + "lib/zmodnz.gi", + "lib/zmodnze.gi", + "lib/ffe.gi", + "lib/ffeconway.gi", + "lib/rational.gi", + "lib/gaussian.gi", + "lib/cyclotom.gi", + "lib/fldabnum.gi", + "lib/padics.gi", + "lib/matobj.gi", + "lib/matobjrowlist.gi", + "lib/vecmat.gi", + "lib/vec8bit.gi", + "lib/mat8bit.gi", + "lib/matobjplist.gi", + "lib/matobjnz.gi", + "lib/meataxe.gi", + "lib/meatauto.gi", + "lib/word.gi", + "lib/wordass.gi", + "lib/wordrep.gi", + "lib/wordlett.gi", + "lib/mgmfree.gi", + "lib/smgrpfre.gi", + "lib/monofree.gi", + "lib/grpfree.gi", + "lib/rws.gi", + "lib/rwspcclt.gi", + "lib/rwspcsng.gi", + "lib/rwspccoc.gi", + "lib/rwsgrp.gi", + "lib/rwspcgrp.gi", + "lib/rwsdt.gi", + "lib/nilpquot.gi", + "lib/pquot.gi", + "lib/pcgs.gi", + "lib/pcgsind.gi", + "lib/pcgsmodu.gi", + "lib/pcgspcg.gi", + "lib/pcgscomp.gi", + "lib/pcgsperm.gi", + "lib/pcgsnice.gi", + "lib/pcgsspec.gi", + "lib/grppc.gi", + "lib/grppcint.gi", + "lib/grppcprp.gi", + "lib/grppcatr.gi", + "lib/grppcnrm.gi", + "lib/bitfields.gi", + "lib/dict.gi", + "lib/dicthf.gi", + "lib/grptbl.gi", + "lib/ghom.gi", + "lib/ghompcgs.gi", + "lib/gprd.gi", + "lib/ghomperm.gi", + "lib/grpperm.gi", + "lib/gpprmsya.gi", + "lib/gprdperm.gi", + "lib/gprdpc.gi", + "lib/gprdmat.gi", + "lib/oprt.gi", + "lib/oprtperm.gi", + "lib/oprtpcgs.gi", + "lib/partitio.gi", + "lib/stbc.gi", + "lib/stbcbckt.gi", + "lib/stbcrand.gi", + "lib/clas.gi", + "lib/claspcgs.gi", + "lib/csetgrp.gi", + "lib/csetperm.gi", + "lib/csetpc.gi", + "lib/factgrp.gi", + "lib/grpreps.gi", + "lib/grppcrep.gi", + "lib/grpprmcs.gi", + "lib/grpnames.gi", + "lib/onecohom.gi", + "lib/grppccom.gi", + "lib/grpcompl.gi", + "lib/twocohom.gi", + "lib/grppcext.gi", + "lib/randiso.gi", + "lib/randiso2.gi", + "lib/grppcfp.gi", + "lib/schur.gi", + "lib/schursym.gi", + "lib/grpnice.gi", + "lib/fitfree.gi", + "lib/permdeco.gi", + "lib/clashom.gi", + "lib/clasperm.gi", + "lib/maxsub.gi", + "lib/norad.gi", + "lib/autsr.gi", + "lib/morpheus.gi", + "lib/grplatt.gi", + "lib/oprtglat.gi", + "lib/grppclat.gi", + "lib/grppcaut.gi", + "lib/grpmat.gi", + "lib/grpffmat.gi", + "lib/grpramat.gi", + "lib/grpfp.gi", + "lib/gpfpiso.gi", + "lib/sgpres.gi", + "lib/tietze.gi", + "lib/ghomfp.gi", + "lib/addgphom.gi", + "lib/trans.gi", + "lib/pperm.gi", + "lib/fastendo.gi", + "lib/fpsemi.gi", + "lib/fpmon.gi", + "lib/rwssmg.gi", + "lib/kbsemi.gi", + "lib/tcsemi.gi", + "lib/adjoin.gi", + "lib/semirel.gi", + "lib/semitran.gi", + "lib/reesmat.gi", + "lib/semiquo.gi", + "lib/semipperm.gi", + "lib/proto.gi", + "lib/orders.gi", + "lib/gasman.gi", + "lib/memusage.gi", + "lib/function.gi", + "lib/float.gi", + "lib/ieee754.g", + "lib/read6.g", + "grp/basicpcg.gi", + "grp/basicprm.gi", + "grp/basicmat.gi", + "grp/basicfp.gi", + "grp/perf.grp", + "grp/classic.gi", + "grp/conformal.gi", + "grp/suzuki.gi", + "grp/ree.gi", + "grp/simple.gi", + "grp/imf.grp", + "grp/imf.gi", + "grp/glzmodmz.gi", + "lib/read7.g", + "lib/ctbl.gi", + "lib/ctblfuns.gi", + "lib/ctblmaps.gi", + "lib/ctblauto.gi", + "lib/ctbllatt.gi", + "lib/ctblsymm.gi", + "lib/ctblsolv.gi", + "lib/ctblpope.gi", + "lib/ctblmoli.gi", + "lib/ctblmono.gi", + "lib/ctblgrp.gi", + "lib/ctblperm.gi", + "lib/ctblpc.gi", + "lib/tom.gi", + "lib/straight.gi", + "lib/memory.gi", + "lib/read8.g", + "lib/overload.g", + "lib/syntaxtree.gd", + "lib/syntaxtree.gi", + "lib/teaching.g", + "lib/teachm2.g", + "lib/operdebug.g", + "lib/colorprompt.g", + "pkg/4ti2interface/PackageInfo.g", + "pkg/ace/PackageInfo.g", + "pkg/aclib/PackageInfo.g", + "pkg/agt/PackageInfo.g", + "pkg/alco/PackageInfo.g", + "pkg/alnuth/PackageInfo.g", + "pkg/anupq/PackageInfo.g", + "pkg/atlasrep/PackageInfo.g", + "pkg/autodoc/PackageInfo.g", + "pkg/automata/PackageInfo.g", + "pkg/automgrp/PackageInfo.g", + "pkg/autpgrp/PackageInfo.g", + "pkg/browse/PackageInfo.g", + "pkg/cap/PackageInfo.g", + "pkg/caratinterface/PackageInfo.g", + "pkg/cddinterface/PackageInfo.g", + "pkg/circle/PackageInfo.g", + "pkg/classicalmaximals/PackageInfo.g", + "pkg/classicpres/PackageInfo.g", + "pkg/cohomolo/PackageInfo.g", + "pkg/congruence/PackageInfo.g", + "pkg/corefreesub/PackageInfo.g", + "pkg/corelg/PackageInfo.g", + "pkg/crime/PackageInfo.g", + "pkg/crisp/PackageInfo.g", + "pkg/crypting/PackageInfo.g", + "pkg/cryst/PackageInfo.g", + "pkg/crystcat/PackageInfo.g", + "pkg/ctbllib/PackageInfo.g", + "pkg/cubefree/PackageInfo.g", + "pkg/curlinterface/PackageInfo.g", + "pkg/cvec/PackageInfo.g", + "pkg/datastructures/PackageInfo.g", + "pkg/deepthought/PackageInfo.g", + "pkg/design/PackageInfo.g", + "pkg/difsets/PackageInfo.g", + "pkg/digraphs/PackageInfo.g", + "pkg/edim/PackageInfo.g", + "pkg/example/PackageInfo.g", + "pkg/examplesforhomalg/PackageInfo.g", + "pkg/factint/PackageInfo.g", + "pkg/ferret/PackageInfo.g", + "pkg/fga/PackageInfo.g", + "pkg/fining/PackageInfo.g", + "pkg/float/PackageInfo.g", + "pkg/format/PackageInfo.g", + "pkg/forms/PackageInfo.g", + "pkg/fplsa/PackageInfo.g", + "pkg/fr/PackageInfo.g", + "pkg/francy/PackageInfo.g", + "pkg/fwtree/PackageInfo.g", + "pkg/gapdoc/PackageInfo.g", + "pkg/gauss/PackageInfo.g", + "pkg/gaussforhomalg/PackageInfo.g", + "pkg/gbnp/PackageInfo.g", + "pkg/generalizedmorphismsforcap/PackageInfo.g", + "pkg/genss/PackageInfo.g", + "pkg/gradedmodules/PackageInfo.g", + "pkg/gradedringforhomalg/PackageInfo.g", + "pkg/grape/PackageInfo.g", + "pkg/groupoids/PackageInfo.g", + "pkg/grpconst/PackageInfo.g", + "pkg/guarana/PackageInfo.g", + "pkg/guava/PackageInfo.g", + "pkg/hap/PackageInfo.g", + "pkg/hapcryst/PackageInfo.g", + "pkg/hecke/PackageInfo.g", + "pkg/help/PackageInfo.g", + "pkg/homalg/PackageInfo.g", + "pkg/homalgtocas/PackageInfo.g", + "pkg/ibnp/PackageInfo.g", + "pkg/idrel/PackageInfo.g", + "pkg/images/PackageInfo.g", + "pkg/inducereduce/PackageInfo.g", + "pkg/intpic/PackageInfo.g", + "pkg/io/PackageInfo.g", + "pkg/io_forhomalg/PackageInfo.g", + "pkg/irredsol/PackageInfo.g", + "pkg/itc/PackageInfo.g", + "pkg/json/PackageInfo.g", + "pkg/jupyterkernel/PackageInfo.g", + "pkg/jupyterviz/PackageInfo.g", + "pkg/kan/PackageInfo.g", + "pkg/kbmag/PackageInfo.g", + "pkg/laguna/PackageInfo.g", + "pkg/liealgdb/PackageInfo.g", + "pkg/liepring/PackageInfo.g", + "pkg/liering/PackageInfo.g", + "pkg/linearalgebraforcap/PackageInfo.g", + "pkg/lins/PackageInfo.g", + "pkg/localizeringforhomalg/PackageInfo.g", + "pkg/localnr/PackageInfo.g", + "pkg/loops/PackageInfo.g", + "pkg/lpres/PackageInfo.g", + "pkg/majoranaalgebras/PackageInfo.g", + "pkg/mapclass/PackageInfo.g", + "pkg/matgrp/PackageInfo.g", + "pkg/matricesforhomalg/PackageInfo.g", + "pkg/modisom/PackageInfo.g", + "pkg/modulargroup/PackageInfo.g", + "pkg/modulepresentationsforcap/PackageInfo.g", + "pkg/modules/PackageInfo.g", + "pkg/monoidalcategories/PackageInfo.g", + "pkg/nconvex/PackageInfo.g", + "pkg/nilmat/PackageInfo.g", + "pkg/nock/PackageInfo.g", + "pkg/nofoma/PackageInfo.g", + "pkg/normalizinterface/PackageInfo.g", + "pkg/nq/PackageInfo.g", + "pkg/numericalsgps/PackageInfo.g", + "pkg/openmath/PackageInfo.g", + "pkg/orb/PackageInfo.g", + "pkg/origami/PackageInfo.g", + "pkg/packagemaker/PackageInfo.g", + "pkg/packagemanager/PackageInfo.g", + "pkg/patternclass/PackageInfo.g", + "pkg/permut/PackageInfo.g", + "pkg/polenta/PackageInfo.g", + "pkg/polycyclic/PackageInfo.g", + "pkg/polymaking/PackageInfo.g", + "pkg/primgrp/PackageInfo.g", + "pkg/profiling/PackageInfo.g", + "pkg/qdistrnd/PackageInfo.g", + "pkg/qpa/PackageInfo.g", + "pkg/quagroup/PackageInfo.g", + "pkg/radiroot/PackageInfo.g", + "pkg/rcwa/PackageInfo.g", + "pkg/rds/PackageInfo.g", + "pkg/recog/PackageInfo.g", + "pkg/repndecomp/PackageInfo.g", + "pkg/repsn/PackageInfo.g", + "pkg/resclasses/PackageInfo.g", + "pkg/ringsforhomalg/PackageInfo.g", + "pkg/sco/PackageInfo.g", + "pkg/scscp/PackageInfo.g", + "pkg/semigroups/PackageInfo.g", + "pkg/sglppow/PackageInfo.g", + "pkg/sgpviz/PackageInfo.g", + "pkg/simpcomp/PackageInfo.g", + "pkg/singular/PackageInfo.g", + "pkg/sl2reps/PackageInfo.g", + "pkg/sla/PackageInfo.g", + "pkg/smallantimagmas/PackageInfo.g", + "pkg/smallclassnr/PackageInfo.g", + "pkg/smallgrp/PackageInfo.g", + "pkg/smallsemi/PackageInfo.g", + "pkg/sonata/PackageInfo.g", + "pkg/sophus/PackageInfo.g", + "pkg/sotgrps/PackageInfo.g", + "pkg/spinsym/PackageInfo.g", + "pkg/standardff/PackageInfo.g", + "pkg/symbcompcc/PackageInfo.g", + "pkg/thelma/PackageInfo.g", + "pkg/tomlib/PackageInfo.g", + "pkg/toolsforhomalg/PackageInfo.g", + "pkg/toric/PackageInfo.g", + "pkg/transgrp/PackageInfo.g", + "pkg/twistedconjugacy/PackageInfo.g", + "pkg/typeset/PackageInfo.g", + "pkg/ugaly/PackageInfo.g", + "pkg/unipot/PackageInfo.g", + "pkg/unitlib/PackageInfo.g", + "pkg/utils/PackageInfo.g", + "pkg/uuid/PackageInfo.g", + "pkg/walrus/PackageInfo.g", + "pkg/wedderga/PackageInfo.g", + "pkg/wpe/PackageInfo.g", + "pkg/xgap/PackageInfo.g", + "pkg/xmod/PackageInfo.g", + "pkg/xmodalg/PackageInfo.g", + "pkg/yangbaxter/PackageInfo.g", + "pkg/zeromqinterface/PackageInfo.g", + "pkg/gapdoc/init.g", + "pkg/gapdoc/lib/UnicodeTools.gd", + "pkg/gapdoc/lib/PrintUtil.gd", + "pkg/gapdoc/lib/Text.gd", + "pkg/gapdoc/lib/ComposeXML.gd", + "pkg/gapdoc/lib/XMLParser.gd", + "pkg/gapdoc/lib/GAPDoc.gd", + "pkg/gapdoc/lib/BibTeX.gd", + "pkg/gapdoc/lib/BibXMLextTools.gd", + "pkg/gapdoc/lib/GAPDoc2LaTeX.gd", + "pkg/gapdoc/lib/GAPDoc2Text.gd", + "pkg/gapdoc/lib/GAPDoc2HTML.gd", + "pkg/gapdoc/lib/Make.g", + "pkg/gapdoc/lib/Examples.gd", + "pkg/gapdoc/read.g", + "pkg/gapdoc/lib/UnicodeTools.gi", + "pkg/gapdoc/lib/UnicodeTabs.g", + "pkg/gapdoc/lib/PrintUtil.gi", + "pkg/gapdoc/lib/Text.gi", + "pkg/gapdoc/lib/ComposeXML.gi", + "pkg/gapdoc/lib/XMLParser.gi", + "pkg/gapdoc/lib/gapdocdtdinfo.g", + "pkg/gapdoc/lib/GAPDoc.gi", + "pkg/gapdoc/lib/BibTeX.gi", + "pkg/gapdoc/lib/bibxmlextinfo.g", + "pkg/gapdoc/lib/BibXMLextTools.gi", + "pkg/gapdoc/lib/GAPDoc2LaTeX.gi", + "pkg/gapdoc/lib/latexhead.tex", + "pkg/gapdoc/lib/GAPDoc2Text.gi", + "pkg/gapdoc/lib/TextThemes.g", + "pkg/gapdoc/lib/GAPDoc2HTML.gi", + "pkg/gapdoc/lib/Examples.gi", + "pkg/gapdoc/lib/HelpBookHandler.g", + "pkg/primgrp/init.g", + "pkg/primgrp/lib/primitiv.gd", + "pkg/primgrp/lib/irredsol.gd", + "pkg/primgrp/read.g", + "pkg/primgrp/lib/primitiv.grp", + "pkg/primgrp/lib/primitiv.gi", + "pkg/primgrp/lib/irredsol.grp", + "pkg/primgrp/lib/irredsol.gi", + "pkg/primgrp/lib/cohorts.grp", + "pkg/smallgrp/init.g", + "pkg/smallgrp/gap/small.gd", + "pkg/smallgrp/read.g", + "pkg/smallgrp/gap/small.gi", + "pkg/smallgrp/gap/smlgp1.g", + "pkg/smallgrp/gap/idgrp1.g", + "pkg/smallgrp/gap/smlinfo.gi", + "pkg/smallgrp/small2/smlgp2.g.gz", + "pkg/smallgrp/small3/smlgp3.g.gz", + "pkg/smallgrp/small4/smlgp4.g.gz", + "pkg/smallgrp/small5/smlgp5.g.gz", + "pkg/smallgrp/small6/smlgp6.g.gz", + "pkg/smallgrp/small7/smlgp7.g.gz", + "pkg/smallgrp/small8/smlgp8.g.gz", + "pkg/smallgrp/small9/smlgp9.g.gz", + "pkg/smallgrp/small10/smlgp10.g.gz", + "pkg/smallgrp/small11/smlgp11.g.gz", + "pkg/smallgrp/id2/idgrp2.g.gz", + "pkg/smallgrp/id3/idgrp3.g.gz", + "pkg/smallgrp/id4/idgrp4.g.gz", + "pkg/smallgrp/id5/idgrp5.g.gz", + "pkg/smallgrp/id6/idgrp6.g.gz", + "pkg/smallgrp/id9/idgrp9.g.gz", + "pkg/smallgrp/id10/idgrp10.g.gz", + "pkg/transgrp/init.g", + "pkg/transgrp/lib/trans.gd", + "pkg/transgrp/read.g", + "pkg/transgrp/lib/trans.grp", + "pkg/transgrp/lib/trans.gi", + "pkg/autpgrp/init.g", + "pkg/autpgrp/gap/autos.gd", + "pkg/autpgrp/read.g", + "pkg/autpgrp/gap/general.gi", + "pkg/autpgrp/gap/autoops.gi", + "pkg/autpgrp/gap/matrix.gi", + "pkg/autpgrp/gap/nicestab.gi", + "pkg/autpgrp/gap/initmat.gi", + "pkg/autpgrp/gap/initperm.gi", + "pkg/autpgrp/gap/hybrstab.gi", + "pkg/autpgrp/gap/matrstab.gi", + "pkg/autpgrp/gap/orbstab.gi", + "pkg/autpgrp/gap/autos.gi", + "pkg/autpgrp/gap/pcpres.gi", + "pkg/autpgrp/gap/countcl.gi", + "pkg/alnuth/init.g", + "pkg/alnuth/gap/setup.gd", + "pkg/alnuth/gap/factors.gd", + "pkg/alnuth/gap/field.gd", + "pkg/polycyclic/init.g", + "pkg/polycyclic/gap/matrix/matrix.gd", + "pkg/polycyclic/gap/basic/infos.gd", + "pkg/polycyclic/gap/basic/collect.gd", + "pkg/polycyclic/gap/basic/pcpelms.gd", + "pkg/polycyclic/gap/basic/pcpgrps.gd", + "pkg/polycyclic/gap/basic/pcppcps.gd", + "pkg/polycyclic/gap/basic/grphoms.gd", + "pkg/polycyclic/gap/basic/basic.gd", + "pkg/polycyclic/gap/cohom/cohom.gd", + "pkg/polycyclic/gap/matrep/matrep.gd", + "pkg/polycyclic/gap/matrep/unitri.gd", + "pkg/polycyclic/gap/pcpgrp/pcpgrp.gd", + "pkg/polycyclic/gap/pcpgrp/torsion.gd", + "pkg/polycyclic/gap/exam/exam.gd", + "pkg/polycyclic/gap/obsolete.gd", + "pkg/alnuth/read.g", + "pkg/alnuth/gap/userpref.gi", + "pkg/alnuth/gap/setup.gi", + "pkg/alnuth/gap/pari.gi", + "pkg/alnuth/gap/factors.gi", + "pkg/alnuth/gap/matfield.gi", + "pkg/alnuth/gap/polfield.gi", + "pkg/alnuth/gap/field.gi", + "pkg/alnuth/gap/unithom.gi", + "pkg/alnuth/gap/matunits.gi", + "pkg/alnuth/gap/rels.gi", + "pkg/alnuth/gap/present.gi", + "pkg/alnuth/gap/isom.gi", + "pkg/alnuth/gap/rationals.gi", + "pkg/alnuth/exam/unimod.gi", + "pkg/alnuth/exam/rationals.gi", + "pkg/alnuth/exam/fields.gi", + "pkg/polycyclic/read.g", + "pkg/polycyclic/gap/matrix/rowbases.gi", + "pkg/polycyclic/gap/matrix/latbases.gi", + "pkg/polycyclic/gap/matrix/lattices.gi", + "pkg/polycyclic/gap/matrix/modules.gi", + "pkg/polycyclic/gap/matrix/triangle.gi", + "pkg/polycyclic/gap/matrix/hnf.gi", + "pkg/polycyclic/gap/basic/collect.gi", + "pkg/polycyclic/gap/basic/colftl.gi", + "pkg/polycyclic/gap/basic/colcom.gi", + "pkg/polycyclic/gap/basic/coldt.gi", + "pkg/polycyclic/gap/basic/colsave.gi", + "pkg/polycyclic/gap/basic/pcpelms.gi", + "pkg/polycyclic/gap/basic/pcppcps.gi", + "pkg/polycyclic/gap/basic/pcpgrps.gi", + "pkg/polycyclic/gap/basic/pcppara.gi", + "pkg/polycyclic/gap/basic/pcpexpo.gi", + "pkg/polycyclic/gap/basic/pcpsers.gi", + "pkg/polycyclic/gap/basic/grphoms.gi", + "pkg/polycyclic/gap/basic/pcpfact.gi", + "pkg/polycyclic/gap/basic/chngpcp.gi", + "pkg/polycyclic/gap/basic/convert.gi", + "pkg/polycyclic/gap/basic/orbstab.gi", + "pkg/polycyclic/gap/basic/construct.gi", + "pkg/polycyclic/gap/cohom/cohom.gi", + "pkg/polycyclic/gap/cohom/addgrp.gi", + "pkg/polycyclic/gap/cohom/general.gi", + "pkg/polycyclic/gap/cohom/solabel.gi", + "pkg/polycyclic/gap/cohom/solcohom.gi", + "pkg/polycyclic/gap/cohom/twocohom.gi", + "pkg/polycyclic/gap/cohom/intcohom.gi", + "pkg/polycyclic/gap/cohom/onecohom.gi", + "pkg/polycyclic/gap/cohom/grpext.gi", + "pkg/polycyclic/gap/cohom/grpcom.gi", + "pkg/polycyclic/gap/cohom/norcom.gi", + "pkg/polycyclic/gap/action/extend.gi", + "pkg/polycyclic/gap/action/basepcgs.gi", + "pkg/polycyclic/gap/action/freegens.gi", + "pkg/polycyclic/gap/action/dixon.gi", + "pkg/polycyclic/gap/action/kernels.gi", + "pkg/polycyclic/gap/action/orbstab.gi", + "pkg/polycyclic/gap/action/orbnorm.gi", + "pkg/polycyclic/gap/pcpgrp/general.gi", + "pkg/polycyclic/gap/pcpgrp/inters.gi", + "pkg/polycyclic/gap/pcpgrp/grpinva.gi", + "pkg/polycyclic/gap/pcpgrp/torsion.gi", + "pkg/polycyclic/gap/pcpgrp/maxsub.gi", + "pkg/polycyclic/gap/pcpgrp/findex.gi", + "pkg/polycyclic/gap/pcpgrp/nindex.gi", + "pkg/polycyclic/gap/pcpgrp/nilpot.gi", + "pkg/polycyclic/gap/pcpgrp/polyz.gi", + "pkg/polycyclic/gap/pcpgrp/pcpattr.gi", + "pkg/polycyclic/gap/pcpgrp/wreath.gi", + "pkg/polycyclic/gap/pcpgrp/fitting.gi", + "pkg/polycyclic/gap/pcpgrp/centcon.gi", + "pkg/polycyclic/gap/pcpgrp/normcon.gi", + "pkg/polycyclic/gap/pcpgrp/schur.gi", + "pkg/polycyclic/gap/pcpgrp/tensor.gi", + "pkg/polycyclic/gap/matrep/matrep.gi", + "pkg/polycyclic/gap/matrep/affine.gi", + "pkg/polycyclic/gap/matrep/unitri.gi", + "pkg/polycyclic/gap/exam/pcplib.gi", + "pkg/polycyclic/gap/exam/matlib.gi", + "pkg/polycyclic/gap/exam/nqlib.gi", + "pkg/polycyclic/gap/exam/generic.gi", + "pkg/polycyclic/gap/exam/bgnilp.gi", + "pkg/polycyclic/gap/exam/metacyc.gi", + "pkg/polycyclic/gap/exam/metagrp.gi", + "pkg/polycyclic/gap/cover/const/bas.gi", + "pkg/polycyclic/gap/cover/const/orb.gi", + "pkg/polycyclic/gap/cover/const/aut.gi", + "pkg/polycyclic/gap/cover/const/com.gi", + "pkg/polycyclic/gap/cover/const/cov.gi", + "pkg/crisp/init.g", + "pkg/crisp/lib/classes.gd", + "pkg/crisp/lib/grpclass.gd", + "pkg/crisp/lib/fitting.gd", + "pkg/crisp/lib/schunck.gd", + "pkg/crisp/lib/form.gd", + "pkg/crisp/lib/projector.gd", + "pkg/crisp/lib/injector.gd", + "pkg/crisp/lib/normpro.gd", + "pkg/crisp/lib/solveeq.gd", + "pkg/crisp/lib/compl.gd", + "pkg/crisp/lib/radical.gd", + "pkg/crisp/lib/residual.gd", + "pkg/crisp/lib/util.gd", + "pkg/crisp/lib/samples.gd", + "pkg/crisp/lib/socle.gd", + "pkg/crisp/read.g", + "pkg/crisp/lib/classes.gi", + "pkg/crisp/lib/grpclass.gi", + "pkg/crisp/lib/fitting.gi", + "pkg/crisp/lib/schunck.gi", + "pkg/crisp/lib/form.gi", + "pkg/crisp/lib/projector.gi", + "pkg/crisp/lib/injector.gi", + "pkg/crisp/lib/normpro.gi", + "pkg/crisp/lib/solveeq.gi", + "pkg/crisp/lib/compl.gi", + "pkg/crisp/lib/radical.gi", + "pkg/crisp/lib/residual.gi", + "pkg/crisp/lib/util.gi", + "pkg/crisp/lib/samples.gi", + "pkg/crisp/lib/socle.gi", + "pkg/factint/init.g", + "pkg/factint/lib/factint.gd", + "pkg/factint/read.g", + "pkg/factint/tables/3k2k.g", + "pkg/factint/tables/akbk.g", + "pkg/factint/tables/factorial.g", + "pkg/factint/tables/fibo.g", + "pkg/factint/tables/primorial.g", + "pkg/factint/lib/general.gi", + "pkg/factint/lib/pminus1.gi", + "pkg/factint/lib/pplus1.gi", + "pkg/factint/lib/ecm.gi", + "pkg/factint/lib/cfrac.gi", + "pkg/factint/lib/mpqs.gi", + "pkg/forms/init.g", + "pkg/forms/lib/forms.gd", + "pkg/forms/lib/recognition.gd", + "pkg/forms/lib/conformal.gd", + "pkg/forms/read.g", + "pkg/forms/lib/forms.gi", + "pkg/forms/lib/recognition.gi", + "pkg/forms/lib/classic.gi", + "pkg/forms/lib/recognition_new.gi", + "pkg/forms/lib/conformal.gi", + "pkg/orb/init.g", + "pkg/orb/gap/homwdata.gd", + "pkg/orb/gap/avltree.gd", + "pkg/orb/gap/hash.gd", + "pkg/orb/gap/cache.gd", + "pkg/orb/gap/orbits.gd", + "pkg/orb/gap/search.gd", + "pkg/orb/gap/bysuborbit.gd", + "pkg/orb/read.g", + "pkg/orb/gap/homwdata.gi", + "pkg/orb/gap/avltree.gi", + "pkg/orb/gap/hash.gi", + "pkg/orb/gap/cache.gi", + "pkg/orb/gap/orbits.gi", + "pkg/orb/gap/search.gi", + "pkg/orb/gap/bysuborbit.gi", + "pkg/utils/init.g", + "pkg/utils/lib/start.gd", + "pkg/utils/lib/files.gd", + "pkg/utils/lib/groups.gd", + "pkg/utils/lib/iterator.gd", + "pkg/utils/lib/latex.gd", + "pkg/utils/lib/lcset.gd", + "pkg/utils/lib/lists.gd", + "pkg/utils/lib/magma.gd", + "pkg/utils/lib/maps.gd", + "pkg/utils/lib/matrix.gd", + "pkg/utils/lib/number.gd", + "pkg/utils/lib/print.gd", + "pkg/utils/lib/record.gd", + "pkg/utils/lib/string.gd", + "pkg/utils/lib/gslp.gd", + "pkg/utils/lib/download.gd", + "pkg/utils/read.g", + "pkg/utils/lib/files.gi", + "pkg/utils/lib/groups.gi", + "pkg/utils/lib/iterator.gi", + "pkg/utils/lib/latex.gi", + "pkg/utils/lib/lcset.gi", + "pkg/utils/lib/lists.gi", + "pkg/utils/lib/magma.gi", + "pkg/utils/lib/maps.gi", + "pkg/utils/lib/matrix.gi", + "pkg/utils/lib/number.gi", + "pkg/utils/lib/print.gi", + "pkg/utils/lib/record.gi", + "pkg/utils/lib/string.gi", + "pkg/utils/lib/gslp.gi", + "pkg/utils/lib/download.gi", + "pkg/genss/init.g", + "pkg/genss/gap/genss.gd", + "pkg/genss/gap/setwise.gd", + "pkg/genss/read.g", + "pkg/genss/gap/genss.gi", + "pkg/genss/gap/setwise.gi", + "pkg/atlasrep/init.g", + "pkg/atlasrep/gap/userpref.g", + "pkg/atlasrep/gap/bbox.gd", + "pkg/atlasrep/gap/access.gd", + "pkg/atlasrep/gap/scanmtx.gd", + "pkg/atlasrep/gap/scanmtx.gi", + "pkg/atlasrep/gap/types.gd", + "pkg/atlasrep/gap/interfac.gd", + "pkg/atlasrep/gap/mindeg.gd", + "pkg/atlasrep/gap/utils.gd", + "pkg/ctbllib/init.g", + "pkg/ctbllib/gap4/ctadmin.gd", + "pkg/ctbllib/gap4/construc.gd", + "pkg/ctbllib/gap4/ctblothe.gd", + "pkg/ctbllib/dlnames/dlnames.gd", + "pkg/ctbllib/gap4/obsolete.gd", + "pkg/ctbllib/gap4/brdbattrX.gd", + "pkg/ctbllib/gap4/brdbattrX.gi", + "pkg/recog/init.g", + "pkg/recog/gap/base/hack.g", + "pkg/recog/gap/base/methods.gd", + "pkg/recog/gap/base/methsel.gd", + "pkg/recog/gap/base/recognition.gd", + "pkg/recog/gap/base/kernel.gd", + "pkg/recog/gap/base/projective.gd", + "pkg/recog/gap/matrix/ppd.gd", + "pkg/recog/gap/matrix/classical.gd", + "pkg/recog/gap/projective/almostsimple.gd", + "pkg/recog/gap/projective/findnormal.gd", + "pkg/recog/gap/projective/AnSnOnFDPM.gd", + "pkg/spinsym/init.g", + "pkg/spinsym/gap/mtx.gd", + "pkg/spinsym/gap/fus.gd", + "pkg/spinsym/gap/young.gd", + "pkg/standardff/init.g", + "pkg/standardff/lib/Util.gd", + "pkg/standardff/lib/IsIrred.gd", + "pkg/standardff/lib/StandardFF.gd", + "pkg/standardff/lib/StandardCyc.gd", + "pkg/tomlib/init.g", + "pkg/tomlib/gap/tmadmin.tmd", + "pkg/tomlib/gap/stdgen.gd", + "pkg/atlasrep/read.g", + "pkg/atlasrep/gap/bbox.gi", + "pkg/atlasrep/gap/access.gi", + "pkg/atlasrep/gap/types.gi", + "pkg/atlasrep/gap/interfac.gi", + "pkg/atlasrep/gap/mindeg.gi", + "pkg/atlasrep/gap/utlmrkup.g", + "pkg/atlasrep/gap/utils.gi", + "pkg/atlasrep/gap/test.g", + "pkg/atlasrep/gap/json.g", + "pkg/atlasrep/gap/obsolete.gd", + "pkg/atlasrep/gap/obsolete.gi", + "pkg/ctbllib/read.g", + "pkg/ctbllib/gap4/ctadmin.gi", + "pkg/ctbllib/gap4/ctprimar.g", + "pkg/ctbllib/data/firstnames.json", + "pkg/ctbllib/data/othernames.json", + "pkg/ctbllib/data/fusionsources.json", + "pkg/ctbllib/data/extinfo.json", + "pkg/ctbllib/data/ctgeneri.tbl", + "pkg/ctbllib/data/version", + "pkg/ctbllib/data/namerepl.json", + "pkg/ctbllib/gap4/construc.gi", + "pkg/ctbllib/gap4/ctblothe.gi", + "pkg/ctbllib/gap4/test.g", + "pkg/ctbllib/dlnames/dlnames.gi", + "pkg/ctbllib/gap4/ctbltoct.g", + "pkg/ctbllib/gap4/ctdbattr.g", + "pkg/ctbllib/gap4/od.g", + "pkg/ctbllib/data/odresults.json", + "pkg/ctbllib/gap4/atlasstr.g", + "pkg/ctbllib/gap4/atlasirr.g", + "pkg/recog/read.g", + "pkg/recog/gap/base/methods.gi", + "pkg/recog/gap/base/methsel.gi", + "pkg/recog/gap/base/recognition.gi", + "pkg/recog/gap/base/kernel.gi", + "pkg/recog/gap/base/projective.gi", + "pkg/recog/gap/utils.gi", + "pkg/recog/gap/generic/TrivialGroup.gi", + "pkg/recog/gap/generic/FewGensAbelian.gi", + "pkg/recog/gap/generic/KnownNilpotent.gi", + "pkg/recog/gap/perm/giant.gi", + "pkg/recog/gap/perm/largebase.gi", + "pkg/recog/gap/SnAnBB.gi", + "pkg/recog/gap/generic/SnAnUnknownDegree.gi", + "pkg/recog/gap/matrix/matimpr.gi", + "pkg/recog/gap/matrix/blocks.gi", + "pkg/recog/gap/matrix/ppd.gi", + "pkg/recog/gap/matrix/classical.gi", + "pkg/recog/gap/matrix/slconstr.gi", + "pkg/recog/gap/projective/findnormal.gi", + "pkg/recog/gap/projective/c6.gi", + "pkg/recog/gap/projective/tensor.gi", + "pkg/recog/gap/projective/c3c5.gi", + "pkg/recog/gap/projective/d247.gi", + "pkg/recog/gap/projective/almostsimple/threeelorders.gi", + "pkg/recog/gap/projective/almostsimple.gi", + "pkg/recog/gap/projective/almostsimple/lietype.gi", + "pkg/recog/gap/projective/almostsimple/hints.gi", + "pkg/recog/gap/projective/classicalnatural.gi", + "pkg/recog/gap/projective/sl2_natural.gi", + "pkg/recog/gap/projective/sl.gi", + "pkg/recog/gap/projective/AnSnOnFDPM.gi", + "pkg/recog/gap/perm.gi", + "pkg/recog/gap/matrix.gi", + "pkg/recog/gap/projective.gi", + "pkg/spinsym/read.g", + "pkg/spinsym/gap/mtx.gi", + "pkg/spinsym/gap/fus.gi", + "pkg/spinsym/gap/young.gi", + "pkg/standardff/read.g", + "pkg/standardff/lib/Util.gi", + "pkg/standardff/lib/IsIrred.gi", + "pkg/standardff/lib/StandardFF.gi", + "pkg/standardff/lib/StandardCyc.gi", + "pkg/standardff/lib/CANFACT.g", + "pkg/standardff/lib/TestFuncs.g", + "pkg/tomlib/read.g", + "pkg/tomlib/gap/tmstdrd.tom", + "pkg/tomlib/gap/tmadmin.tmi", + "pkg/tomlib/gap/stdgen.gi", + "pkg/atlasrep/gap/ctbllib_only.g", + "pkg/ctbllib/gap4/atlasrep_only.g", + "pkg/ctbllib/gap4/tomlib_only.g", + "pkg/ctbllib/data/tom_tbl.json", + "pkg/ctbllib/gap4/spinsym_only.g", + "pkg/ctbllib/data/grp_atlas.json", + "pkg/ctbllib/data/attr_nccl.json", + "pkg/ctbllib/data/grp_small.json", + "pkg/ctbllib/data/grp_tom.json", + "pkg/ctbllib/data/grp_trans.json", + "pkg/ctbllib/data/grp_prim.json", + "pkg/ctbllib/data/grp_perf.json", + "pkg/fga/init.g", + "pkg/fga/lib/util.gd", + "pkg/fga/lib/Iterated.gd", + "pkg/fga/lib/Autom.gd", + "pkg/fga/lib/FreeGrps.gd", + "pkg/fga/lib/ReprAct.gd", + "pkg/fga/lib/Normal.gd", + "pkg/fga/lib/ExtAutom.gd", + "pkg/fga/lib/Hom.gd", + "pkg/fga/lib/AutGrp.gd", + "pkg/fga/lib/Intsect.gd", + "pkg/fga/lib/Whitehd.gd", + "pkg/fga/read.g", + "pkg/fga/lib/util.gi", + "pkg/fga/lib/Iterated.gi", + "pkg/fga/lib/Autom.gi", + "pkg/fga/lib/FreeGrps.gi", + "pkg/fga/lib/ReprAct.gi", + "pkg/fga/lib/Normal.gi", + "pkg/fga/lib/Central.gi", + "pkg/fga/lib/Index.gi", + "pkg/fga/lib/ExtAutom.gi", + "pkg/fga/lib/Hom.gi", + "pkg/fga/lib/AutGrp.gi", + "pkg/fga/lib/Intsect.gi", + "pkg/fga/lib/ReprActT.gi", + "pkg/fga/lib/Whitehd.gi", + "pkg/irredsol/init.g", + "pkg/irredsol/lib/util.g", + "pkg/irredsol/lib/util.gd", + "pkg/irredsol/lib/matmeths.gd", + "pkg/irredsol/lib/loading.gd", + "pkg/irredsol/lib/loadfp.gd", + "pkg/irredsol/lib/access.gd", + "pkg/irredsol/lib/iterators.gd", + "pkg/irredsol/lib/recognize.gd", + "pkg/irredsol/lib/primitive.gd", + "pkg/irredsol/lib/recognizeprim.gd", + "pkg/irredsol/lib/obsolete.gd", + "pkg/irredsol/read.g", + "pkg/irredsol/lib/matmeths.gi", + "pkg/irredsol/lib/loading.gi", + "pkg/irredsol/lib/loadfp.gi", + "pkg/irredsol/lib/access.gi", + "pkg/irredsol/lib/iterators.gi", + "pkg/irredsol/lib/recognize.gi", + "pkg/irredsol/lib/primitive.gi", + "pkg/irredsol/lib/recognizeprim.gi", + "pkg/irredsol/lib/util.gi", + "pkg/irredsol/lib/obsolete.gi", + "pkg/sophus/init.g", + "pkg/sophus/gap/sophus.gd", + "pkg/sophus/read.g", + "pkg/sophus/gap/general.gi", + "pkg/sophus/gap/lienp.gi", + "pkg/sophus/gap/liesct.gi", + "pkg/sophus/gap/liecover.gi", + "pkg/sophus/gap/nicestab.gi", + "pkg/sophus/gap/lieautoops.gi", + "pkg/sophus/gap/initauts.gi", + "pkg/sophus/gap/lieautgrp.gi", + "pkg/sophus/gap/allowable.gi", + "pkg/sophus/gap/descendant.gi", + "pkg/sophus/gap/lieisom.gi", + "pkg/sophus/gap/io.gi", + "pkg/laguna/init.g", + "pkg/laguna/lib/laguna.gd", + "pkg/laguna/lib/laguna.g", + "pkg/laguna/read.g", + "pkg/laguna/lib/laguna.gi", + "pkg/autodoc/init.g", + "pkg/autodoc/gap/DocumentationTree.gd", + "pkg/autodoc/gap/Parser.gd", + "pkg/autodoc/gap/AutoDocMainFunction.gd", + "pkg/autodoc/gap/ToolFunctions.gd", + "pkg/autodoc/gap/Magic.gd", + "pkg/autodoc/gap/Markdown.gd", + "pkg/autodoc/read.g", + "pkg/autodoc/gap/ToolFunctions.gi", + "pkg/autodoc/gap/DocumentationTree.gi", + "pkg/autodoc/gap/Parser.gi", + "pkg/autodoc/gap/AutoDocMainFunction.gi", + "pkg/autodoc/gap/Magic.gi", + "pkg/autodoc/gap/Markdown.gi", + "pkg/packagemanager/init.g", + "pkg/packagemanager/gap/PackageManager.gd", + "pkg/packagemanager/gap/archive.gd", + "pkg/packagemanager/gap/compile.gd", + "pkg/packagemanager/gap/directories.gd", + "pkg/packagemanager/gap/distro.gd", + "pkg/packagemanager/gap/doc.gd", + "pkg/packagemanager/gap/download.gd", + "pkg/packagemanager/gap/git.gd", + "pkg/packagemanager/gap/hg.gd", + "pkg/packagemanager/gap/interactive.gd", + "pkg/packagemanager/gap/packageinfo.gd", + "pkg/packagemanager/read.g", + "pkg/packagemanager/gap/PackageManager.gi", + "pkg/packagemanager/gap/archive.gi", + "pkg/packagemanager/gap/compile.gi", + "pkg/packagemanager/gap/directories.gi", + "pkg/packagemanager/gap/distro.gi", + "pkg/packagemanager/gap/doc.gi", + "pkg/packagemanager/gap/download.gi", + "pkg/packagemanager/gap/git.gi", + "pkg/packagemanager/gap/hg.gi", + "pkg/packagemanager/gap/interactive.gi", + "pkg/packagemanager/gap/packageinfo.gi", + "pkg/radiroot/init.g", + "pkg/radiroot/lib/Radicals.gd", + "pkg/radiroot/lib/SplittField.gd", + "pkg/radiroot/lib/Manipulations.gd", + "pkg/radiroot/lib/Strings.gd", + "pkg/radiroot/lib/Maple.gd", + "pkg/radiroot/read.g", + "pkg/radiroot/lib/Radicals.gi", + "pkg/radiroot/lib/SplittField.gi", + "pkg/radiroot/lib/Manipulations.gi", + "pkg/radiroot/lib/Strings.gi", + "pkg/radiroot/lib/Maple.gi", + "pkg/aclib/init.g", + "pkg/aclib/gap/groups.gd", + "pkg/cryst/init.g", + "pkg/cryst/gap/common.gd", + "pkg/cryst/gap/cryst.gd", + "pkg/cryst/gap/hom.gd", + "pkg/cryst/gap/wyckoff.gd", + "pkg/cryst/gap/zass.gd", + "pkg/cryst/gap/max.gd", + "pkg/cryst/gap/color.gd", + "pkg/cryst/gap/equiv.gd", + "pkg/cryst/grp/spacegrp.gd", + "pkg/crystcat/init.g", + "pkg/crystcat/lib/crystcat.gd", + "pkg/polenta/init.g", + "pkg/polenta/lib/finite.gd", + "pkg/polenta/lib/info.gd", + "pkg/polenta/lib/basic.gd", + "pkg/polenta/exam/test.gd", + "pkg/polenta/lib/cpcs.gd", + "pkg/polenta/lib/present.gd", + "pkg/polenta/lib/solvable.gd", + "pkg/polenta/lib/series.gd", + "pkg/polenta/lib/subgroups.gd", + "pkg/polenta/lib/ispolyz.gd", + "pkg/aclib/read.g", + "pkg/aclib/gap/matgrp3.gi", + "pkg/aclib/gap/matgrp4.gi", + "pkg/aclib/gap/matgrp.gi", + "pkg/aclib/gap/pcpgrp3.gi", + "pkg/aclib/gap/pcpgrp4.gi", + "pkg/aclib/gap/pcpgrp.gi", + "pkg/aclib/gap/betti.gi", + "pkg/aclib/gap/union.gi", + "pkg/aclib/gap/extend.gi", + "pkg/aclib/gap/crystgrp.gi", + "pkg/cryst/read.g", + "pkg/cryst/gap/common.gi", + "pkg/cryst/gap/hom.gi", + "pkg/cryst/gap/cryst.gi", + "pkg/cryst/gap/cryst2.gi", + "pkg/cryst/gap/fpgrp.gi", + "pkg/cryst/gap/zass.gi", + "pkg/cryst/gap/max.gi", + "pkg/cryst/gap/wyckoff.gi", + "pkg/cryst/gap/color.gi", + "pkg/cryst/gap/noxgap.gi", + "pkg/cryst/gap/pcpgrp.gi", + "pkg/cryst/gap/orbstab.gi", + "pkg/cryst/gap/equiv.gi", + "pkg/cryst/grp/spacegrp.grp", + "pkg/cryst/grp/spacegrp.gi", + "pkg/crystcat/read.g", + "pkg/crystcat/grp/crystcat.grp", + "pkg/crystcat/lib/crystcat.gi", + "pkg/crystcat/lib/normalizer.gi", + "pkg/polenta/read.g", + "pkg/polenta/lib/finite.gi", + "pkg/polenta/lib/basic.gi", + "pkg/polenta/lib/unipo.gi", + "pkg/polenta/lib/series.gi", + "pkg/polenta/lib/semi.gi", + "pkg/polenta/lib/ispoly.gi", + "pkg/polenta/lib/cpcs.gi", + "pkg/polenta/lib/present.gi", + "pkg/polenta/lib/isom.gi", + "pkg/polenta/lib/solvable.gi", + "pkg/polenta/exam/exam.gi", + "pkg/polenta/exam/test.gi", + "pkg/polenta/lib/subgroups.gi", + "pkg/polenta/lib/ispolyz.gi", + "pkg/resclasses/init.g", + "pkg/resclasses/lib/general.gd", + "pkg/resclasses/lib/z_pi.gd", + "pkg/resclasses/lib/resclass.gd", + "pkg/resclasses/lib/fixedrep.gd", + "pkg/resclasses/read.g", + "pkg/resclasses/lib/general.gi", + "pkg/resclasses/lib/resclaux.g", + "pkg/resclasses/lib/z_pi.gi", + "pkg/resclasses/lib/resclass.gi", + "pkg/resclasses/lib/fixedrep.gi", + "lib/obsolete.gi", + "pkg/4ti2interface/doc/manual.six", + "pkg/ace/doc/manual.six", + "pkg/aclib/doc/manual.six", + "pkg/agt/doc/manual.six", + "pkg/alco/doc/manual.six", + "pkg/alnuth/doc/manual.six", + "pkg/anupq/doc/manual.six", + "pkg/atlasrep/doc/manual.six", + "pkg/autodoc/doc/manual.six", + "pkg/automata/doc/manual.six", + "pkg/automgrp/doc/manual.six", + "pkg/autpgrp/doc/manual.six", + "pkg/browse/doc/manual.six", + "pkg/cap/doc/manual.six", + "pkg/caratinterface/doc/manual.six", + "pkg/cddinterface/doc/manual.six", + "pkg/circle/doc/manual.six", + "pkg/classicalmaximals/doc/manual.six", + "pkg/classicpres/doc/manual.six", + "pkg/cohomolo/doc/manual.six", + "pkg/congruence/doc/manual.six", + "pkg/corefreesub/doc/manual.six", + "pkg/corelg/doc/manual.six", + "pkg/crime/doc/manual.six", + "pkg/crisp/doc/manual.six", + "pkg/crypting/doc/manual.six", + "pkg/cryst/doc/manual.six", + "pkg/crystcat/doc/manual.six", + "pkg/ctbllib/doc/manual.six", + "pkg/ctbllib/doc2/manual.six", + "pkg/cubefree/doc/manual.six", + "pkg/curlinterface/doc/manual.six", + "pkg/cvec/doc/manual.six", + "pkg/datastructures/doc/manual.six", + "pkg/deepthought/doc/manual.six", + "pkg/design/doc/manual.six", + "pkg/difsets/doc/manual.six", + "pkg/digraphs/doc/manual.six", + "pkg/edim/doc/manual.six", + "pkg/example/doc/manual.six", + "pkg/examplesforhomalg/doc/manual.six", + "pkg/factint/doc/manual.six", + "pkg/ferret/doc/manual.six", + "pkg/fga/doc/manual.six", + "pkg/fining/doc/manual.six", + "pkg/float/doc/manual.six", + "pkg/format/doc/manual.six", + "pkg/forms/doc/manual.six", + "pkg/fplsa/doc/manual.six", + "pkg/fr/doc/manual.six", + "pkg/francy/doc/manual.six", + "pkg/fwtree/doc/manual.six", + "pkg/gapdoc/doc/manual.six", + "pkg/gapdoc/example/manual.six", + "pkg/gauss/doc/manual.six", + "pkg/gaussforhomalg/doc/manual.six", + "pkg/gbnp/doc/manual.six", + "pkg/generalizedmorphismsforcap/doc/manual.six", + "pkg/genss/doc/manual.six", + "pkg/gradedmodules/doc/manual.six", + "pkg/gradedringforhomalg/doc/manual.six", + "pkg/grape/doc/manual.six", + "pkg/groupoids/doc/manual.six", + "pkg/grpconst/doc/manual.six", + "pkg/guarana/doc/manual.six", + "pkg/guava/doc/manual.six", + "pkg/hap/doc/manual.six", + "pkg/hapcryst/doc/manual.six", + "pkg/hecke/doc/manual.six", + "pkg/help/doc/manual.six", + "pkg/homalg/doc/manual.six", + "pkg/homalgtocas/doc/manual.six", + "pkg/ibnp/doc/manual.six", + "pkg/idrel/doc/manual.six", + "pkg/images/doc/manual.six", + "pkg/inducereduce/doc/manual.six", + "pkg/intpic/doc/manual.six", + "pkg/io/doc/manual.six", + "pkg/io_forhomalg/doc/manual.six", + "pkg/irredsol/doc/manual.six", + "pkg/itc/doc/manual.six", + "pkg/json/doc/manual.six", + "pkg/jupyterkernel/doc/manual.six", + "pkg/jupyterviz/doc/manual.six", + "pkg/kan/doc/manual.six", + "pkg/kbmag/doc/manual.six", + "pkg/laguna/doc/manual.six", + "pkg/liealgdb/doc/manual.six", + "pkg/liepring/doc/manual.six", + "pkg/liering/doc/manual.six", + "pkg/linearalgebraforcap/doc/manual.six", + "pkg/lins/doc/manual.six", + "pkg/localizeringforhomalg/doc/manual.six", + "pkg/localnr/doc/manual.six", + "pkg/loops/doc/manual.six", + "pkg/lpres/doc/manual.six", + "pkg/majoranaalgebras/doc/manual.six", + "pkg/mapclass/doc/manual.six", + "pkg/matgrp/doc/manual.six", + "pkg/matricesforhomalg/doc/manual.six", + "pkg/modisom/doc/manual.six", + "pkg/modulargroup/doc/manual.six", + "pkg/modulepresentationsforcap/doc/manual.six", + "pkg/modules/doc/manual.six", + "pkg/monoidalcategories/doc/manual.six", + "pkg/nconvex/doc/manual.six", + "pkg/nilmat/doc/manual.six", + "pkg/nock/doc/manual.six", + "pkg/nofoma/doc/manual.six", + "pkg/normalizinterface/doc/manual.six", + "pkg/nq/doc/manual.six", + "pkg/numericalsgps/doc/manual.six", + "pkg/openmath/doc/manual.six", + "pkg/orb/doc/manual.six", + "pkg/origami/doc/manual.six", + "pkg/packagemaker/doc/manual.six", + "pkg/packagemanager/doc/manual.six", + "pkg/patternclass/doc/manual.six", + "pkg/permut/doc/manual.six", + "pkg/polenta/doc/manual.six", + "pkg/polycyclic/doc/manual.six", + "pkg/polymaking/doc/manual.six", + "pkg/primgrp/doc/manual.six", + "pkg/profiling/doc/manual.six", + "pkg/qdistrnd/doc/manual.six", + "pkg/qpa/doc/manual.six", + "pkg/quagroup/doc/manual.six", + "pkg/radiroot/doc/manual.six", + "pkg/rcwa/doc/manual.six", + "pkg/rds/doc/manual.six", + "pkg/recog/doc/manual.six", + "pkg/repndecomp/doc/manual.six", + "pkg/repsn/doc/manual.six", + "pkg/resclasses/doc/manual.six", + "pkg/ringsforhomalg/doc/manual.six", + "pkg/sco/doc/manual.six", + "pkg/scscp/doc/manual.six", + "pkg/semigroups/doc/manual.six", + "pkg/sglppow/doc/manual.six", + "pkg/sgpviz/doc/manual.six", + "pkg/simpcomp/doc/manual.six", + "pkg/singular/doc/manual.six", + "pkg/sl2reps/doc/manual.six", + "pkg/sla/doc/manual.six", + "pkg/smallantimagmas/doc/manual.six", + "pkg/smallclassnr/doc/manual.six", + "pkg/smallgrp/doc/manual.six", + "pkg/smallsemi/doc/manual.six", + "pkg/sonata/doc/ref/manual.six", + "pkg/sonata/doc/tut/manual.six", + "pkg/sophus/doc/manual.six", + "pkg/sotgrps/doc/manual.six", + "pkg/spinsym/doc/manual.six", + "pkg/standardff/doc/manual.six", + "pkg/symbcompcc/doc/manual.six", + "pkg/thelma/doc/manual.six", + "pkg/tomlib/doc/manual.six", + "pkg/toolsforhomalg/doc/manual.six", + "pkg/toric/doc/manual.six", + "pkg/transgrp/doc/manual.six", + "pkg/twistedconjugacy/doc/manual.six", + "pkg/typeset/doc/manual.six", + "pkg/ugaly/doc/manual.six", + "pkg/unipot/doc/manual.six", + "pkg/unitlib/doc/manual.six", + "pkg/utils/doc/manual.six", + "pkg/uuid/doc/manual.six", + "pkg/walrus/doc/manual.six", + "pkg/wedderga/doc/manual.six", + "pkg/wpe/doc/manual.six", + "pkg/xgap/doc/manual.six", + "pkg/xmod/doc/manual.six", + "pkg/xmodalg/doc/manual.six", + "pkg/yangbaxter/doc/manual.six", + "pkg/zeromqinterface/doc/manual.six" +] diff --git a/etc/emscripten/web-template/gap-fs.js b/etc/emscripten/web-template/gap-fs.js index f3a1467d42..ca8ea4f23d 100644 --- a/etc/emscripten/web-template/gap-fs.js +++ b/etc/emscripten/web-template/gap-fs.js @@ -1,3 +1,29 @@ +// Instrument fetch and XMLHttpRequest so the page can collect the list of +// URLs the worker actually requests, for rebuilding startup_manifest.json +// without scraping the browser network panel. Each unique URL is posted +// to the main thread as { type: "gap-fetched", url: ... }. +(function instrumentFetches() { + const seen = new Set(); + const report = (raw) => { + if (typeof raw !== "string") return; + if (seen.has(raw)) return; + seen.add(raw); + self.postMessage({ type: "gap-fetched", url: raw }); + }; + + const origFetch = self.fetch; + self.fetch = function(input, init) { + report(typeof input === "string" ? input : input && input.url); + return origFetch.apply(this, arguments); + }; + + const origOpen = XMLHttpRequest.prototype.open; + XMLHttpRequest.prototype.open = function(method, url) { + report(url); + return origOpen.apply(this, arguments); + }; +})(); + self.Module = self.Module || {}; self.Module.preRun = self.Module.preRun || []; @@ -43,8 +69,12 @@ self.Module.preRun.push(function() { if (p.startsWith('/')) p = p.substring(1); startupSet.add(p); }); + } else { + console.info("startup_manifest.json not present; falling back to fully lazy loading"); } - } catch (e) {} + } catch (e) { + console.warn("Failed to load startup_manifest.json:", e); + } var fetchPromises = fileList.map(async function(appPath) { var fetchRelativePath = appPath.split('/').map(encodeURIComponent).join('/'); @@ -58,16 +88,15 @@ self.Module.preRun.push(function() { FS.stat(idbfsPath); FS.writeFile(finalAppPath, FS.readFile(idbfsPath)); } catch (e) { - try { - const response = await fetch(fetchPath); - if (response.ok) { - const buffer = await response.arrayBuffer(); - const data = new Uint8Array(buffer); - FS.writeFile(finalAppPath, data); - FS.writeFile(idbfsPath, data); - needsSave = true; - } - } catch (fetchErr) {} + const response = await fetch(fetchPath); + if (!response.ok) { + throw new Error("Failed to fetch startup file " + fetchPath + ": " + response.status); + } + const buffer = await response.arrayBuffer(); + const data = new Uint8Array(buffer); + FS.writeFile(finalAppPath, data); + FS.writeFile(idbfsPath, data); + needsSave = true; } } else { var parts = appPath.split('/'); diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index b51df45fb8..d5f1bec759 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -1,22 +1,185 @@ - + + - gap-wasm + + + GAP in the browser + -
+
+

GAP in the browser

+

+ A WebAssembly build of GAP + running entirely in your browser — useful for trying things out + without installing. Not all packages work, working memory is + capped, and performance is reduced compared to a native build. + For real work, install GAP from + www.gap-system.org. +

+
+ +
+ What is this? · Licensing +

+ GAP is a system for + computational discrete algebra, with particular emphasis on + computational group theory. This page is a self-contained + WebAssembly build, served as a static site and run inside a + Web Worker; you interact with it through an + xterm-pty + terminal in the page below. +

+

+ To get started, try 1+1;, + Factorial(20);, or SymmetricGroup(5);. + The full GAP + manuals apply, with two caveats: some packages won't load + (anything that needs a native compiler or system library), and + anything that wants the local filesystem won't work. +

+

+ Files downloaded on first visit are cached in your browser's + IndexedDB, so subsequent visits start much faster. Clear the + site data to reset the cache. +

+

+ GAP is free software, distributed under the + GNU General Public License (version 2 or + later). See the copyright notice for + the full statement. +

+
+ +
+ Loading GAP… The first visit downloads several tens of megabytes; + subsequent visits are cached in your browser and load much faster. +
+ +
+ This page needs SharedArrayBuffer, which is only + available when the page is served with the headers + Cross-Origin-Opener-Policy: same-origin and + Cross-Origin-Embedder-Policy: require-corp. The + bundled service worker handles this on hosts where you can't set + headers (e.g. GitHub Pages); for local hosting use + etc/emscripten/serve.py. +
+ +
+
+
+ + + From a5bacfe6e8d333d3cfe0a3873a2aa644e8bd3530 Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Sun, 31 May 2026 16:23:13 +0800 Subject: [PATCH 2/2] gasman: use __EMSCRIPTEN__ to guard emscripten GC support GASMAN's emscripten_scan_stack/emscripten_scan_registers calls -- which spill pointers held in wasm registers so the conservative collector can see them -- were guarded by `#ifdef EMSCRIPTEN`. Older emscripten defined the bare `EMSCRIPTEN` macro, so the block compiled and worked; modern emscripten removed it in favour of `__EMSCRIPTEN__`, which silently disabled the block. Without the register scan, the fallback stack scan misses roots that live only in registers, so live bags are freed and the heap is corrupted (observed as "index out of bounds" / "corrupted its heap memory area" aborts on a recent emsdk). Update the guard to the modern macro. AI assistance: Claude Code (Opus 4.8) diagnosed and made this change. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/gasman.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gasman.c b/src/gasman.c index 6712ebec79..7a616d6eb6 100644 --- a/src/gasman.c +++ b/src/gasman.c @@ -129,7 +129,7 @@ #include #include -#ifdef EMSCRIPTEN +#ifdef __EMSCRIPTEN__ #include #endif @@ -1957,7 +1957,7 @@ static NOINLINE void GenStackFuncBags(void) DisableMarkBagValidation = 1; #endif -#ifdef EMSCRIPTEN +#ifdef __EMSCRIPTEN__ emscripten_scan_stack(ScanRange); emscripten_scan_registers(ScanRange); // The standard scanning may not be required with