diff --git a/.gitattributes b/.gitattributes index e539c858..98c18627 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,8 @@ **/.git* annex.largefiles=nothing * annex.largefiles=((mimeencoding=binary)and(largerthan=0)) *.svg annex.largefiles=(largerthan=100K) +# Preserve the storage rule for the original SVG in this branch's history. +2026-usrse/orinoco-lite-poster.svg annex.largefiles=nothing +# Preserve the original Git-stored logo in PR history; the relocated asset +# under 2026-usrse/orinoco-lite/assets/ follows the normal SVG annex rule. +pics/con-logo-outlined.svg annex.largefiles=nothing diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0b40b2df..2f588683 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,4 +7,4 @@ repos: rev: v0.9.1 hooks: - id: snapper - files: ^2026-usrse/stamped-abcd-poster-draft\.md$ + files: ^2026-usrse/(stamped-abcd-poster-draft|orinoco-lite/README)\.md$ diff --git a/2026-usrse/Makefile b/2026-usrse/Makefile index c03928c4..9fdca52d 100644 --- a/2026-usrse/Makefile +++ b/2026-usrse/Makefile @@ -12,6 +12,7 @@ # make pdf -- builds .pdf for every *.md (needs a PDF engine) # make html -- explicit alias for the default # make diagram -- rebuilds the Orinoco metadata-flow figure +# make poster -- prints the editable Orinoco poster HTML to PDF # make proposal -- just 2026-usrse-con-talk-abstract.html + 2026-usrse-con-talk-abstract.pdf # make clean -- remove generated *.html / *.pdf # @@ -77,7 +78,7 @@ stamped-abcd-poster-draft.pdf: PDF_LATEX_OPTS := $(subst fontsize=11pt,fontsize= # PDF via HTML (wkhtmltopdf / weasyprint) — same look as the HTML render PDF_HTML_OPTS := --to html5 --css=https://cdn.jsdelivr.net/npm/water.css@2/out/water.css -.PHONY: all html pdf diagram proposal clean help check +.PHONY: all html pdf diagram proposal poster clean help check all: pdf @@ -87,6 +88,12 @@ pdf: $(PDFS) diagram: orinoco-metadata-flow.png +# Browser setup: uv run --with playwright playwright install chromium +# Or use POSTER_BROWSER_ARGS='--channel chrome' for installed Google Chrome. +POSTER_BROWSER_ARGS ?= +poster: + uv run --with playwright python orinoco-lite/build-poster.py $(POSTER_BROWSER_ARGS) + proposal: 2026-usrse-con-talk-abstract.html 2026-usrse-con-talk-abstract.pdf orinoco-metadata-flow.png: orinoco-metadata-flow.mmd diff --git a/2026-usrse/README.md b/2026-usrse/README.md index 0e926749..d9afc27a 100644 --- a/2026-usrse/README.md +++ b/2026-usrse/README.md @@ -1,5 +1,8 @@ This is folder to collect ideas/drafts for submissions for https://us-rse.org/usrse26/ as described on https://us-rse.org/usrse26/participate/ . +The Orinoco Lite poster is available as [editable poster](orinoco-lite_poster.html), with [editing, PDF export and release notes](orinoco-lite/README.md). +Its [submitted abstract](orinoco-lite-poster-draft.md) remains alongside it. + ### Meeting theme etc That meeting is about/for Software Research Engineers. And this particular meeting has following @@ -46,4 +49,3 @@ scientific fields. So, it would be great to alert audience to our efforts and efforts of our collaborators (like https://www.distribits.live/ conference etc). - diff --git a/2026-usrse/orinoco-lite/README.md b/2026-usrse/orinoco-lite/README.md new file mode 100644 index 00000000..01a6211d --- /dev/null +++ b/2026-usrse/orinoco-lite/README.md @@ -0,0 +1,180 @@ +# ORINOCO Lite poster + +The editable source is [../orinoco-lite_poster.html](../orinoco-lite_poster.html). +It preserves the title, presenter order and comparison in the [accepted abstract](../orinoco-lite-poster-draft.md). + +## Editing and rebuilding + +Open the HTML in a browser to view it, or edit it in any text editor. +Text is ordinary HTML, colors and layout are in the opening ` +

Compare the poster's printed text sizes

+

Print this US Letter page at Actual size / 100%. + Do not use “Fit to page”. Read it from the distance you expect at the poster, + around one metre, and choose a size that is comfortable without leaning in. + The wording, font family, line spacing and colors match the poster; + this sheet uses narrower lines to fit ordinary paper.

+ {blocks} +

This line should measure exactly 2 inches (50.8 mm).

+

PosterNerd recommends at least 24 pt for text and 36 pt for headings. + Current main paragraphs are {body_pt:g} pt. + Source: posternerd.com/tutorials/customer-questions

+ ''') + proof = Path(__file__).with_name('font-proof.pdf') + await page.pdf(path=str(proof), print_background=True, prefer_css_page_size=True, + display_header_footer=False) + print(f"Created {proof}") + await browser.close() + print(f"Created {output} ({output.stat().st_size / 1e6:.2f} MB)") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--channel", help="Browser channel, e.g. chrome; default: Playwright Chromium") + parser.add_argument("--preview", type=Path, help="Optional PNG preview path") + parser.add_argument("--font-proof", action="store_true", help="Also export a printable Letter-size type comparison") + args = parser.parse_args() + asyncio.run(build(args.channel, args.preview, args.font_proof)) diff --git a/2026-usrse/orinoco-lite/make-component-diagram.py b/2026-usrse/orinoco-lite/make-component-diagram.py new file mode 100644 index 00000000..ef2d6a94 --- /dev/null +++ b/2026-usrse/orinoco-lite/make-component-diagram.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Center for Open Neuroscience +# SPDX-License-Identifier: Apache-2.0 +"""Adapt Stephan Heunis's ORINOCO component artwork for the Lite deployment. + +Run from any directory with Python 3. The source illustration remains unchanged. +The output is a self-contained SVG; its new labels remain ordinary editable text. +""" +from copy import deepcopy +from pathlib import Path +import xml.etree.ElementTree as ET + +SVG = "http://www.w3.org/2000/svg" +XLINK = "http://www.w3.org/1999/xlink" +ET.register_namespace("", SVG) +ET.register_namespace("xlink", XLINK) +ROOT = Path(__file__).resolve().parent +SOURCE = ROOT / "assets/orinoco-selfhost-components-poster.svg" +OUTPUT = ROOT / "assets/orinoco-lite-components-poster.svg" + + +def main(): + source = ET.parse(SOURCE).getroot() + diagram = ET.Element(f"{{{SVG}}}svg", { + "viewBox": "0 0 678.08 304.58", "width": "678.08", "height": "304.58", + "role": "img", "aria-labelledby": "lite-title lite-description", + }) + ET.SubElement(diagram, f"{{{SVG}}}title", {"id": "lite-title"}).text = "ORINOCO Lite components" + ET.SubElement(diagram, f"{{{SVG}}}desc", {"id": "lite-description"}).text = ( + "A shared schema defines the SHACL Vue editor. The editor proposes changes " + "through the shared App to GitHub pull requests. Reviewers merge accepted " + "changes into Git-backed YAML records. GitHub Actions runs ORINOCO tools to " + "build reusable outputs, illustrated by a catalog, website and report. " + "Adapted from ORINOCO artwork by Stephan Heunis, CC BY 4.0." + ) + defs = deepcopy(source.find(f"{{{SVG}}}defs")) + diagram.append(defs) + marker = ET.SubElement(defs, f"{{{SVG}}}marker", { + "id": "lite-arrowhead", "viewBox": "0 0 10 10", "refX": "9", "refY": "5", + "markerWidth": "5", "markerHeight": "5", "orient": "auto-start-reverse", + }) + ET.SubElement(marker, f"{{{SVG}}}path", {"d": "M 1 1 L 9 5 L 1 9", "fill": "none", "stroke": "#009900", "stroke-width": "1.6"}) + # Keep the original schema, editor, processing and output artwork in place. + # Remove Forgejo, Dump Things, and the old integration/storage arrows. + removed = { + "g6835", # Forgejo + "g1", # Dump Things truck, logo and label + "layer1-5-3-1-8-5-3-2", "layer1-5-3-1-8-5-3-2-7", # editor/storage pair + "g36094", "g36094-2", # Forgejo integration pairs + "g34511-8", # schema arrow; its replacement leads directly to the editor + } + scale = ET.SubElement(diagram, f"{{{SVG}}}g", {"transform": "scale(3.7795275591)"}) + layer = deepcopy(source.find(f"{{{SVG}}}g")) + for child in list(layer): + if child.get("id") in removed: + layer.remove(child) + scale.append(layer) + # Overlay coordinates use CSS pixels, corresponding to the original canvas. + overlay = ET.fromstring(''' + + + + + + + + defines + propose + via shared App + merge + build + + + + + + + + GitHub + pull requests + + + + + + + + + + Git + YAML + accepted records + + + GitHub Actions + ORINOCO tools + + ''') + diagram.append(overlay) + # Avoid following a git-annex symlink when regenerating a staged asset. + if OUTPUT.is_symlink(): + OUTPUT.unlink() + ET.ElementTree(diagram).write(OUTPUT, encoding="utf-8", xml_declaration=True) + print(f"Created {OUTPUT}") + + +if __name__ == "__main__": + main() diff --git a/2026-usrse/orinoco-lite/make-logo-qrs.py b/2026-usrse/orinoco-lite/make-logo-qrs.py new file mode 100644 index 00000000..38bf658d --- /dev/null +++ b/2026-usrse/orinoco-lite/make-logo-qrs.py @@ -0,0 +1,238 @@ +# SPDX-FileCopyrightText: 2026 Center for Open Neuroscience +# SPDX-License-Identifier: Apache-2.0 +# /// script +# requires-python = ">=3.11" +# dependencies = ["qrcode==8.2", "Pillow==11.3.0", "zxing-cpp==2.3.0"] +# /// +"""Generate the poster's eight vector QR codes and verify their destinations. + +Run with `uv run 2026-usrse/orinoco-lite/make-logo-qrs.py --check-dir /tmp/con-qr-checks`. +Requires Inkscape (only to measure the already outlined logo) and rsvg-convert +(for independent rasterization). SVG assets are written to assets/; check images and +the JSON report stay in --check-dir, outside the repository by default. +""" + +import argparse +import copy +import json +from pathlib import Path +import shutil +import subprocess +import tempfile +import xml.etree.ElementTree as ET + +from PIL import Image, ImageDraw, ImageFilter +import qrcode +import zxingcpp + + +ROOT = Path(__file__).resolve().parent +SVG = "http://www.w3.org/2000/svg" +INK = "#193c4d" +BORDER = 4 # Four completely clear modules on every side. +LOGO_WIDTH_FRACTION = 0.42 +DESTINATIONS = { + "upstream": "https://hub.psychoinformatics.de/orinoco/", + "lite": "https://github.com/ORINOCO-Lite", + "con": "https://dev.centerforopenneuroscience.org/", + "graph": "https://dev.centerforopenneuroscience.org/explore/", + "poster": "https://doi.org/10.5281/zenodo.22834595", + "video": ( + "https://datasets.datalad.org/repronim/ReproTube/web/" + "#/channel/DataLad/video/oF98hdaph1k" + ), + "psychoinformatics": "https://www.psychoinformatics.de/", + "workflow": "https://github.com/con/dev-centerforopenneuroscience.org/pulls?q=is%3Apr+head%3Acuration%2Fshacl-vue-", +} +ET.register_namespace("", SVG) + + +def element(tag, attrs=None, text=None): + node = ET.Element(f"{{{SVG}}}{tag}", attrs or {}) + node.text = text + return node + + +def load_logo(inkscape): + """Reuse the corrected paths and original blue; never regenerate its type.""" + source = ROOT / "assets/con-logo-outlined.svg" + original = ET.parse(source).getroot() + # The source retains hidden alternate artwork and wide canvas margins. + # Query the visible blue layer, then convert page-pixel bounds to its + # original SVG coordinates. Only our embedding viewport is cropped. + measured = subprocess.run( + [inkscape, str(source), "--query-id=layer1", "--query-x", "--query-y", + "--query-width", "--query-height"], + check=True, text=True, capture_output=True, + ) + x, y, width, height = map(float, measured.stdout.split()) + vx, vy, vw, vh = map(float, original.get("viewBox").split()) + scale_x = vw / float(original.get("width")) + scale_y = vh / float(original.get("height")) + # A tiny margin absorbs rounding in Inkscape's reported bounds. + margin = 0.05 + logo = element("svg", {"viewBox": ( + f"{vx+x*scale_x-margin:.6f} {vy+y*scale_y-margin:.6f} " + f"{width*scale_x+2*margin:.6f} {height*scale_y+2*margin:.6f}" + )}) + + def visible_copy(node): + if not node.tag.startswith(f"{{{SVG}}}"): + return None + if node.tag in {f"{{{SVG}}}{tag}" for tag in ("metadata", "title", "desc")}: + return None + if "display:none" in node.get("style", "").replace(" ", ""): + return None + result = ET.Element(node.tag, { + key: value for key, value in node.attrib.items() + if not key.startswith("{") # Drop editor-only namespaced metadata. + }) + for child in node: + copied = visible_copy(child) + if copied is not None: + result.append(copied) + return result + + for child in original: + copied = visible_copy(child) + if copied is not None: + logo.append(copied) + assert not logo.findall(f".//{{{SVG}}}text"), "Visible logo must be outlined" + assert not logo.findall(f".//{{{SVG}}}image"), "Logo must remain native vector" + return logo + + +def write_qr(name, url, logo): + qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H, + border=BORDER, box_size=1) + qr.add_data(url) + qr.make(fit=True) + modules = qr.get_matrix() + size = len(modules) + body_size = size - 2 * BORDER + assert all(not any(row) for row in modules[:BORDER] + modules[-BORDER:]) + assert all(not any(row[:BORDER] + row[-BORDER:]) for row in modules) + root = element("svg", { + "version": "1.1", "width": "45mm", "height": "45mm", + "viewBox": f"0 0 {size} {size}", "role": "img", + "aria-labelledby": "qr-title qr-description", + }) + root.append(element("title", {"id": "qr-title"}, f"CON QR code: {name}")) + root.append(element("desc", {"id": "qr-description"}, + f"{url}; high error correction; four-module quiet zone.")) + root.append(element("rect", {"width": str(size), "height": str(size), + "fill": "#ffffff"})) + # Combine consecutive dark cells into horizontal runs, retaining square + # module geometry and avoiding hairline seams between adjacent cells. + runs = [] + for y, row in enumerate(modules): + x = 0 + while x < size: + if not row[x]: + x += 1 + continue + start = x + while x < size and row[x]: + x += 1 + runs.append(f"M{start},{y}h{x-start}v1h-{x-start}z") + root.append(element("path", {"d": "".join(runs), "fill": INK})) + + _, _, logo_vw, logo_vh = map(float, logo.get("viewBox").split()) + logo_width = body_size * LOGO_WIDTH_FRACTION + logo_height = logo_width * logo_vh / logo_vw + padding = 1.0 + pad_width, pad_height = logo_width + 2 * padding, logo_height + 2 * padding + root.append(element("rect", { + "x": f"{(size-pad_width)/2:.6f}", "y": f"{(size-pad_height)/2:.6f}", + "width": f"{pad_width:.6f}", "height": f"{pad_height:.6f}", + "rx": "0.55", "fill": "#ffffff", + })) + logo_box = element("svg", { + "x": f"{(size-logo_width)/2:.6f}", "y": f"{(size-logo_height)/2:.6f}", + "width": f"{logo_width:.6f}", "height": f"{logo_height:.6f}", + "viewBox": logo.get("viewBox"), "preserveAspectRatio": "xMidYMid meet", + }) + for child in logo: + # Inkscape export may retain metadata/hidden layers; only SVG drawing + # content belongs in the embedded mark. + if not child.tag.startswith(f"{{{SVG}}}"): + continue + if child.tag in {f"{{{SVG}}}metadata", f"{{{SVG}}}title", f"{{{SVG}}}desc"}: + continue + if "display:none" in child.get("style", "").replace(" ", ""): + continue + logo_box.append(copy.deepcopy(child)) + root.append(logo_box) + assert not root.findall(f".//{{{SVG}}}text") + assert not root.findall(f".//{{{SVG}}}image"), "Logo must remain native vector" + destination = ROOT / f"assets/orinoco-qr-{name}.svg" + ET.ElementTree(root).write(destination, encoding="utf-8", xml_declaration=True) + assert destination.stat().st_size < 100_000, "QR should remain a small SVG" + return { + "name": name, "url": url, "file": str(destination), + "qr_version": qr.version, "error_correction": "H", + "modules_including_border": size, "quiet_border_modules": BORDER, + "logo_source": "assets/con-logo-outlined.svg", + "logo_width_fraction_of_body": LOGO_WIDTH_FRACTION, + "file_bytes": destination.stat().st_size, + "logo_pad_percent_of_body_area": round(100*pad_width*pad_height/body_size**2, 2), + } + + +def check_code(row, check_dir): + checks = [] + # 200–220 px cover the planned poster CSS sizes; 144/180 retain earlier + # screen-size checks. These are raster checks, not physical-camera scans. + # 177/266 px approximate 30/45 mm at + # 150 dpi; 354/531 px approximate 30/45 mm at 300 dpi. + for pixels in (144, 177, 180, 200, 210, 220, 240, 266, 354, 531, 720): + raster = check_dir / f"qr-{row['name']}-{pixels}px.png" + subprocess.run(["rsvg-convert", "-w", str(pixels), "-h", str(pixels), + "-o", str(raster), row["file"]], check=True) + image = Image.open(raster).convert("RGB") + variants = {"original": image, "rotated-90": image.transpose(Image.Transpose.ROTATE_90)} + if pixels >= 177: + variants["grayscale-softened"] = image.convert("L").filter(ImageFilter.GaussianBlur(0.35)) + variants["rotated-13"] = image.rotate( + 13, resample=Image.Resampling.BICUBIC, expand=True, fillcolor="white" + ) + for variant, candidate in variants.items(): + decoded = zxingcpp.read_barcodes(candidate) + ok = len(decoded) == 1 and decoded[0].text == row["url"] + checks.append({"pixels": pixels, "variant": variant, "passed": ok, + "decoded": [code.text for code in decoded]}) + row["checks"] = checks + return all(check["passed"] for check in checks) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check-dir", type=Path, + default=Path(tempfile.gettempdir()) / "con-qr-checks") + parser.add_argument("--inkscape", default=shutil.which("inkscape") or + "/Applications/Inkscape.app/Contents/MacOS/inkscape") + args = parser.parse_args() + args.check_dir.mkdir(parents=True, exist_ok=True) + logo = load_logo(args.inkscape) + report = [write_qr(name, url, logo) for name, url in DESTINATIONS.items()] + success = True + for row in report: + passed = check_code(row, args.check_dir) + success = passed and success + print(f"{row['name']}: version {row['qr_version']} / H; " + f"{sum(check['passed'] for check in row['checks'])}/" + f"{len(row['checks'])} decoding checks passed") + (args.check_dir / "decode-report.json").write_text(json.dumps(report, indent=2)+"\n") + overview = Image.new("RGB", (len(report)*360, 400), "white") + draw = ImageDraw.Draw(overview) + for i, row in enumerate(report): + image = Image.open(args.check_dir / f"qr-{row['name']}-354px.png") + overview.paste(image, (360*i+3, 5)) + draw.text((360*i+20, 370), row["name"], fill=INK) + overview.save(args.check_dir / "qr-overview.png") + if not success: + raise SystemExit("QR verification failed; inspect decode-report.json") + + +if __name__ == "__main__": + main() diff --git a/2026-usrse/orinoco-lite_poster.html b/2026-usrse/orinoco-lite_poster.html new file mode 100644 index 00000000..09296904 --- /dev/null +++ b/2026-usrse/orinoco-lite_poster.html @@ -0,0 +1,326 @@ + + + + + + Beyond the Lab Website: Reusing Structured Research Metadata Across Lab Operations + + + + + +
+
+
+
+

ORINOCO / ORINOCO Lite · US-RSE 2026

+

Beyond the Lab WebsiteReusing Structured Research Metadata
Across Lab Operations

+
+ +
+
+

John LeeIsaac ToYaroslav O. Halchenko

+

Center for Open Neuroscience
Psychological and Brain Sciences
Dartmouth College

+
+ QR code for the poster on ZenodoView this poster +
+
+ +
+

Who works on which project, and what has it produced? Labs repeatedly assemble these facts for websites, grants and reports. ORINOCO makes them a shared collection of structured, connected records that people, software and AI tools can use.

+

Deploy with dedicated services, or use our GitHub-based model with no services for your lab to deploy.We compare two ways to run the same metadata approach: the service deployment at Psychoinformatics and ORINOCO Lite at the Center for Open Neuroscience (CON).

+
+ +
+
+
+
+ +

ORINOCO

+ QR code for the ORINOCO videoORINOCO video +

Developed by Michael Hanke and colleagues at Psychoinformatics, INM-7, Forschungszentrum Jülich, ORINOCO brings together tools for maintaining connected research information using dedicated services.

+
+
+ ORINOCO components connect a shared data model and editor with services and tools for producing catalogs, websites and reports. +
+
ORINOCO components. A common data model supports editing and reuse across applications.Artwork: Stephan Heunis, CC BY 4.0.
+ QR code for the ORINOCO organizationORINOCO +
+
+
+
+
Psychoinformatics homepage with its graph and objectives.
Homepage
+
Psychoinformatics people directory.
People
+
+
+

Psychoinformatics

Connected research information, presented as a group website.

+ QR code for the Psychoinformatics websiteVisit the site +
+
+
+ +
+
+ +

ORINOCO-Lite

+

Developed and used by CON, ORINOCO Lite brings the same approach to GitHub. Labs can edit, review and reuse their research information without deploying services.

+
+
+ ORINOCO Lite uses the shared model and editor with GitHub to manage records and generate reusable outputs. +
+
ORINOCO-Lite components. The model and editor are shared; GitHub manages changes and accepted records.Adapted from Stephan Heunis, CC BY 4.0.
+ QR code for the ORINOCO Lite organizationORINOCO Lite +
+
+
+
+
CON homepage with its graph and objectives.
Homepage
+
CON people directory with Centroids and collaborators.
People
+
+
+

Center for Open Neuroscience

The GitHub deployment, used for CON’s development website.

+ QR code for the CON development websiteVisit the site +
+
+
+ +
+
+ SHACL Vue showing a Person record linked to a project and a typed role selector with Author, Co-author, Contributor and Creator choices. +
SHACL Vue: editing a person’s project association with typed record and role selectors.
+
+
+ +

Editing structured metadata

+

Describe people, projects and publications using a common data model. Forms guide contributions and validation helps keep records consistent.

+

The model generates the form, so contributors work with familiar fields while maintaining structured metadata.

+
+

In ORINOCO-Lite, proposed edits become GitHub pull requests for maintainers to review. Explore edits and their review history.

+ QR code for ORINOCO-Lite editor-generated pull requestsGitHub workflow +
+
+
+
+ +
+
+ +

Using metadata within
and across organizations

+

Both deployments maintain information where a group knows it best, and describe it in ways that other tools and organizations can understand.

+
+
+

Websites, reports and queries

+
+
+

Connect people, projects, publications and datasets. Websites, reports and queries can draw on the same records and their relationships.

+ QR code for CON’s graph explorerExplore the graph +
+
CON’s graph of connected people, projects, publications, datasets and other research information.
CON’s graph explorer
+
+
+
+

Connections through global identifiers

+

ORCID and DOI make it possible to match people and papers across independently maintained records.

+
+ + CON and publisher records connected through ORCID and DOI + CON and JOSS independently identify Yaroslav Halchenko by ORCID 0000-0003-3456-2493, and the DataLad paper by DOI 10.21105/joss.03262. Both describe him as an author; CON uses the MARC author role. Dashed lines show the matching identifiers that can connect the two collections. + + CON lab records + Publisher (JOSS) + + same ORCID + same DOI + + + author + MARC role + author + Yaroslav Halchenko + Yaroslav Halchenko + DataLad paper + DataLad paper + +
+
+
+

Structured context for AI

+

Explicit fields, identifiers and relationships give AI tools a clearer structure to work with: answering questions, checking records and proposing updates.

+
+
Example: annual reportingThe upstream TRR379 deployment uses its central metadata infrastructure to collect personnel information and generate a DFG annual-survey PDF.
+ +
+
+ + +
+
+ + + diff --git a/INDEX.md b/INDEX.md index db2d4035..6ce0d7ea 100644 --- a/INDEX.md +++ b/INDEX.md @@ -12,6 +12,13 @@ This matches reveal.js's URL-fragment numbering: `#//`. ## Per-talk inventory +### `2026-usrse/orinoco-lite_poster.html` — *Beyond the Lab Website* + +- US-RSE 2026 poster: service-based ORINOCO and GitHub-based ORINOCO Lite, + with actual websites, metadata editing, graph exploration and funder reporting. +- Editable HTML/CSS, with PDF export through `2026-usrse/orinoco-lite/build-poster.py`. +- Sources, licensing and four tagged component revisions: `2026-usrse/orinoco-lite/README.md`. + Shelved drafts and outlines that are not currently being prepared for a venue live under [`_backdrawer_/`](_backdrawer_/README.md) and are listed in the *Shelved (backdrawer)* section below the active inventory. diff --git a/REUSE.toml b/REUSE.toml index 7e97e6fb..a0eceac5 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -455,3 +455,45 @@ path = [ precedence = "aggregate" SPDX-FileCopyrightText = "2022-2026 Yaroslav O. Halchenko " SPDX-License-Identifier = "CC-BY-SA-4.0" + +# Poster authorship and original upstream artwork, with text outlined for display. +[[annotations]] +path = ["2026-usrse/orinoco-lite_poster.html", "2026-usrse/orinoco-lite/README.md", "2026-usrse/orinoco-lite/assets/orinoco-qr-*.svg"] +precedence = "closest" +SPDX-FileCopyrightText = ["2026 John Lee", "2026 Isaac To", "2026 Yaroslav O. Halchenko"] +SPDX-License-Identifier = "CC-BY-SA-4.0" + +[[annotations]] +path = "2026-usrse/orinoco-lite/assets/orinoco-selfhost-components-poster.svg" +precedence = "aggregate" +SPDX-FileCopyrightText = "2026 Stephan Heunis" +SPDX-License-Identifier = "CC-BY-4.0" + +# Official group mark; source and text-to-path adaptation in 2026-usrse/orinoco-lite/README.md. +[[annotations]] +path = "2026-usrse/orinoco-lite/assets/psychoinformatics_logo.svg" +precedence = "aggregate" +SPDX-FileCopyrightText = "2014-2016 Michael Hanke and Alex Waite" +SPDX-License-Identifier = "CC-BY-SA-4.0" + +# Lite deployment adaptation of Stephan Heunis's ORINOCO component artwork. +[[annotations]] +path = "2026-usrse/orinoco-lite/assets/orinoco-lite-components-poster.svg" +precedence = "aggregate" +SPDX-FileCopyrightText = ["2026 Stephan Heunis", "2026 John Lee", "2026 Isaac To", "2026 Yaroslav O. Halchenko"] +SPDX-License-Identifier = "CC-BY-4.0" + +# Relocated poster screenshots retain the third-party notices applied to +# their original pics/borrowed/ locations. +[[annotations]] +path = "2026-usrse/orinoco-lite/assets/orinoco-*.png" +precedence = "aggregate" +SPDX-FileCopyrightText = "NOASSERTION" +SPDX-License-Identifier = "LicenseRef-ThirdPartyMixed" + +# Copy of the shared ReproNim logo, with the same third-party logo notice. +[[annotations]] +path = "2026-usrse/orinoco-lite/assets/repronim_logo.svg" +precedence = "aggregate" +SPDX-FileCopyrightText = "NOASSERTION" +SPDX-License-Identifier = "LicenseRef-ThirdPartyLogo"