Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
7bae65d
M0: add ARCHITECTURE.md
pgousdal Oct 5, 2026
ef6ef6c
M0: add pyproject.toml
pgousdal Oct 5, 2026
bec5422
M0: add src/retroasset/__init__.py
pgousdal Oct 5, 2026
a947e13
M0: add src/retroasset/model.py
pgousdal Oct 5, 2026
0a35dcc
M0: add src/retroasset/targets.py
pgousdal Oct 5, 2026
2ea2ae9
M0: add src/retroasset/cli.py
pgousdal Oct 5, 2026
7c3380c
M0: add examples/amiga-ocs-sprite.json
pgousdal Oct 5, 2026
ab0224c
M0: add tests/test_targets.py
pgousdal Oct 5, 2026
84b6cd1
M0: add .github/workflows/ci.yml
pgousdal Oct 5, 2026
0e372c5
M0: add LICENSE
pgousdal Oct 5, 2026
3a09351
M0: document RetroAsset foundation
pgousdal Oct 5, 2026
1edf37b
M0.1: add src/retroasset/profiles.py
pgousdal Oct 5, 2026
c5954ef
M0.1: add src/retroasset/character.py
pgousdal Oct 5, 2026
3aa4fc8
M0.1: add examples/ansi-cp437-screen.json
pgousdal Oct 5, 2026
723981f
M0.1: add tests/test_profiles.py
pgousdal Oct 5, 2026
99893bb
M0.1: add tests/test_character.py
pgousdal Oct 5, 2026
55daa40
M0.1: make validation profile-driven
pgousdal Oct 5, 2026
d199770
M0.1: expose target profiles in CLI
pgousdal Oct 5, 2026
a85b172
M0.1: exercise raster and character profiles in CI
pgousdal Oct 5, 2026
6447888
M0.2: add src/retroasset/indexed.py
pgousdal Oct 6, 2026
634287f
M0.2: add src/retroasset/amiga.py
pgousdal Oct 6, 2026
ad8bcfa
M0.2: add examples/amiga-ocs-checker.json
pgousdal Oct 6, 2026
8e12576
M0.2: add tests/test_amiga.py
pgousdal Oct 6, 2026
0b5452f
M0.2: add native ILBM export command
pgousdal Oct 6, 2026
be03690
M0.2: smoke-test ILBM export
pgousdal Oct 6, 2026
91483ba
M0.3: add src/retroasset/exporters.py
pgousdal Oct 6, 2026
3cb644b
M0.3: add tests/test_exporters.py
pgousdal Oct 6, 2026
dca9044
M0.3: add planar and ILBM round-trip decoding
pgousdal Oct 6, 2026
4b703fa
M0.3: test ILBM round trip
pgousdal Oct 6, 2026
15ac993
M0.3: expose raw C and ASM exporters
pgousdal Oct 6, 2026
271de87
M0.4: add ByteRun1 encoding and compressed ILBM
pgousdal Oct 6, 2026
30aad23
M0.4: add native CP437 ANSI writer
pgousdal Oct 6, 2026
0db543c
M0.4: test ByteRun1 and compressed ILBM
pgousdal Oct 6, 2026
6ac7189
M0.4: test native ANSI output
pgousdal Oct 6, 2026
b0769ab
M0.4: add native ANSI fixture
pgousdal Oct 6, 2026
c1503db
M0.5: add ANSI SGR subset parser
pgousdal Oct 6, 2026
eeee16e
M0.5: add native C64 screen representation
pgousdal Oct 6, 2026
c36c77b
M0.5: add C64 screen and PETSCII profiles
pgousdal Oct 6, 2026
4f4a2ab
M0.5: add ANSI round-trip test
pgousdal Oct 6, 2026
4111efa
M0.5: test native C64 screen/color RAM export
pgousdal Oct 6, 2026
15e6f24
M0.6: add explicit PETSCII screen-code mapping
pgousdal Oct 6, 2026
d83da3e
M0.6: add SAUCE metadata codec
pgousdal Oct 6, 2026
c5b6796
M0.6: test PETSCII mapping rules
pgousdal Oct 6, 2026
4760191
M0.6: test SAUCE round trip
pgousdal Oct 6, 2026
1b8e2c6
M0.7: add PETSCII stream state machine
pgousdal Oct 6, 2026
b32e923
M0.7: add first deterministic C64 PRG viewer
pgousdal Oct 6, 2026
f4522cb
M0.7: test PETSCII state and C64 PRG structure
pgousdal Oct 6, 2026
eb1ec36
M0.7: document 6502 copy-loop branch displacement
pgousdal Oct 6, 2026
01cda80
M0.8: document verified C64 PRG address layout
pgousdal Oct 6, 2026
ce9162e
M0.8: add byte-exact C64 PRG layout tests
pgousdal Oct 6, 2026
c9cc15d
M0.8: separate emulator qualification workflow
pgousdal Oct 6, 2026
85c3b60
M0.8: document runtime qualification boundary
pgousdal Oct 6, 2026
fd6f978
M0.9: add deterministic C64 qualification fixture
pgousdal Oct 6, 2026
754bdb3
M0.9: add VICE monitor memory dump script
pgousdal Oct 6, 2026
4abce90
M0.9: verify VICE RAM dumps against source fixture
pgousdal Oct 6, 2026
dd87140
M0.9: run generated C64 PRG under VICE and verify RAM
pgousdal Oct 6, 2026
449ed23
M0.9: qualify C64 with redistributable Open ROMs
pgousdal Oct 6, 2026
bd12cd3
M0.9: discover Open ROMs qualification firmware
pgousdal Oct 6, 2026
e209bf3
M0.9: install libpng headers for Open ROMs build
pgousdal Oct 6, 2026
7344376
M0.9: fix C64 BASIC next-line pointer
pgousdal Oct 6, 2026
89a0863
M0.9: assert valid BASIC end-marker pointer
pgousdal Oct 6, 2026
b3a9b80
M0.9: load C64 PRG directly in VICE monitor
pgousdal Oct 6, 2026
5f5ee2c
M0.9: bypass drive ROMs in C64 qualification
pgousdal Oct 6, 2026
a94f37e
M0.9: trigger direct-monitor C64 qualification
pgousdal Oct 6, 2026
819ed4f
M0.9: actually remove VICE autostart dependency
pgousdal Oct 6, 2026
40bcbaf
M0.9: bound C64 viewer copies to visible 1000 cells
pgousdal Oct 6, 2026
77d4f96
M0.9: test bounded C64 viewer layout
pgousdal Oct 6, 2026
83352c1
M0.9: stop VICE at bounded viewer completion
pgousdal Oct 6, 2026
5a1dab7
M0.9: dump raw C64 RAM evidence with bsave
pgousdal Oct 6, 2026
ba5ed7e
M0.9: disable VICE sound in headless qualification
pgousdal Oct 6, 2026
f238b9c
M0.9: dump C64 RAM after completion breakpoint
pgousdal Oct 6, 2026
e0c41f5
M0.9: use inclusive VICE bsave ranges
pgousdal Oct 6, 2026
9ed03a3
M0.9: record C64 VICE runtime qualification PASS
pgousdal Oct 6, 2026
9c70428
M0.4: decode ByteRun1 ILBM rows
pgousdal Oct 6, 2026
61c4837
M0.4: test compressed ILBM round trip
pgousdal Oct 6, 2026
5b2dc20
M0.4: expose ByteRun1 ILBM compression in CLI
pgousdal Oct 6, 2026
ef7bec5
M0.4: record ByteRun1 round-trip PASS
pgousdal Oct 6, 2026
df562ea
M0.4: add Amiga ILBM qualification fixtures
pgousdal Oct 6, 2026
b8b3c2f
M0.4: qualify ILBM with independent consumer
pgousdal Oct 6, 2026
0f45e7d
M0.4: record independent ILBM interoperability PASS
pgousdal Oct 6, 2026
a40b2d7
M0.5: add independent m68k ILBM guest verifier
pgousdal Oct 6, 2026
7efa00f
M0.5: smoke-test standalone ILBM verifier
pgousdal Oct 6, 2026
91f901d
M0.5: add generated ILBM fixture embedder
pgousdal Oct 6, 2026
288fed0
M0.5: support embedded ILBM guest fixtures
pgousdal Oct 6, 2026
3c35282
M0.5: add AROS m68k runtime contract
pgousdal Oct 6, 2026
e217e43
M0.5: smoke-test embedded Amiga guest payload
pgousdal Oct 6, 2026
8a35cd1
M0.5: preserve const data in embedded ILBM verifier
pgousdal Oct 6, 2026
16fbf7e
M0.5: build Amiga m68k Q1 runtime payload
pgousdal Oct 6, 2026
ff4986a
M0.5: fix m68k payload container output
pgousdal Oct 6, 2026
87f9b53
M0.5: make Q1 payload output runner-writable
pgousdal Oct 6, 2026
5d13bae
M0.5: run ILBM verifier in AROS m68k guest
pgousdal Oct 6, 2026
80278ca
M0.5: record Amiga AROS m68k Q3 qualification PASS
pgousdal Oct 6, 2026
c8138f5
M0.8: verify exact Amiga ILBM pixels and palette
pgousdal Oct 6, 2026
4719ee4
M0.8: record exact-content Amiga Q3 PASS
pgousdal Oct 6, 2026
6ebc8d9
M0.2: complete Amiga asset readiness validator
pgousdal Oct 6, 2026
09739a4
M0.2: test Amiga target readiness and metadata
pgousdal Oct 6, 2026
bb7efaf
OCI: add Alpine runtime image
pgousdal Oct 6, 2026
61808ff
OCI: smoke-test Alpine image in CI
pgousdal Oct 6, 2026
bec4263
OCI: add multiarch GHCR publishing
pgousdal Oct 6, 2026
5cb49d3
OCI: document container contract and distribution
pgousdal Oct 6, 2026
3427002
M0.5: add ANSI character import/export CLI
pgousdal Oct 6, 2026
895f777
M0.5: test ANSI CLI round trip
pgousdal Oct 6, 2026
f57a509
M0.5: preserve SAUCE metadata in character CLI
pgousdal Oct 6, 2026
953ec07
M0.5: test SAUCE CLI preservation
pgousdal Oct 6, 2026
910156e
M0.6: expose native C64 screen exports in CLI
pgousdal Oct 6, 2026
3ff012f
M0.6: test C64 native CLI exports
pgousdal Oct 6, 2026
4b657d3
M0.6: add PETSCII stream import CLI
pgousdal Oct 6, 2026
8be66b9
M0.6: test PETSCII control-state import
pgousdal Oct 6, 2026
9694b05
M0.6: add machine-readable conversion reports
pgousdal Oct 7, 2026
299e3b3
M0.6: expose character conversion reports in CLI
pgousdal Oct 7, 2026
3bd2323
M0.6: test machine-readable conversion report
pgousdal Oct 7, 2026
be5b8a3
OCI: restrict publishing to main and release tags
pgousdal Oct 7, 2026
1794558
OCI: create stable work directories
pgousdal Oct 7, 2026
d5904ed
OCI: add minimal Docker build context
pgousdal Oct 7, 2026
d83a16b
Release: set M0 version to 0.1.0
pgousdal Oct 7, 2026
2c52cde
Docs: mark RetroAsset 0.1.0 release-ready
pgousdal Oct 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.git
.github
__pycache__
*.py[cod]
*.egg-info
.pytest_cache
.venv
venv
dist
build
tests
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install -e .
- run: python -m unittest discover -s tests -v
- run: retroasset targets
- run: retroasset profile amiga-ocs
- run: retroasset profile ansi-cp437
- run: retroasset validate examples/amiga-ocs-sprite.json
- run: retroasset validate examples/ansi-cp437-screen.json
- run: retroasset export examples/amiga-ocs-checker.json --target amiga-ocs --format ilbm -o /tmp/checker.ilbm
- run: test -s /tmp/checker.ilbm
- name: Build OCI image
run: docker build -t retroasset:test .
- name: Smoke-test OCI CLI
run: docker run --rm retroasset:test targets
- name: Smoke-test OCI native export
run: |
mkdir -p /tmp/retroasset-oci
chmod 777 /tmp/retroasset-oci
docker run --rm \
-v "$PWD/examples:/work/input:ro" \
-v "/tmp/retroasset-oci:/work/output" \
retroasset:test export /work/input/amiga-ocs-checker.json \
--target amiga-ocs --format ilbm -o /work/output/checker.ilbm
test -s /tmp/retroasset-oci/checker.ilbm
42 changes: 42 additions & 0 deletions .github/workflows/oci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: OCI

on:
push:
branches: [main]
tags: ["v*"]
workflow_dispatch:

permissions:
contents: read
packages: write

jobs:
publish:
# Manual runs must not turn feature branches into published package sources.
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
with:
images: ghcr.io/ploos-as/retroasset
tags: |
type=sha,prefix=sha-
type=raw,value=edge,enable=${{ github.ref == 'refs/heads/main' }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
196 changes: 196 additions & 0 deletions .github/workflows/qualification.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
name: Emulator qualification

on:
workflow_dispatch:
push:
branches: [m0-foundation]
paths:
- "src/retroasset/c64prg.py"
- "src/retroasset/petscii.py"
- "src/retroasset/amiga.py"
- "qualification/**"
- ".github/workflows/qualification.yml"

jobs:

amiga-m68k-q1:
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: python -m pip install -e .
- name: Generate and embed ILBM fixtures
run: |
python qualification/generate_amiga_fixtures.py
python qualification/embed_amiga_fixtures.py
- name: Pull qualified Amiga development environment
run: docker pull ghcr.io/ploos-as/amiga-dev:edge
- name: Cross-build m68k guest verifier
run: |
mkdir -p qualification/runtime-input
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$PWD:/workspace:ro" \
-v "$PWD/qualification/runtime-input:/output" \
-w /workspace \
ghcr.io/ploos-as/amiga-dev:edge \
sh -ec 'amiga-check && m68k-amigaos-gcc -m68000 -Os -Wall -Wextra -Werror -DRETROASSET_EMBEDDED_FIXTURES qualification/amiga/ilbm_verify.c -o /tmp/ilbm-verify && file /tmp/ilbm-verify | tee /tmp/ilbm-file.txt && grep -Fq "AmigaOS loadseg()ble executable/binary" /tmp/ilbm-file.txt && cp /tmp/ilbm-verify /output/ilbm-verify'
cp qualification/amiga/amiga-runtime.json qualification/runtime-input/amiga-runtime.json
test -s qualification/runtime-input/ilbm-verify
test -s qualification/runtime-input/amiga-runtime.json
- name: Upload Q1 runtime payload
uses: actions/upload-artifact@v4
with:
name: retroasset-amiga-m68k-q1
path: qualification/runtime-input/
if-no-files-found: error


amiga-aros-q3:
needs: amiga-m68k-q1
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
env:
AMIGA_RUNTIME_IMAGE: ghcr.io/ploos-as/amiga-runtime:sha-fd7cc88
steps:
- name: Download Q1 payload
uses: actions/download-artifact@v4
with:
name: retroasset-amiga-m68k-q1
path: runtime-input
- name: Verify project contract
run: |
test -s runtime-input/amiga-runtime.json
jq -e '.schema == 1 and .architecture == "m68k"' runtime-input/amiga-runtime.json >/dev/null
- name: Pull immutable Amiga runtime
run: docker pull "$AMIGA_RUNTIME_IMAGE"
- name: Prepare AROS/m68k runtime
run: |
mkdir -p runtime-evidence runtime-aros
docker run --rm \
-v "$PWD/runtime-aros:/work/aros" \
-e AROS_RUNTIME_DIR=/work/aros \
"$AMIGA_RUNTIME_IMAGE" prepare-aros | tee runtime-evidence/aros-prepare.log
grep -Fq 'AROS m68k runtime prepared: PASS' runtime-evidence/aros-prepare.log
- name: Qualify RetroAsset ILBM payload in AROS/m68k
run: |
docker run --rm \
-v "$PWD/runtime-input:/work/input:ro" \
-v "$PWD/runtime-evidence:/work/evidence" \
-v "$PWD/runtime-aros:/work/aros" \
-e AROS_RUNTIME_DIR=/work/aros \
"$AMIGA_RUNTIME_IMAGE" qualify-contract /work/input --profile a1200-020-aros
- name: Upload AROS qualification evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: retroasset-amiga-aros-q3-evidence
path: runtime-evidence/
if-no-files-found: warn

c64-structural:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install -e .
- run: python -m unittest tests.test_c64prg tests.test_c64prg_layout -v
- run: python qualification/generate_c64_fixture.py
- uses: actions/upload-artifact@v4
with:
name: retroasset-c64-fixture
path: qualification/generated/

c64-vice-open-roms:
runs-on: ubuntu-latest
needs: c64-structural
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install -e .
- run: python qualification/generate_c64_fixture.py
- name: Install VICE and Open ROMs build dependencies
run: |
sudo apt-get update
sudo apt-get install -y vice git make gcc libpng-dev
x64sc --version
- name: Build redistributable C64 Open ROMs
run: |
git clone --depth 1 https://github.com/MEGA65/open-roms.git /tmp/open-roms
make -C /tmp/open-roms
find /tmp/open-roms/bin -maxdepth 1 -type f -print
- name: Locate Open ROMs
run: |
python qualification/find_open_roms.py /tmp/open-roms/bin qualification/generated/roms.env
cat qualification/generated/roms.env
- name: Run VICE qualification with Open ROMs
run: |
set -a
. qualification/generated/roms.env
set +a
xvfb-run -a x64sc \
-basic "$RETROASSET_BASIC_ROM" \
-kernal "$RETROASSET_KERNAL_ROM" \
-chargen "$RETROASSET_CHARGEN_ROM" \
-moncommands qualification/vice-monitor.txt \
-console
- name: Verify emulated RAM
run: python qualification/verify_c64.py
- uses: actions/upload-artifact@v4
if: always()
with:
name: retroasset-c64-vice-open-roms-evidence
path: qualification/generated/

amiga-ilbm-consumer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install -e .
- run: python -m unittest tests.test_amiga -v
- run: python qualification/generate_amiga_fixtures.py
- name: Build standalone ILBM verifier
run: |
cc -std=c99 -Wall -Wextra -Werror -O2 qualification/amiga/ilbm_verify.c -o qualification/generated/ilbm-verify-host
qualification/generated/ilbm-verify-host qualification/generated/amiga-uncompressed.ilbm qualification/generated/amiga-byterun1.ilbm | tee qualification/generated/ilbm-verify-host.log
grep -Fq 'RETROASSET_ILBM_UNCOMPRESSED_PASS' qualification/generated/ilbm-verify-host.log
grep -Fq 'RETROASSET_ILBM_BYTERUN1_PASS' qualification/generated/ilbm-verify-host.log
- name: Smoke-test embedded guest payload mode
run: |
python qualification/embed_amiga_fixtures.py
cc -std=c99 -Wall -Wextra -Werror -O2 -DRETROASSET_EMBEDDED_FIXTURES qualification/amiga/ilbm_verify.c -o qualification/generated/ilbm-verify-embedded-host
qualification/generated/ilbm-verify-embedded-host | tee qualification/generated/ilbm-verify-embedded-host.log
grep -Fq 'RETROASSET_ILBM_UNCOMPRESSED_PASS' qualification/generated/ilbm-verify-embedded-host.log
grep -Fq 'RETROASSET_ILBM_BYTERUN1_PASS' qualification/generated/ilbm-verify-embedded-host.log
- name: Install independent ILBM consumer
run: |
sudo apt-get update
sudo apt-get install -y imagemagick
convert -version
- name: Decode generated ILBM files independently
run: |
identify qualification/generated/amiga-uncompressed.ilbm
identify qualification/generated/amiga-byterun1.ilbm
convert qualification/generated/amiga-uncompressed.ilbm qualification/generated/amiga-uncompressed.ppm
convert qualification/generated/amiga-byterun1.ilbm qualification/generated/amiga-byterun1.ppm
test -s qualification/generated/amiga-uncompressed.ppm
test -s qualification/generated/amiga-byterun1.ppm
- uses: actions/upload-artifact@v4
if: always()
with:
name: retroasset-amiga-ilbm-consumer-evidence
path: qualification/generated/
25 changes: 25 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# RetroAsset architecture

RetroAsset is an AI-assisted compiler/toolchain for native retro-computing assets.

## Design principles

1. **Hardware-authentic output.** A preview that looks retro is not sufficient; target validators decide whether an asset is valid.
2. **Provider-independent AI.** Generation is an optional source stage. The core pipeline must work without any AI service.
3. **Deterministic compilation.** Given a source asset, manifest and tool version, conversion and validation should be reproducible.
4. **Targets own constraints.** Machine-specific rules live in target profiles and validators, not in the generic image pipeline.
5. **Native output first.** PNG/SVG may be previews; ILBM, planar data, character cells and other native forms are first-class outputs.

## Pipeline

source -> import/generate -> RetroAsset IR -> transform -> target validator -> exporter -> native asset

## Target families

- raster: Amiga OCS/ECS/AGA, later Atari ST, EGA/VGA and Mac68k
- character: ANSI/CP437, PETSCII, ATASCII
- tile/sprite: machine-specific tile, Bob and sprite representations

## M0

M0 establishes the IR/manifest, CLI, target registry, Amiga OCS baseline validator and character-art extension points. AI backends are intentionally deferred.
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3.12-alpine

LABEL org.opencontainers.image.source="https://github.com/Ploos-AS/RetroAsset"
LABEL org.opencontainers.image.description="RetroAsset native retro-asset compiler and validator"
LABEL org.opencontainers.image.licenses="MIT"

WORKDIR /app
COPY pyproject.toml README.md LICENSE ./
COPY src ./src
RUN pip install --no-cache-dir . \
&& addgroup -S retroasset \
&& adduser -S -G retroasset retroasset

RUN mkdir -p /work/input /work/output \
&& chown retroasset:retroasset /work/output

WORKDIR /work
USER retroasset
ENTRYPOINT ["retroasset"]
CMD ["--help"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Ploos AS

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading