From 96235c83db9b8eca87dc4d9cc8ab78cd4ba6b46a Mon Sep 17 00:00:00 2001 From: "Wesley R. Elsberry" Date: Sat, 4 Oct 2025 22:29:06 -0400 Subject: [PATCH] Initial ChatGPT code and docs. --- .forgejo/workflows/build.yml | 25 +++++++ CITATION.cff | 14 ++++ CODE_OF_CONDUCT.md | 3 + CONTRIBUTING.md | 3 + Dockerfile.full | 10 +++ Dockerfile.tinytex | 14 ++++ Makefile | 40 +++++++++++ biblio.bib | 9 +++ build.el | 91 ++++++++++++++++++++++++ docker-compose.yml | 14 ++++ paper.org | 96 ++++++++++++++++++++++++++ polypaper-logo.svg | 11 +++ polypaper/.forgejo/workflows/build.yml | 25 +++++++ polypaper/.github/workflows/build.yml | 31 +++++++++ polypaper/.gitignore | 22 ++++++ polypaper/CITATION.cff | 14 ++++ polypaper/CODE_OF_CONDUCT.md | 3 + polypaper/CONTRIBUTING.md | 3 + polypaper/Dockerfile.full | 10 +++ polypaper/Dockerfile.tinytex | 14 ++++ polypaper/LICENSE | 21 ++++++ polypaper/Makefile | 40 +++++++++++ polypaper/README.md | 49 +++++++++++++ polypaper/biblio.bib | 9 +++ polypaper/build.el | 91 ++++++++++++++++++++++++ polypaper/docker-compose.yml | 14 ++++ polypaper/paper.org | 96 ++++++++++++++++++++++++++ polypaper/polypaper-logo.svg | 11 +++ polypaper/repo_meta.json | 36 ++++++++++ polypaper/scripts/check_metadata.py | 10 +++ polypaper/setup/venue-acm.org | 31 +++++++++ polypaper/setup/venue-arxiv.org | 18 +++++ polypaper/setup/venue-elsevier.org | 27 ++++++++ polypaper/setup/venue-ieee.org | 17 +++++ repo_meta.json | 36 ++++++++++ scripts/check_metadata.py | 10 +++ setup/venue-acm.org | 31 +++++++++ setup/venue-arxiv.org | 18 +++++ setup/venue-elsevier.org | 27 ++++++++ setup/venue-ieee.org | 17 +++++ 40 files changed, 1061 insertions(+) create mode 100755 .forgejo/workflows/build.yml create mode 100755 CITATION.cff create mode 100755 CODE_OF_CONDUCT.md create mode 100755 CONTRIBUTING.md create mode 100755 Dockerfile.full create mode 100755 Dockerfile.tinytex create mode 100755 Makefile create mode 100755 biblio.bib create mode 100755 build.el create mode 100755 docker-compose.yml create mode 100755 paper.org create mode 100755 polypaper-logo.svg create mode 100755 polypaper/.forgejo/workflows/build.yml create mode 100755 polypaper/.github/workflows/build.yml create mode 100755 polypaper/.gitignore create mode 100755 polypaper/CITATION.cff create mode 100755 polypaper/CODE_OF_CONDUCT.md create mode 100755 polypaper/CONTRIBUTING.md create mode 100755 polypaper/Dockerfile.full create mode 100755 polypaper/Dockerfile.tinytex create mode 100755 polypaper/LICENSE create mode 100755 polypaper/Makefile create mode 100755 polypaper/README.md create mode 100755 polypaper/biblio.bib create mode 100755 polypaper/build.el create mode 100755 polypaper/docker-compose.yml create mode 100755 polypaper/paper.org create mode 100755 polypaper/polypaper-logo.svg create mode 100755 polypaper/repo_meta.json create mode 100755 polypaper/scripts/check_metadata.py create mode 100755 polypaper/setup/venue-acm.org create mode 100755 polypaper/setup/venue-arxiv.org create mode 100755 polypaper/setup/venue-elsevier.org create mode 100755 polypaper/setup/venue-ieee.org create mode 100755 repo_meta.json create mode 100755 scripts/check_metadata.py create mode 100755 setup/venue-acm.org create mode 100755 setup/venue-arxiv.org create mode 100755 setup/venue-elsevier.org create mode 100755 setup/venue-ieee.org diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml new file mode 100755 index 0000000..5f77404 --- /dev/null +++ b/.forgejo/workflows/build.yml @@ -0,0 +1,25 @@ +name: Build PolyPaper (Forgejo) +on: [push, pull_request, workflow_dispatch] +jobs: + build: + runs-on: docker + strategy: { fail-fast: false, matrix: { venue: [arxiv, ieee, elsevier, acm] } } + steps: + - uses: actions/checkout@v4 + - name: Build Docker image + run: docker build -f Dockerfile.full -t polypaper:full . + - name: Validate metadata + run: docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'chmod +x scripts/check_metadata.py && scripts/check_metadata.py' + - name: Build PDFs and HTML (${{ matrix.venue }}) + run: | + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make VENUE=${{ matrix.venue }}' + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make supplement VENUE=${{ matrix.venue }}' + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make camera-ready VENUE=${{ matrix.venue }}' + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make site VENUE=${{ matrix.venue }}' + - name: Archive outputs + run: | + mkdir -p artifacts/${{ matrix.venue }} + mv paper-${{ matrix.venue }}.pdf artifacts/${{ matrix.venue }}/ || true + mv paper-supplement-${{ matrix.venue }}.pdf artifacts/${{ matrix.venue }}/ || true + mv paper-camera-ready-${{ matrix.venue }}.pdf artifacts/${{ matrix.venue }}/ || true + cp -a public artifacts/${{ matrix.venue }}/ || true diff --git a/CITATION.cff b/CITATION.cff new file mode 100755 index 0000000..7ebcd92 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,14 @@ +cff-version: 1.2.0 +message: "If you use this project, please cite it as below." +title: "PolyPaper" +authors: + - family-names: "Elsberry" + given-names: "Wesley R." + orcid: "https://orcid.org/0000-0000-0000-0000" +identifiers: + - type: doi + value: 10.5281/zenodo.0000000 +repository-code: "https://example.org/polypaper" +license: MIT +version: "0.1.0" +date-released: "2025-10-04" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100755 index 0000000..406d1f9 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +We follow the Contributor Covenant. Be kind. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000..e3dd668 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing + +Thanks for considering a contribution! See issues for ideas. diff --git a/Dockerfile.full b/Dockerfile.full new file mode 100755 index 0000000..4539799 --- /dev/null +++ b/Dockerfile.full @@ -0,0 +1,10 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1 LC_ALL=C.UTF-8 LANG=C.UTF-8 +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git make emacs-nox python3 python3-pip python3-matplotlib \ + latexmk biber texlive-full && rm -rf /var/lib/apt/lists/* +RUN useradd -m -u 1000 builder +WORKDIR /work +USER builder +CMD ["bash", "-lc", "make VENUE=arxiv"] diff --git a/Dockerfile.tinytex b/Dockerfile.tinytex new file mode 100755 index 0000000..566f4c2 --- /dev/null +++ b/Dockerfile.tinytex @@ -0,0 +1,14 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1 LC_ALL=C.UTF-8 LANG=C.UTF-8 PATH=/opt/TinyTeX/bin/x86_64-linux:$PATH +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git make emacs-nox python3 python3-pip python3-matplotlib perl && \ + rm -rf /var/lib/apt/lists/* +RUN curl -sL https://yihui.org/tinytex/install-unx.sh | sh -s - --admin --no-path && \ + /opt/TinyTeX/bin/*/tlmgr path add && \ + tlmgr install latexmk biber latex-bin biblatex hyperref geometry microtype etoolbox enumitem xcolor listings IEEEtran acmart elsarticle && \ + tlmgr path add +RUN useradd -m -u 1000 builder +WORKDIR /work +USER builder +CMD ["bash", "-lc", "make VENUE=arxiv"] diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..961b7fe --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +VENUE ?= arxiv +JOB ?= paper-$(VENUE) + +all: $(JOB).pdf + +$(JOB).pdf: paper.org setup/venue-$(VENUE).org build.el biblio.bib + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/export-pdf-cli + +site: + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/publish-site-cli + @echo "HTML written to public/ (paper.org → public/paper.html)" + +supplement: + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/export-supplement-pdf-cli + +camera-ready: + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/export-camera-ready-pdf-cli + +clean: + latexmk -C + rm -f paper-*.pdf + +# Dockerized builds +DOCKER_IMAGE ?= polypaper:full +DOCKERFILE ?= Dockerfile.full + +build-image: + docker build -f $(DOCKERFILE) -t $(DOCKER_IMAGE) . + +docker: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make VENUE=$(VENUE)" + +docker-supplement: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make supplement VENUE=$(VENUE)" + +docker-camera-ready: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make camera-ready VENUE=$(VENUE)" + +docker-site: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make site VENUE=$(VENUE)" diff --git a/biblio.bib b/biblio.bib new file mode 100755 index 0000000..1a02a67 --- /dev/null +++ b/biblio.bib @@ -0,0 +1,9 @@ +@article{demo2020, + title = {A Demo Reference for PolyPaper}, + author = {Example, Ada and Example, Alan}, + journal = {Journal of Demos}, + year = {2020}, + volume = {1}, + number = {1}, + pages = {1--10} +} diff --git a/build.el b/build.el new file mode 100755 index 0000000..af0b9bb --- /dev/null +++ b/build.el @@ -0,0 +1,91 @@ +;; Batch export & site publish +(setq org-confirm-babel-evaluate nil) +(setq org-latex-pdf-process '("latexmk -pdf -interaction=nonstopmode -shell-escape %f")) + +(defun wes/export-pdf (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv"))) + (outfile (format "paper-%s.pdf" v))) + (with-current-buffer (find-file-noselect "paper.org") + (setenv "VENUE" v) + (org-latex-export-to-pdf nil nil nil t) + (when (file-exists-p "paper.pdf") + (rename-file "paper.pdf" outfile t)) + (message "Wrote %s" outfile)))) + +(defun wes/export-pdf-cli () (wes/export-pdf)) + +(require 'ox) (require 'ox-publish) +(defun wes/publish-site (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv")))) + (setenv "VENUE" v) + (setq org-publish-project-alist + `(("site-html" + :base-directory "." + :publishing-directory "public" + :publishing-function org-html-publish-to-html + :with-author t :with-toc t :section-numbers t + :html-head "" + :recursive nil + :exclude "setup/\\|code/\\|figs/\\|public/\\|data/" + :include ("paper.org") + :select-tags ("export") + :exclude-tags ,(if (member v '("ieee" "acm")) + '("noexport" "appendix" "notes") + '("noexport"))))) + (org-publish "site-html" t) + (message "Published HTML site for %s" v))) + +(defun wes/publish-site-cli () (wes/publish-site)) + +(defun wes--cam-tight-latex () + (mapconcat #'identity + '("\\usepackage{microtype}" + "\\flushbottom" + "\\setlength{\\textfloatsep}{10pt}" + "\\setlength{\\floatsep}{8pt}" + "\\setlength{\\intextsep}{8pt}" + "\\usepackage{enumitem}" + "\\setlist{nosep}" + "\\usepackage{balance}") + "\n")) + +(defun wes/export-camera-ready-pdf (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv"))) + (base-setup (expand-file-name (format "setup/venue-%s.org" v))) + (tmp-name (format ".tmp-venue-%s-camera" v)) + (tmp-setup (expand-file-name (format "setup/%s.org" tmp-name))) + (outfile (format "paper-camera-ready-%s.pdf" v))) + (unless (file-exists-p base-setup) + (error "Base setup file not found for venue %s" v)) + (with-temp-buffer + (insert-file-contents base-setup) + (goto-char (point-max)) + (insert "\n# Camera-ready overrides\n#+BIND: paper-anon nil\n") + (insert (format "#+latex_header: %s\n" (wes--cam-tight-latex))) + (write-region (point-min) (point-max) tmp-setup)) + (unwind-protect + (progn + (with-current-buffer (find-file-noselect "paper.org") + (setenv "VENUE" tmp-name) + (org-latex-export-to-pdf nil nil nil t) + (when (file-exists-p "paper.pdf") + (rename-file "paper.pdf" outfile t)) + (message "Wrote %s" outfile))) + (ignore-errors (delete-file tmp-setup))))) + +(defun wes/export-camera-ready-pdf-cli () (wes/export-camera-ready-pdf)) + +(defun wes/export-supplement-pdf (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv"))) + (outfile (format "paper-supplement-%s.pdf" v)) + (paper-short nil) (paper-anon nil) (paper-limit-figs nil) + (org-export-select-tags '("export")) + (org-export-exclude-tags '("noexport"))) + (with-current-buffer (find-file-noselect "paper.org") + (setenv "VENUE" v) + (org-latex-export-to-pdf nil nil nil t) + (when (file-exists-p "paper.pdf") + (rename-file "paper.pdf" outfile t)) + (message "Wrote %s" outfile)))) + +(defun wes/export-supplement-pdf-cli () (wes/export-supplement-pdf)) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100755 index 0000000..7bb1d79 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +services: + paper: + build: { context: ., dockerfile: Dockerfile.full } + image: polypaper:full + working_dir: /work + volumes: [ ".:/work" ] + command: bash -lc "make VENUE=${VENUE:-arxiv}" + + paper-tiny: + build: { context: ., dockerfile: Dockerfile.tinytex } + image: polypaper:tinytex + working_dir: /work + volumes: [ ".:/work" ] + command: bash -lc "make VENUE=${VENUE:-arxiv}" diff --git a/paper.org b/paper.org new file mode 100755 index 0000000..f0f01db --- /dev/null +++ b/paper.org @@ -0,0 +1,96 @@ +# -*- org-export-allow-bind: t; -*- +#+TITLE: Demo Paper (PolyPaper) +#+AUTHOR: {{{NAME}}} +#+FILETAGS: :export: +#+OPTIONS: toc:2 num:t broken-links:auto +#+PROPERTY: header-args:python :session py :results file graphics :exports results :cache yes +#+PROPERTY: header-args: :mkdirp yes + +#+MACRO: VENUE (eval (or (getenv "VENUE") "arxiv")) +#+SETUPFILE: setup/venue-{{{VENUE}}}.org + +#+MACRO: IF-SHORT (eval (when (bound-and-true-p paper-short) "")) +#+MACRO: IF-LONG (eval (unless (bound-and-true-p paper-short) "")) +#+MACRO: IF-ANON (eval (when (bound-and-true-p paper-anon) "")) +#+MACRO: IF-LIMITFIG (eval (when (bound-and-true-p paper-limit-figs) "")) + +* Abstract :export: +PolyPaper demonstrates building venue-specific PDFs from a single Org source. + +* Introduction :export: +- One literate Org source. +- Venue profiles in =setup/=. +- Reproducible figures via Org Babel. +- Conditional content via tags/macros. + +{{{IF-ANON}}} +Double-blind mode replaces author name and redacts URLs. +{{{end}}} + +* Methods :export: +We generate a simple figure via Python/Matplotlib. + +#+name: fig-core +#+begin_src python :var seed=123 +import numpy as np, matplotlib.pyplot as plt +np.random.seed(seed) +x=np.linspace(0,10,200); y=np.sin(x)+0.15*np.random.randn(200) +plt.figure(); plt.plot(x,y); plt.xlabel("x"); plt.ylabel("y") +out="figs/sine-core.pdf"; plt.savefig(out, bbox_inches="tight"); out +#+end_src + +#+caption: Core figure used in all venues. +#+attr_latex: :width 0.8\linewidth +#+RESULTS: fig-core +file:figs/sine-core.pdf + +* Results :export: +Here is a citation [cite:@demo2020]. + +{{{IF-LIMITFIG}}} +** Extra figures (excluded when figure-limited) :noexport: +Text here won't export when =paper-limit-figs=t=. +{{{end}}} + +{{{IF-LONG}}} +* Appendix :export: +Extended content appears only for non-short profiles. +{{{end}}} + +* Data and Code Availability :export: +# This section is auto-generated from repo_meta.json. + +#+name: availability +#+begin_src python :var meta_file="repo_meta.json" :results raw :exports results :cache yes +import json, textwrap +m=json.load(open(meta_file, "r", encoding="utf-8")) +lines = [] +lines.append("*Data and Code Availability*") +if m.get("url"): + lines.append(f"- Code repository: [[{m['url']}][{m.get('repo_name', m['url'])}]]") +if m.get("license"): + lines.append(f"- License: {m['license']} (see LICENSE file)") +if m.get("code_archive_doi"): + lines.append(f"- Code archive DOI: {m['code_archive_doi']}") +if m.get("data_availability"): + lines.append(f"- Data availability: {m['data_availability']}") +dls = m.get("data_links", []) +if dls: + lines.append("- Data links:") + for d in dls: + if 'url' in d: + label = d.get('label', d['url']) + lines.append(f" - [[{d['url']}][{label}]]") +steps = m.get("repro_instructions", []) +if steps: + lines.append("- Reproducibility:") + for st in steps: + lines.append(f" - {st}") +if m.get("contact_email"): + lines.append(f"- Contact: {m['contact_email']}") +print("\n".join(lines)) +#+end_src + +#+RESULTS: availability + +* References :export: diff --git a/polypaper-logo.svg b/polypaper-logo.svg new file mode 100755 index 0000000..014b1db --- /dev/null +++ b/polypaper-logo.svg @@ -0,0 +1,11 @@ + + + + + Poly + Paper + + + One manuscript, many venues — Org-mode → LaTeX, reproducibly. + + diff --git a/polypaper/.forgejo/workflows/build.yml b/polypaper/.forgejo/workflows/build.yml new file mode 100755 index 0000000..5f77404 --- /dev/null +++ b/polypaper/.forgejo/workflows/build.yml @@ -0,0 +1,25 @@ +name: Build PolyPaper (Forgejo) +on: [push, pull_request, workflow_dispatch] +jobs: + build: + runs-on: docker + strategy: { fail-fast: false, matrix: { venue: [arxiv, ieee, elsevier, acm] } } + steps: + - uses: actions/checkout@v4 + - name: Build Docker image + run: docker build -f Dockerfile.full -t polypaper:full . + - name: Validate metadata + run: docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'chmod +x scripts/check_metadata.py && scripts/check_metadata.py' + - name: Build PDFs and HTML (${{ matrix.venue }}) + run: | + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make VENUE=${{ matrix.venue }}' + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make supplement VENUE=${{ matrix.venue }}' + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make camera-ready VENUE=${{ matrix.venue }}' + docker run --rm -v $GITHUB_WORKSPACE:/work -w /work polypaper:full bash -lc 'make site VENUE=${{ matrix.venue }}' + - name: Archive outputs + run: | + mkdir -p artifacts/${{ matrix.venue }} + mv paper-${{ matrix.venue }}.pdf artifacts/${{ matrix.venue }}/ || true + mv paper-supplement-${{ matrix.venue }}.pdf artifacts/${{ matrix.venue }}/ || true + mv paper-camera-ready-${{ matrix.venue }}.pdf artifacts/${{ matrix.venue }}/ || true + cp -a public artifacts/${{ matrix.venue }}/ || true diff --git a/polypaper/.github/workflows/build.yml b/polypaper/.github/workflows/build.yml new file mode 100755 index 0000000..720eb6d --- /dev/null +++ b/polypaper/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: Build PolyPaper + +on: [push, pull_request, workflow_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: { venue: [arxiv, ieee, elsevier, acm] } + steps: + - uses: actions/checkout@v4 + - name: Build Docker image + run: docker build -f Dockerfile.full -t polypaper:full . + - name: Validate metadata (in container) + run: docker run --rm -v ${{ github.workspace }}:/work -w /work polypaper:full bash -lc 'chmod +x scripts/check_metadata.py && scripts/check_metadata.py' + - name: Build PDFs and HTML (${{ matrix.venue }}) + run: | + docker run --rm -v ${{ github.workspace }}:/work -w /work polypaper:full bash -lc 'make VENUE=${{ matrix.venue }}' + docker run --rm -v ${{ github.workspace }}:/work -w /work polypaper:full bash -lc 'make supplement VENUE=${{ matrix.venue }}' + docker run --rm -v ${{ github.workspace }}:/work -w /work polypaper:full bash -lc 'make camera-ready VENUE=${{ matrix.venue }}' + docker run --rm -v ${{ github.workspace }}:/work -w /work polypaper:full bash -lc 'make site VENUE=${{ matrix.venue }}' + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: polypaper-${{ matrix.venue }} + path: | + paper-${{ matrix.venue }}.pdf + paper-supplement-${{ matrix.venue }}.pdf + paper-camera-ready-${{ matrix.venue }}.pdf + public/paper.html diff --git a/polypaper/.gitignore b/polypaper/.gitignore new file mode 100755 index 0000000..105dd6d --- /dev/null +++ b/polypaper/.gitignore @@ -0,0 +1,22 @@ +.DS_Store +*.aux +*.bbl +*.bcf +*.blg +*.fdb_latexmk +*.fls +*.log +*.out +*.run.xml +*.toc +*.synctex.gz +build/ +public/ +figs/ +code/ +__pycache__/ +*.pyc +.venv/ +env/ +*~ +\#*\# diff --git a/polypaper/CITATION.cff b/polypaper/CITATION.cff new file mode 100755 index 0000000..7ebcd92 --- /dev/null +++ b/polypaper/CITATION.cff @@ -0,0 +1,14 @@ +cff-version: 1.2.0 +message: "If you use this project, please cite it as below." +title: "PolyPaper" +authors: + - family-names: "Elsberry" + given-names: "Wesley R." + orcid: "https://orcid.org/0000-0000-0000-0000" +identifiers: + - type: doi + value: 10.5281/zenodo.0000000 +repository-code: "https://example.org/polypaper" +license: MIT +version: "0.1.0" +date-released: "2025-10-04" diff --git a/polypaper/CODE_OF_CONDUCT.md b/polypaper/CODE_OF_CONDUCT.md new file mode 100755 index 0000000..406d1f9 --- /dev/null +++ b/polypaper/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +We follow the Contributor Covenant. Be kind. diff --git a/polypaper/CONTRIBUTING.md b/polypaper/CONTRIBUTING.md new file mode 100755 index 0000000..e3dd668 --- /dev/null +++ b/polypaper/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing + +Thanks for considering a contribution! See issues for ideas. diff --git a/polypaper/Dockerfile.full b/polypaper/Dockerfile.full new file mode 100755 index 0000000..4539799 --- /dev/null +++ b/polypaper/Dockerfile.full @@ -0,0 +1,10 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1 LC_ALL=C.UTF-8 LANG=C.UTF-8 +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git make emacs-nox python3 python3-pip python3-matplotlib \ + latexmk biber texlive-full && rm -rf /var/lib/apt/lists/* +RUN useradd -m -u 1000 builder +WORKDIR /work +USER builder +CMD ["bash", "-lc", "make VENUE=arxiv"] diff --git a/polypaper/Dockerfile.tinytex b/polypaper/Dockerfile.tinytex new file mode 100755 index 0000000..566f4c2 --- /dev/null +++ b/polypaper/Dockerfile.tinytex @@ -0,0 +1,14 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1 LC_ALL=C.UTF-8 LANG=C.UTF-8 PATH=/opt/TinyTeX/bin/x86_64-linux:$PATH +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git make emacs-nox python3 python3-pip python3-matplotlib perl && \ + rm -rf /var/lib/apt/lists/* +RUN curl -sL https://yihui.org/tinytex/install-unx.sh | sh -s - --admin --no-path && \ + /opt/TinyTeX/bin/*/tlmgr path add && \ + tlmgr install latexmk biber latex-bin biblatex hyperref geometry microtype etoolbox enumitem xcolor listings IEEEtran acmart elsarticle && \ + tlmgr path add +RUN useradd -m -u 1000 builder +WORKDIR /work +USER builder +CMD ["bash", "-lc", "make VENUE=arxiv"] diff --git a/polypaper/LICENSE b/polypaper/LICENSE new file mode 100755 index 0000000..759872d --- /dev/null +++ b/polypaper/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Your Name + +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. diff --git a/polypaper/Makefile b/polypaper/Makefile new file mode 100755 index 0000000..961b7fe --- /dev/null +++ b/polypaper/Makefile @@ -0,0 +1,40 @@ +VENUE ?= arxiv +JOB ?= paper-$(VENUE) + +all: $(JOB).pdf + +$(JOB).pdf: paper.org setup/venue-$(VENUE).org build.el biblio.bib + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/export-pdf-cli + +site: + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/publish-site-cli + @echo "HTML written to public/ (paper.org → public/paper.html)" + +supplement: + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/export-supplement-pdf-cli + +camera-ready: + emacs -Q --batch -l build.el --eval "(setenv \"VENUE\" \"$(VENUE)\")" --funcall wes/export-camera-ready-pdf-cli + +clean: + latexmk -C + rm -f paper-*.pdf + +# Dockerized builds +DOCKER_IMAGE ?= polypaper:full +DOCKERFILE ?= Dockerfile.full + +build-image: + docker build -f $(DOCKERFILE) -t $(DOCKER_IMAGE) . + +docker: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make VENUE=$(VENUE)" + +docker-supplement: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make supplement VENUE=$(VENUE)" + +docker-camera-ready: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make camera-ready VENUE=$(VENUE)" + +docker-site: + docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/work -w /work $(DOCKER_IMAGE) bash -lc "make site VENUE=$(VENUE)" diff --git a/polypaper/README.md b/polypaper/README.md new file mode 100755 index 0000000..a9e1a9d --- /dev/null +++ b/polypaper/README.md @@ -0,0 +1,49 @@ +
+ +PolyPaper logo + +**PolyPaper** +*One manuscript, many venues — Org-mode → LaTeX, reproducibly.* + +[![Build (GitHub Actions)](https://img.shields.io/badge/build-GitHub_Actions-blue)](#) +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) + +
+ +--- + +# PolyPaper: Org → Multi-venue LaTeX Toolkit + +This is a literate, *single-source* paper template that exports venue-specific PDFs and HTML. + +## Requirements +- Emacs with Org-mode +- TeX toolchain (`latexmk`, `biber`) +- Python + Matplotlib + +## Quick start +```bash +make VENUE=arxiv +make VENUE=ieee +make VENUE=elsevier +make VENUE=acm +make supplement VENUE=arxiv +make camera-ready VENUE=ieee +make site VENUE=arxiv +``` + +## Data & Code Availability Appendix +Edit `repo_meta.json` and rebuild. Validate with: +```bash +scripts/check_metadata.py +``` + +## Dockerized builds +```bash +make build-image DOCKERFILE=Dockerfile.full DOCKER_IMAGE=polypaper:full +make docker VENUE=arxiv +``` + +## Continuous Integration +- GitHub: `.github/workflows/build.yml` +- Forgejo: `.forgejo/workflows/build.yml` diff --git a/polypaper/biblio.bib b/polypaper/biblio.bib new file mode 100755 index 0000000..1a02a67 --- /dev/null +++ b/polypaper/biblio.bib @@ -0,0 +1,9 @@ +@article{demo2020, + title = {A Demo Reference for PolyPaper}, + author = {Example, Ada and Example, Alan}, + journal = {Journal of Demos}, + year = {2020}, + volume = {1}, + number = {1}, + pages = {1--10} +} diff --git a/polypaper/build.el b/polypaper/build.el new file mode 100755 index 0000000..af0b9bb --- /dev/null +++ b/polypaper/build.el @@ -0,0 +1,91 @@ +;; Batch export & site publish +(setq org-confirm-babel-evaluate nil) +(setq org-latex-pdf-process '("latexmk -pdf -interaction=nonstopmode -shell-escape %f")) + +(defun wes/export-pdf (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv"))) + (outfile (format "paper-%s.pdf" v))) + (with-current-buffer (find-file-noselect "paper.org") + (setenv "VENUE" v) + (org-latex-export-to-pdf nil nil nil t) + (when (file-exists-p "paper.pdf") + (rename-file "paper.pdf" outfile t)) + (message "Wrote %s" outfile)))) + +(defun wes/export-pdf-cli () (wes/export-pdf)) + +(require 'ox) (require 'ox-publish) +(defun wes/publish-site (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv")))) + (setenv "VENUE" v) + (setq org-publish-project-alist + `(("site-html" + :base-directory "." + :publishing-directory "public" + :publishing-function org-html-publish-to-html + :with-author t :with-toc t :section-numbers t + :html-head "" + :recursive nil + :exclude "setup/\\|code/\\|figs/\\|public/\\|data/" + :include ("paper.org") + :select-tags ("export") + :exclude-tags ,(if (member v '("ieee" "acm")) + '("noexport" "appendix" "notes") + '("noexport"))))) + (org-publish "site-html" t) + (message "Published HTML site for %s" v))) + +(defun wes/publish-site-cli () (wes/publish-site)) + +(defun wes--cam-tight-latex () + (mapconcat #'identity + '("\\usepackage{microtype}" + "\\flushbottom" + "\\setlength{\\textfloatsep}{10pt}" + "\\setlength{\\floatsep}{8pt}" + "\\setlength{\\intextsep}{8pt}" + "\\usepackage{enumitem}" + "\\setlist{nosep}" + "\\usepackage{balance}") + "\n")) + +(defun wes/export-camera-ready-pdf (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv"))) + (base-setup (expand-file-name (format "setup/venue-%s.org" v))) + (tmp-name (format ".tmp-venue-%s-camera" v)) + (tmp-setup (expand-file-name (format "setup/%s.org" tmp-name))) + (outfile (format "paper-camera-ready-%s.pdf" v))) + (unless (file-exists-p base-setup) + (error "Base setup file not found for venue %s" v)) + (with-temp-buffer + (insert-file-contents base-setup) + (goto-char (point-max)) + (insert "\n# Camera-ready overrides\n#+BIND: paper-anon nil\n") + (insert (format "#+latex_header: %s\n" (wes--cam-tight-latex))) + (write-region (point-min) (point-max) tmp-setup)) + (unwind-protect + (progn + (with-current-buffer (find-file-noselect "paper.org") + (setenv "VENUE" tmp-name) + (org-latex-export-to-pdf nil nil nil t) + (when (file-exists-p "paper.pdf") + (rename-file "paper.pdf" outfile t)) + (message "Wrote %s" outfile))) + (ignore-errors (delete-file tmp-setup))))) + +(defun wes/export-camera-ready-pdf-cli () (wes/export-camera-ready-pdf)) + +(defun wes/export-supplement-pdf (&optional venue) + (let* ((v (or venue (or (getenv "VENUE") "arxiv"))) + (outfile (format "paper-supplement-%s.pdf" v)) + (paper-short nil) (paper-anon nil) (paper-limit-figs nil) + (org-export-select-tags '("export")) + (org-export-exclude-tags '("noexport"))) + (with-current-buffer (find-file-noselect "paper.org") + (setenv "VENUE" v) + (org-latex-export-to-pdf nil nil nil t) + (when (file-exists-p "paper.pdf") + (rename-file "paper.pdf" outfile t)) + (message "Wrote %s" outfile)))) + +(defun wes/export-supplement-pdf-cli () (wes/export-supplement-pdf)) diff --git a/polypaper/docker-compose.yml b/polypaper/docker-compose.yml new file mode 100755 index 0000000..7bb1d79 --- /dev/null +++ b/polypaper/docker-compose.yml @@ -0,0 +1,14 @@ +services: + paper: + build: { context: ., dockerfile: Dockerfile.full } + image: polypaper:full + working_dir: /work + volumes: [ ".:/work" ] + command: bash -lc "make VENUE=${VENUE:-arxiv}" + + paper-tiny: + build: { context: ., dockerfile: Dockerfile.tinytex } + image: polypaper:tinytex + working_dir: /work + volumes: [ ".:/work" ] + command: bash -lc "make VENUE=${VENUE:-arxiv}" diff --git a/polypaper/paper.org b/polypaper/paper.org new file mode 100755 index 0000000..f0f01db --- /dev/null +++ b/polypaper/paper.org @@ -0,0 +1,96 @@ +# -*- org-export-allow-bind: t; -*- +#+TITLE: Demo Paper (PolyPaper) +#+AUTHOR: {{{NAME}}} +#+FILETAGS: :export: +#+OPTIONS: toc:2 num:t broken-links:auto +#+PROPERTY: header-args:python :session py :results file graphics :exports results :cache yes +#+PROPERTY: header-args: :mkdirp yes + +#+MACRO: VENUE (eval (or (getenv "VENUE") "arxiv")) +#+SETUPFILE: setup/venue-{{{VENUE}}}.org + +#+MACRO: IF-SHORT (eval (when (bound-and-true-p paper-short) "")) +#+MACRO: IF-LONG (eval (unless (bound-and-true-p paper-short) "")) +#+MACRO: IF-ANON (eval (when (bound-and-true-p paper-anon) "")) +#+MACRO: IF-LIMITFIG (eval (when (bound-and-true-p paper-limit-figs) "")) + +* Abstract :export: +PolyPaper demonstrates building venue-specific PDFs from a single Org source. + +* Introduction :export: +- One literate Org source. +- Venue profiles in =setup/=. +- Reproducible figures via Org Babel. +- Conditional content via tags/macros. + +{{{IF-ANON}}} +Double-blind mode replaces author name and redacts URLs. +{{{end}}} + +* Methods :export: +We generate a simple figure via Python/Matplotlib. + +#+name: fig-core +#+begin_src python :var seed=123 +import numpy as np, matplotlib.pyplot as plt +np.random.seed(seed) +x=np.linspace(0,10,200); y=np.sin(x)+0.15*np.random.randn(200) +plt.figure(); plt.plot(x,y); plt.xlabel("x"); plt.ylabel("y") +out="figs/sine-core.pdf"; plt.savefig(out, bbox_inches="tight"); out +#+end_src + +#+caption: Core figure used in all venues. +#+attr_latex: :width 0.8\linewidth +#+RESULTS: fig-core +file:figs/sine-core.pdf + +* Results :export: +Here is a citation [cite:@demo2020]. + +{{{IF-LIMITFIG}}} +** Extra figures (excluded when figure-limited) :noexport: +Text here won't export when =paper-limit-figs=t=. +{{{end}}} + +{{{IF-LONG}}} +* Appendix :export: +Extended content appears only for non-short profiles. +{{{end}}} + +* Data and Code Availability :export: +# This section is auto-generated from repo_meta.json. + +#+name: availability +#+begin_src python :var meta_file="repo_meta.json" :results raw :exports results :cache yes +import json, textwrap +m=json.load(open(meta_file, "r", encoding="utf-8")) +lines = [] +lines.append("*Data and Code Availability*") +if m.get("url"): + lines.append(f"- Code repository: [[{m['url']}][{m.get('repo_name', m['url'])}]]") +if m.get("license"): + lines.append(f"- License: {m['license']} (see LICENSE file)") +if m.get("code_archive_doi"): + lines.append(f"- Code archive DOI: {m['code_archive_doi']}") +if m.get("data_availability"): + lines.append(f"- Data availability: {m['data_availability']}") +dls = m.get("data_links", []) +if dls: + lines.append("- Data links:") + for d in dls: + if 'url' in d: + label = d.get('label', d['url']) + lines.append(f" - [[{d['url']}][{label}]]") +steps = m.get("repro_instructions", []) +if steps: + lines.append("- Reproducibility:") + for st in steps: + lines.append(f" - {st}") +if m.get("contact_email"): + lines.append(f"- Contact: {m['contact_email']}") +print("\n".join(lines)) +#+end_src + +#+RESULTS: availability + +* References :export: diff --git a/polypaper/polypaper-logo.svg b/polypaper/polypaper-logo.svg new file mode 100755 index 0000000..014b1db --- /dev/null +++ b/polypaper/polypaper-logo.svg @@ -0,0 +1,11 @@ + + + + + Poly + Paper + + + One manuscript, many venues — Org-mode → LaTeX, reproducibly. + + diff --git a/polypaper/repo_meta.json b/polypaper/repo_meta.json new file mode 100755 index 0000000..3abf4ca --- /dev/null +++ b/polypaper/repo_meta.json @@ -0,0 +1,36 @@ +{ + "brand": "PolyPaper", + "repo_name": "PolyPaper", + "url": "https://example.org/polypaper", + "contact_email": "you@example.org", + "license": "MIT", + "code_archive_doi": "10.5281/zenodo.0000000", + "data_availability": "All data needed to evaluate the conclusions are available within the paper and its Supplementary Materials.", + "data_links": [ + { + "label": "Zenodo dataset", + "url": "https://zenodo.org/record/0000000" + }, + { + "label": "OSF project", + "url": "https://osf.io/xxxxx/" + } + ], + "software_env": { + "python": ">=3.10", + "packages": [ + "matplotlib", + "numpy" + ], + "latex": [ + "latexmk", + "biber" + ] + }, + "repro_instructions": [ + "Install TeX (with latexmk and biber).", + "Ensure Python and Matplotlib are installed.", + "Run `make VENUE=arxiv` to build the paper.", + "Run `make supplement VENUE=arxiv` to build the supplement." + ] +} \ No newline at end of file diff --git a/polypaper/scripts/check_metadata.py b/polypaper/scripts/check_metadata.py new file mode 100755 index 0000000..fa8bf0b --- /dev/null +++ b/polypaper/scripts/check_metadata.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 +import sys, json, os +META = "repo_meta.json" +REQ = ["url", "license"] +def fail(msg): print(f"[meta-check] {msg}", file=sys.stderr); sys.exit(1) +if not os.path.exists(META): fail(f"{META} not found.") +m = json.load(open(META, "r", encoding="utf-8")) +missing = [k for k in REQ if not m.get(k)] +if missing: fail("Missing required fields: " + ", ".join(missing)) +print("[meta-check] repo_meta.json looks OK.") diff --git a/polypaper/setup/venue-acm.org b/polypaper/setup/venue-acm.org new file mode 100755 index 0000000..5133c4e --- /dev/null +++ b/polypaper/setup/venue-acm.org @@ -0,0 +1,31 @@ +#+latex_class: acmart +#+latex_class_options: [sigconf] +#+latex_header: \citestyle{acmauthoryear} +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} + +#+latex_header: \usepackage[backend=biber,style=acmauthoryear,sorting=nyt]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport appendix notes + +#+BIND: paper-short t +#+BIND: paper-anon t +#+BIND: paper-limit-figs t + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) + +# ACM CCS taxonomy placeholders +#+latex_header: \begin{CCSXML} +#+latex_header: +#+latex_header: +#+latex_header: 10010147.10010257 +#+latex_header: Computing methodologies~Machine learning +#+latex_header: 500 +#+latex_header: +#+latex_header: +#+latex_header: \end{CCSXML} +#+latex_header: \ccsdesc[500]{Computing methodologies~Machine learning} +#+latex_header: \keywords{add, your, keywords} diff --git a/polypaper/setup/venue-arxiv.org b/polypaper/setup/venue-arxiv.org new file mode 100755 index 0000000..dda083a --- /dev/null +++ b/polypaper/setup/venue-arxiv.org @@ -0,0 +1,18 @@ +#+latex_class: article +#+latex_class_options: [10pt] +#+latex_header: \usepackage[margin=1in]{geometry} +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} + +#+latex_header: \usepackage[backend=biber,style=authoryear,maxbibnames=99]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport + +#+BIND: paper-short nil +#+BIND: paper-anon nil +#+BIND: paper-limit-figs nil + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) diff --git a/polypaper/setup/venue-elsevier.org b/polypaper/setup/venue-elsevier.org new file mode 100755 index 0000000..697f0a2 --- /dev/null +++ b/polypaper/setup/venue-elsevier.org @@ -0,0 +1,27 @@ +#+latex_class: elsarticle +#+latex_class_options: [preprint,12pt] +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} +#+latex_header: \usepackage{lineno} +#+latex_header: \usepackage[margin=1in]{geometry} + +#+latex_header: \usepackage[backend=biber,style=authoryear,maxbibnames=99]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport + +#+BIND: paper-short nil +#+BIND: paper-anon nil +#+BIND: paper-limit-figs nil + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) + +# Elsevier author/affiliation placeholders +#+latex_header: \author[1]{Wesley R. Elsberry\corref{cor1}} +#+latex_header: \ead{welsberr@example.org} +#+latex_header: \author[2]{Coauthor A. Name} +#+latex_header: \address[1]{Department, University, City, Country} +#+latex_header: \address[2]{Institute, Organization, City, Country} +#+latex_header: \cortext[cor1]{Corresponding author.} diff --git a/polypaper/setup/venue-ieee.org b/polypaper/setup/venue-ieee.org new file mode 100755 index 0000000..10d01df --- /dev/null +++ b/polypaper/setup/venue-ieee.org @@ -0,0 +1,17 @@ +#+latex_class: IEEEtran +#+latex_class_options: [conference] +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} + +#+latex_header: \usepackage[backend=biber,style=ieee,sorting=none]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport appendix notes + +#+BIND: paper-short t +#+BIND: paper-anon t +#+BIND: paper-limit-figs t + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) diff --git a/repo_meta.json b/repo_meta.json new file mode 100755 index 0000000..3abf4ca --- /dev/null +++ b/repo_meta.json @@ -0,0 +1,36 @@ +{ + "brand": "PolyPaper", + "repo_name": "PolyPaper", + "url": "https://example.org/polypaper", + "contact_email": "you@example.org", + "license": "MIT", + "code_archive_doi": "10.5281/zenodo.0000000", + "data_availability": "All data needed to evaluate the conclusions are available within the paper and its Supplementary Materials.", + "data_links": [ + { + "label": "Zenodo dataset", + "url": "https://zenodo.org/record/0000000" + }, + { + "label": "OSF project", + "url": "https://osf.io/xxxxx/" + } + ], + "software_env": { + "python": ">=3.10", + "packages": [ + "matplotlib", + "numpy" + ], + "latex": [ + "latexmk", + "biber" + ] + }, + "repro_instructions": [ + "Install TeX (with latexmk and biber).", + "Ensure Python and Matplotlib are installed.", + "Run `make VENUE=arxiv` to build the paper.", + "Run `make supplement VENUE=arxiv` to build the supplement." + ] +} \ No newline at end of file diff --git a/scripts/check_metadata.py b/scripts/check_metadata.py new file mode 100755 index 0000000..fa8bf0b --- /dev/null +++ b/scripts/check_metadata.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 +import sys, json, os +META = "repo_meta.json" +REQ = ["url", "license"] +def fail(msg): print(f"[meta-check] {msg}", file=sys.stderr); sys.exit(1) +if not os.path.exists(META): fail(f"{META} not found.") +m = json.load(open(META, "r", encoding="utf-8")) +missing = [k for k in REQ if not m.get(k)] +if missing: fail("Missing required fields: " + ", ".join(missing)) +print("[meta-check] repo_meta.json looks OK.") diff --git a/setup/venue-acm.org b/setup/venue-acm.org new file mode 100755 index 0000000..5133c4e --- /dev/null +++ b/setup/venue-acm.org @@ -0,0 +1,31 @@ +#+latex_class: acmart +#+latex_class_options: [sigconf] +#+latex_header: \citestyle{acmauthoryear} +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} + +#+latex_header: \usepackage[backend=biber,style=acmauthoryear,sorting=nyt]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport appendix notes + +#+BIND: paper-short t +#+BIND: paper-anon t +#+BIND: paper-limit-figs t + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) + +# ACM CCS taxonomy placeholders +#+latex_header: \begin{CCSXML} +#+latex_header: +#+latex_header: +#+latex_header: 10010147.10010257 +#+latex_header: Computing methodologies~Machine learning +#+latex_header: 500 +#+latex_header: +#+latex_header: +#+latex_header: \end{CCSXML} +#+latex_header: \ccsdesc[500]{Computing methodologies~Machine learning} +#+latex_header: \keywords{add, your, keywords} diff --git a/setup/venue-arxiv.org b/setup/venue-arxiv.org new file mode 100755 index 0000000..dda083a --- /dev/null +++ b/setup/venue-arxiv.org @@ -0,0 +1,18 @@ +#+latex_class: article +#+latex_class_options: [10pt] +#+latex_header: \usepackage[margin=1in]{geometry} +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} + +#+latex_header: \usepackage[backend=biber,style=authoryear,maxbibnames=99]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport + +#+BIND: paper-short nil +#+BIND: paper-anon nil +#+BIND: paper-limit-figs nil + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) diff --git a/setup/venue-elsevier.org b/setup/venue-elsevier.org new file mode 100755 index 0000000..697f0a2 --- /dev/null +++ b/setup/venue-elsevier.org @@ -0,0 +1,27 @@ +#+latex_class: elsarticle +#+latex_class_options: [preprint,12pt] +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} +#+latex_header: \usepackage{lineno} +#+latex_header: \usepackage[margin=1in]{geometry} + +#+latex_header: \usepackage[backend=biber,style=authoryear,maxbibnames=99]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport + +#+BIND: paper-short nil +#+BIND: paper-anon nil +#+BIND: paper-limit-figs nil + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry")) + +# Elsevier author/affiliation placeholders +#+latex_header: \author[1]{Wesley R. Elsberry\corref{cor1}} +#+latex_header: \ead{welsberr@example.org} +#+latex_header: \author[2]{Coauthor A. Name} +#+latex_header: \address[1]{Department, University, City, Country} +#+latex_header: \address[2]{Institute, Organization, City, Country} +#+latex_header: \cortext[cor1]{Corresponding author.} diff --git a/setup/venue-ieee.org b/setup/venue-ieee.org new file mode 100755 index 0000000..10d01df --- /dev/null +++ b/setup/venue-ieee.org @@ -0,0 +1,17 @@ +#+latex_class: IEEEtran +#+latex_class_options: [conference] +#+latex_header: \usepackage{microtype} +#+latex_header: \usepackage[hidelinks]{hyperref} + +#+latex_header: \usepackage[backend=biber,style=ieee,sorting=none]{biblatex} +#+latex_header: \addbibresource{biblio.bib} +#+latex_header: \AtEndDocument{\printbibliography} + +#+select_tags: export +#+exclude_tags: noexport appendix notes + +#+BIND: paper-short t +#+BIND: paper-anon t +#+BIND: paper-limit-figs t + +#+MACRO: NAME (eval (if (bound-and-true-p paper-anon) "Anonymous" "Wesley R. Elsberry"))