From ef4936b10c5828d62db97b01ab025838c59b41ee Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Fri, 19 Jun 2026 17:31:51 +0200 Subject: [PATCH] initial commit --- Manuscript/.gitignore | 2 + Manuscript/Taskfile.yml | 65 + Manuscript/_manuscript/_tex/index.tex | 287 +++ Manuscript/_manuscript/index.docx | Bin 0 -> 13009 bytes Manuscript/_manuscript/index.pdf | Bin 0 -> 26525 bytes Manuscript/_manuscript/index.xml | 312 +++ .../_manuscript/resources/references.bib | 19 + Manuscript/_quarto-anonymized.yml | 5 + Manuscript/_quarto-default.yml | 5 + Manuscript/_quarto.yml | 59 + Manuscript/data/README | 1 + Manuscript/figures/README | 1 + Manuscript/index.qmd | 69 + README | 103 + ResearchReport/.gitignore | 2 + ResearchReport/Taskfile.yml | 61 + ResearchReport/_quarto-anonymized.yml | 5 + ResearchReport/_quarto-default.yml | 5 + ResearchReport/_quarto.yml | 26 + ResearchReport/cover.png | Bin 0 -> 51194 bytes ResearchReport/data/README | 1 + ResearchReport/figures/README | 1 + ResearchReport/index.qmd | 5 + ResearchReport/intro.qmd | 5 + ResearchReport/references.bib | 19 + ResearchReport/references.qmd | 4 + ResearchReport/summary.qmd | 3 + Supplements/.gitignore | 2 + Supplements/Taskfile.yml | 62 + Supplements/_quarto-anonymized.yml | 5 + Supplements/_quarto-default.yml | 5 + Supplements/_quarto.yml | 22 + Supplements/data/README | 1 + Supplements/figures/README | 1 + Supplements/index.qmd | 12 + Supplements/references.bib | 19 + Taskfile.yml | 89 + resources/apa7.csl | 2273 +++++++++++++++++ resources/author-info-blocks.lua | 176 ++ .../author_profiles/_quarto-anonymized.yml | 2 + resources/author_profiles/_quarto-default.yml | 27 + resources/authors_block/authors-block.lua | 71 + .../authors_block/from_author_info_blocks.lua | 201 ++ .../authors_block/from_scholarly_metadata.lua | 59 + resources/authors_block/utils.lua | 62 + resources/custom-reference-doc.docx | Bin 0 -> 11040 bytes resources/references.bib | 19 + resources/scripts/split_titlepage.py | 213 ++ resources/scripts/task_utils.py | 168 ++ 49 files changed, 4554 insertions(+) create mode 100644 Manuscript/.gitignore create mode 100644 Manuscript/Taskfile.yml create mode 100644 Manuscript/_manuscript/_tex/index.tex create mode 100644 Manuscript/_manuscript/index.docx create mode 100644 Manuscript/_manuscript/index.pdf create mode 100644 Manuscript/_manuscript/index.xml create mode 100644 Manuscript/_manuscript/resources/references.bib create mode 100644 Manuscript/_quarto-anonymized.yml create mode 100644 Manuscript/_quarto-default.yml create mode 100644 Manuscript/_quarto.yml create mode 100644 Manuscript/data/README create mode 100644 Manuscript/figures/README create mode 100644 Manuscript/index.qmd create mode 100644 README create mode 100644 ResearchReport/.gitignore create mode 100644 ResearchReport/Taskfile.yml create mode 100644 ResearchReport/_quarto-anonymized.yml create mode 100644 ResearchReport/_quarto-default.yml create mode 100644 ResearchReport/_quarto.yml create mode 100644 ResearchReport/cover.png create mode 100644 ResearchReport/data/README create mode 100644 ResearchReport/figures/README create mode 100644 ResearchReport/index.qmd create mode 100644 ResearchReport/intro.qmd create mode 100644 ResearchReport/references.bib create mode 100644 ResearchReport/references.qmd create mode 100644 ResearchReport/summary.qmd create mode 100644 Supplements/.gitignore create mode 100644 Supplements/Taskfile.yml create mode 100644 Supplements/_quarto-anonymized.yml create mode 100644 Supplements/_quarto-default.yml create mode 100644 Supplements/_quarto.yml create mode 100644 Supplements/data/README create mode 100644 Supplements/figures/README create mode 100644 Supplements/index.qmd create mode 100644 Supplements/references.bib create mode 100644 Taskfile.yml create mode 100644 resources/apa7.csl create mode 100644 resources/author-info-blocks.lua create mode 100644 resources/author_profiles/_quarto-anonymized.yml create mode 100644 resources/author_profiles/_quarto-default.yml create mode 100644 resources/authors_block/authors-block.lua create mode 100644 resources/authors_block/from_author_info_blocks.lua create mode 100644 resources/authors_block/from_scholarly_metadata.lua create mode 100644 resources/authors_block/utils.lua create mode 100644 resources/custom-reference-doc.docx create mode 100644 resources/references.bib create mode 100644 resources/scripts/split_titlepage.py create mode 100644 resources/scripts/task_utils.py diff --git a/Manuscript/.gitignore b/Manuscript/.gitignore new file mode 100644 index 0000000..74ef190 --- /dev/null +++ b/Manuscript/.gitignore @@ -0,0 +1,2 @@ +/.quarto/ +**/*.quarto_ipynb diff --git a/Manuscript/Taskfile.yml b/Manuscript/Taskfile.yml new file mode 100644 index 0000000..fe1b161 --- /dev/null +++ b/Manuscript/Taskfile.yml @@ -0,0 +1,65 @@ +version: "3" + +vars: + PROJECT_NAME: Manuscript + PYTHON: '{{if eq OS "windows"}}python{{else}}python3{{end}}' + UTILS: "../resources/scripts/task_utils.py" + +tasks: + default: + desc: "List available tasks" + cmd: task --list + + render: + desc: "Render with the default (non-anonymized) profile, all formats" + cmd: quarto render --profile=default --output-dir _output/default + + render:anonymized: + desc: "Render with the anonymized profile, all formats" + cmd: quarto render --profile=anonymized --output-dir _output/anonymized + + render:html: + desc: "Render to HTML only (default profile)" + cmd: quarto render --profile=default --to html --output-dir _output/default + + render:docx: + desc: "Render to docx only (default profile)" + cmd: quarto render --profile=default --to docx --output-dir _output/default + + render:jats: + desc: "Render to JATS XML only (default profile)" + cmd: quarto render --profile=default --to jats --output-dir _output/default + + render:pdf: + desc: "Render to PDF only (default profile) - requires pdf format configured in _quarto.yml" + cmd: quarto render --profile=default --to pdf --output-dir _output/default + + package: + desc: "Zip the default-profile rendered output into Manuscript-default.zip" + deps: [render] + cmd: "{{.PYTHON}} {{.UTILS}} zip _output/default {{.PROJECT_NAME}}-default.zip" + sources: + - _output/default/**/* + generates: + - "{{.PROJECT_NAME}}-default.zip" + + package:anonymized: + desc: "Zip the anonymized-profile rendered output into Manuscript-anonymized.zip" + deps: [render:anonymized] + cmd: "{{.PYTHON}} {{.UTILS}} zip _output/anonymized {{.PROJECT_NAME}}-anonymized.zip" + sources: + - _output/anonymized/**/* + generates: + - "{{.PROJECT_NAME}}-anonymized.zip" + + package:data: + desc: "Zip the data/ folder into data.zip (skips with a warning if data/ doesn't exist)" + cmd: "{{.PYTHON}} {{.UTILS}} zip-if-exists data data.zip" + sources: + - data/**/* + generates: + - data.zip + + clean: + desc: "Remove _output, .quarto, and stray *_files/*_cache folders" + cmd: "{{.PYTHON}} {{.UTILS}} clean-project ." diff --git a/Manuscript/_manuscript/_tex/index.tex b/Manuscript/_manuscript/_tex/index.tex new file mode 100644 index 0000000..fbb3805 --- /dev/null +++ b/Manuscript/_manuscript/_tex/index.tex @@ -0,0 +1,287 @@ +% Options for packages loaded elsewhere +% Options for packages loaded elsewhere +\PassOptionsToPackage{unicode}{hyperref} +\PassOptionsToPackage{hyphens}{url} +\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor} +% +\documentclass[ + american, + letterpaper, + DIV=11, + numbers=noendperiod]{scrartcl} +\usepackage{xcolor} +\usepackage{amsmath,amssymb} +\setcounter{secnumdepth}{-\maxdimen} % remove section numbering +\usepackage{iftex} +\ifPDFTeX + \usepackage[T1]{fontenc} + \usepackage[utf8]{inputenc} + \usepackage{textcomp} % provide euro and other symbols +\else % if luatex or xetex + \usepackage{unicode-math} % this also loads fontspec + \defaultfontfeatures{Scale=MatchLowercase} + \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\fi +\usepackage{lmodern} +\ifPDFTeX\else + % xetex/luatex font selection +\fi +% Use upquote if available, for straight quotes in verbatim environments +\IfFileExists{upquote.sty}{\usepackage{upquote}}{} +\IfFileExists{microtype.sty}{% use microtype if available + \usepackage[]{microtype} + \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts +}{} +\makeatletter +\@ifundefined{KOMAClassName}{% if non-KOMA class + \IfFileExists{parskip.sty}{% + \usepackage{parskip} + }{% else + \setlength{\parindent}{0pt} + \setlength{\parskip}{6pt plus 2pt minus 1pt}} +}{% if KOMA class + \KOMAoptions{parskip=half}} +\makeatother +% Make \paragraph and \subparagraph free-standing +\makeatletter +\ifx\paragraph\undefined\else + \let\oldparagraph\paragraph + \renewcommand{\paragraph}{ + \@ifstar + \xxxParagraphStar + \xxxParagraphNoStar + } + \newcommand{\xxxParagraphStar}[1]{\oldparagraph*{#1}\mbox{}} + \newcommand{\xxxParagraphNoStar}[1]{\oldparagraph{#1}\mbox{}} +\fi +\ifx\subparagraph\undefined\else + \let\oldsubparagraph\subparagraph + \renewcommand{\subparagraph}{ + \@ifstar + \xxxSubParagraphStar + \xxxSubParagraphNoStar + } + \newcommand{\xxxSubParagraphStar}[1]{\oldsubparagraph*{#1}\mbox{}} + \newcommand{\xxxSubParagraphNoStar}[1]{\oldsubparagraph{#1}\mbox{}} +\fi +\makeatother + + +\usepackage{longtable,booktabs,array} +\usepackage{calc} % for calculating minipage widths +% Correct order of tables after \paragraph or \subparagraph +\usepackage{etoolbox} +\makeatletter +\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{} +\makeatother +% Allow footnotes in longtable head/foot +\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}} +\makesavenoteenv{longtable} +\usepackage{graphicx} +\makeatletter +\newsavebox\pandoc@box +\newcommand*\pandocbounded[1]{% scales image to fit in text height/width + \sbox\pandoc@box{#1}% + \Gscale@div\@tempa{\textheight}{\dimexpr\ht\pandoc@box+\dp\pandoc@box\relax}% + \Gscale@div\@tempb{\linewidth}{\wd\pandoc@box}% + \ifdim\@tempb\p@<\@tempa\p@\let\@tempa\@tempb\fi% select the smaller of both + \ifdim\@tempa\p@<\p@\scalebox{\@tempa}{\usebox\pandoc@box}% + \else\usebox{\pandoc@box}% + \fi% +} +% Set default figure placement to htbp +\def\fps@figure{htbp} +\makeatother + + + +\ifLuaTeX +\usepackage[bidi=basic]{babel} +\else +\usepackage[bidi=default]{babel} +\fi +% get rid of language-specific shorthands (see #6817): +\let\LanguageShortHands\languageshorthands +\def\languageshorthands#1{} +\ifLuaTeX + \usepackage[english]{selnolig} % disable illegal ligatures +\fi + + +\setlength{\emergencystretch}{3em} % prevent overfull lines + +\providecommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} + + + + + + +\KOMAoption{captions}{tableheading} +\usepackage{pdfpages} +\pagenumbering{gobble} +\usepackage{booktabs} +\usepackage{caption} +\DeclareCaptionLabelSeparator{period-newline}{.\par} +\usepackage{setspace} +\usepackage{float} % enables [H] +\usepackage[section]{placeins} % <- add [section] +\makeatletter +\@ifpackageloaded{caption}{}{\usepackage{caption}} +\AtBeginDocument{% +\ifdefined\contentsname + \renewcommand*\contentsname{Table of contents} +\else + \newcommand\contentsname{Table of contents} +\fi +\ifdefined\listfigurename + \renewcommand*\listfigurename{List of Figures} +\else + \newcommand\listfigurename{List of Figures} +\fi +\ifdefined\listtablename + \renewcommand*\listtablename{List of Tables} +\else + \newcommand\listtablename{List of Tables} +\fi +\ifdefined\figurename + \renewcommand*\figurename{Figure} +\else + \newcommand\figurename{Figure} +\fi +\ifdefined\tablename + \renewcommand*\tablename{Table} +\else + \newcommand\tablename{Table} +\fi +} +\@ifpackageloaded{float}{}{\usepackage{float}} +\floatstyle{ruled} +\@ifundefined{c@chapter}{\newfloat{codelisting}{h}{lop}}{\newfloat{codelisting}{h}{lop}[chapter]} +\floatname{codelisting}{Listing} +\newcommand*\listoflistings{\listof{codelisting}{List of Listings}} +\makeatother +\makeatletter +\makeatother +\makeatletter +\@ifpackageloaded{caption}{}{\usepackage{caption}} +\@ifpackageloaded{subcaption}{}{\usepackage{subcaption}} +\makeatother +\usepackage{bookmark} +\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available +\urlstyle{same} +\hypersetup{ + pdftitle={Title}, + pdfauthor={, , and }, + pdflang={en-US}, + pdfkeywords={Open Science Practices, Open Access, Open Data, Open +Materials, Preregistration, Text Mining, Machine Learning +Classification, AI-assisted Coding, Replication}, + colorlinks=true, + linkcolor={blue}, + filecolor={Maroon}, + citecolor={Blue}, + urlcolor={Blue}, + pdfcreator={LaTeX via pandoc}} + + +\title{Title} +\author{John Doe\textsuperscript{$\dagger{}$,1,*} \and John +Roe\textsuperscript{1} \and Jane Roe\textsuperscript{$\dagger{}$,1,2}} +\date{} +\begin{document} +\maketitle +\begin{abstract} +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy +eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam +voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet +clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit +amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, +sed diam voluptua. At vero eos et accusam et justo duo dolores et ea +rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem +ipsum dolor sit amet. +\end{abstract} + + +\textsuperscript{$\dagger{}$} +These authors contributed equally to this work. + +\textsuperscript{1} John Doe Center for Technology, John Doe University, +Doetown, Germany.\\ +\textsuperscript{2} Institute of Technology, John Doe University, +Doetown, Germany. + +\textsuperscript{*} Correspondence: \href{mailto:john.doe@jdct.edu}{John +Doe \textless{}john.doe@jdct.edu\textgreater{}} + +% keeps the title page numbers empty +\pagestyle{empty} +\newpage +\pagenumbering{arabic} +\pagestyle{headings} +\onehalfspacing % 1.5 line spacing from here on + +\section{Introduction}\label{introduction} + +\section{Background}\label{background} + +\section{Research Design}\label{research-design} + +\subsection{Data}\label{data} + +\subsection{Method}\label{method} + +\section{Results}\label{results} + +\section{Discussion}\label{discussion} + +\section{Conclusion}\label{conclusion} + +Conclusions here. + +\section*{Acknowlegments}\label{acknowlegments} +\addcontentsline{toc}{section}{Acknowlegments} + +I would like to thank my advisor, {[}Advisor Name{]}, for his guidance, +constructive feedback, and steady support throughout this project. His +expertise and encouragement were invaluable in shaping both the research +and this publication. + +\section*{Data availability}\label{data-availability} +\addcontentsline{toc}{section}{Data availability} + +Materials, Data and Code are made available at a public OSF-repository +that can be accessed here: + +\begin{itemize} +\tightlist +\item + https://osf.io/ +\end{itemize} + +\section*{Funding}\label{funding} +\addcontentsline{toc}{section}{Funding} + +This research received no external funding. + +\section*{Conflict of interest}\label{conflict-of-interest} +\addcontentsline{toc}{section}{Conflict of interest} + +The authors declare no conflict of interest. + +\section*{Author Biography}\label{author-biography} +\addcontentsline{toc}{section}{Author Biography} + +Jane doe is a scientist. + +\section*{Bibliography}\label{bibliography} +\addcontentsline{toc}{section}{Bibliography} + +\phantomsection\label{refs} + + + + +\end{document} diff --git a/Manuscript/_manuscript/index.docx b/Manuscript/_manuscript/index.docx new file mode 100644 index 0000000000000000000000000000000000000000..1c832de92e728ea33c70d9d92365df147f646426 GIT binary patch literal 13009 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 literal 0 HcmV?d00001 diff --git a/Manuscript/_manuscript/index.pdf b/Manuscript/_manuscript/index.pdf new file mode 100644 index 0000000000000000000000000000000000000000..95fcc4a85b27be46235c342d9c9fbf7b3dff4639 GIT binary patch literal 26525 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 + + +
+ + + + + + + + +Title + + + + +0000-1111-2222-3333 + +Doe +John + +John Doe + +john.doe@jdct.edu +a +* + + + +0000-3333-2222-1111 + +Roe +John + +John Roe + +a + + +0000-2222-1111-3333 + +Roe +Jane + +Jane Roe + +a +b + + + + +john.doe@jdct.edu +

John +Doe

+

Jane +Roe

+
+ + + + + + + + + + + + + +

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, +sed diam voluptua. At vero eos et accusam et justo duo dolores et ea +rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem +ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing +elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna +aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo +dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus +est Lorem ipsum dolor sit amet.

+
+ +Open Science Practices +Open Access +Open Data +Open Materials +Preregistration +Text Mining +Machine Learning Classification +AI-assisted Coding +Replication + + + + + +
+ +
+ + +

* These authors contributed equally to this work.

+

1 John Doe Center for Technology, John Doe University, +Doetown, Germany. +2 Institute of Technology, John Doe University, Doetown, +Germany.

+

Correspondence: +John +Doe <john.doe@jdct.edu>

+ + Introduction + + + Background + + + Research Design + + Data + + + Method + + + + Results + + + Discussion + + + Conclusion +

Conclusions here.

+
+ + Acknowlegments +

I would like to thank my advisor, [Advisor Name], for his guidance, + constructive feedback, and steady support throughout this project. His + expertise and encouragement were invaluable in shaping both the + research and this publication.

+
+ + Data availability +

Materials, Data and Code are made available at a public + OSF-repository that can be accessed here:

+ + +

https://osf.io/

+
+
+
+ + Funding +

This research received no external funding.

+
+ + Conflict of interest +

The authors declare no conflict of interest.

+
+ + Author Biography +

Jane doe is a scientist.

+
+ + Bibliography + + + + + + + + + +Title + + + +0000-1111-2222-3333 + +Doe +John + +John Doe + +john.doe@jdct.edu +a +* + + + +0000-3333-2222-1111 + +Roe +John + +John Roe + +a + + +0000-2222-1111-3333 + +Roe +Jane + +Jane Roe + +a +b + + + + +john.doe@jdct.edu +

John +Doe

+

Jane +Roe

+
+ +

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, +sed diam voluptua. At vero eos et accusam et justo duo dolores et ea +rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem +ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing +elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna +aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo +dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus +est Lorem ipsum dolor sit amet.

+
+
+ + +

* These authors contributed equally to this work.

+

1 John Doe Center for Technology, John Doe University, +Doetown, Germany. +2 Institute of Technology, John Doe University, Doetown, +Germany.

+

Correspondence: +John +Doe <john.doe@jdct.edu>

+ + Introduction + + + Background + + + Research Design + + Data + + + Method + + + + Results + + + Discussion + + + Conclusion +

Conclusions here.

+
+ + Acknowlegments +

I would like to thank my advisor, [Advisor Name], for his guidance, + constructive feedback, and steady support throughout this project. His + expertise and encouragement were invaluable in shaping both the + research and this publication.

+
+ + Data availability +

Materials, Data and Code are made available at a public + OSF-repository that can be accessed here:

+ + +

https://osf.io/

+
+
+
+ + Funding +

This research received no external funding.

+
+ + Conflict of interest +

The authors declare no conflict of interest.

+
+ + Author Biography +

Jane doe is a scientist.

+
+ + Bibliography + + + + + + + + + +
+ +
\ No newline at end of file diff --git a/Manuscript/_manuscript/resources/references.bib b/Manuscript/_manuscript/resources/references.bib new file mode 100644 index 0000000..0220dbd --- /dev/null +++ b/Manuscript/_manuscript/resources/references.bib @@ -0,0 +1,19 @@ +@article{knuth84, + author = {Knuth, Donald E.}, + title = {Literate Programming}, + year = {1984}, + issue_date = {May 1984}, + publisher = {Oxford University Press, Inc.}, + address = {USA}, + volume = {27}, + number = {2}, + issn = {0010-4620}, + url = {https://doi.org/10.1093/comjnl/27.2.97}, + doi = {10.1093/comjnl/27.2.97}, + journal = {Comput. J.}, + month = may, + pages = {97–111}, + numpages = {15} +} + + diff --git a/Manuscript/_quarto-anonymized.yml b/Manuscript/_quarto-anonymized.yml new file mode 100644 index 0000000..590c0da --- /dev/null +++ b/Manuscript/_quarto-anonymized.yml @@ -0,0 +1,5 @@ +project: + output-dir: _output/anonymized + +metadata-files: + - ../resources/author_profiles/_quarto-anonymized.yml \ No newline at end of file diff --git a/Manuscript/_quarto-default.yml b/Manuscript/_quarto-default.yml new file mode 100644 index 0000000..a26186b --- /dev/null +++ b/Manuscript/_quarto-default.yml @@ -0,0 +1,5 @@ +project: + output-dir: _output/default + +metadata-files: + - ../resources/author_profiles/_quarto-default.yml \ No newline at end of file diff --git a/Manuscript/_quarto.yml b/Manuscript/_quarto.yml new file mode 100644 index 0000000..8ed8874 --- /dev/null +++ b/Manuscript/_quarto.yml @@ -0,0 +1,59 @@ +project: + type: manuscript + +manuscript: + article: index.qmd + +format: + docx: + prefer-html: true + toc: true + toc-depth: 3 + lot: true + lof: true + fig-dpi: 300 + reference-doc: ../resources/custom-reference-doc.docx + jats: default + pdf: default + +profile: + default: default + +execute: + freeze: auto + echo: false + warning: false + +bibliography: ../resources/references.bib +citeproc: true +citation-package: none +reference-section-title: Bibliography +link-citations: true +# Check https://www.zotero.org/styles/ for more styles +csl: ../resources/apa7.csl + +lang: en-US + +keywords: + - Open Science Practices + - Open Access + - Open Data + - Open Materials + - Preregistration + - Text Mining + - Machine Learning Classification + - AI-assisted Coding + - Replication + +abstract: | + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +header-includes: | + \usepackage{pdfpages} + \pagenumbering{gobble} + \usepackage{booktabs} + \usepackage{caption} + \DeclareCaptionLabelSeparator{period-newline}{.\par} + \usepackage{setspace} + \usepackage{float} % enables [H] + \usepackage[section]{placeins} % <- add [section] diff --git a/Manuscript/data/README b/Manuscript/data/README new file mode 100644 index 0000000..4cf3206 --- /dev/null +++ b/Manuscript/data/README @@ -0,0 +1 @@ +Put your figures in this folder. \ No newline at end of file diff --git a/Manuscript/figures/README b/Manuscript/figures/README new file mode 100644 index 0000000..4cf3206 --- /dev/null +++ b/Manuscript/figures/README @@ -0,0 +1 @@ +Put your figures in this folder. \ No newline at end of file diff --git a/Manuscript/index.qmd b/Manuscript/index.qmd new file mode 100644 index 0000000..9a575a7 --- /dev/null +++ b/Manuscript/index.qmd @@ -0,0 +1,69 @@ +--- +title: Lorem Ipsum +--- + +```{=latex} +% keeps the title page numbers empty +\pagestyle{empty} +\newpage +\pagenumbering{arabic} +\pagestyle{headings} +\onehalfspacing % 1.5 line spacing from here on +``` + +# Introduction + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ac egestas ipsum. Vivamus bibendum accumsan nisi ac porta. Aenean efficitur sit amet lacus sollicitudin condimentum. Cras eros ipsum, euismod in odio pulvinar, imperdiet semper enim. Proin lobortis molestie mi eu blandit. Etiam eget velit laoreet, fringilla ligula at, fermentum velit. Sed mollis justo vitae quam pharetra, luctus aliquam neque vulputate. In tincidunt purus at viverra accumsan. Vivamus scelerisque suscipit turpis vitae pellentesque. Aliquam et euismod mauris. Mauris vitae erat velit. Aliquam id tincidunt est. Donec consequat est tellus, vitae sagittis tortor laoreet ut. Morbi sed dolor tristique lacus interdum imperdiet eget vitae elit. Cras ut eleifend turpis. + +In efficitur efficitur magna. Praesent id facilisis ex, ut eleifend mi. Sed id felis dapibus, vestibulum elit ac, ultricies nibh. Maecenas accumsan rhoncus rhoncus. Duis quis erat at risus convallis pretium. Sed eget varius nulla, ut sagittis felis. Donec magna justo, sagittis et feugiat a, iaculis in felis. Nam sed aliquam tellus. Fusce non metus quis enim condimentum gravida laoreet non mi. Fusce efficitur laoreet libero, id tincidunt dui tristique molestie. In nisi dolor, pulvinar eu massa at, tempor posuere libero. Suspendisse aliquam dui luctus justo rutrum, in feugiat urna elementum. Quisque rhoncus erat et aliquet dictum. Quisque rutrum nibh sit amet malesuada pretium. Curabitur eget malesuada sapien. + +Fusce faucibus risus sed feugiat lacinia. Nulla nec augue ut nulla facilisis efficitur. Fusce volutpat condimentum tincidunt. Curabitur sodales lacus vel iaculis rutrum. Donec ipsum massa, sagittis vitae ornare sit amet, pulvinar et dui. Duis aliquam laoreet consequat. Nulla rhoncus turpis mauris, eget mollis ipsum malesuada id. Vestibulum dictum erat id nibh laoreet, et facilisis lacus mollis. Aliquam libero neque, efficitur suscipit interdum eget, tempus in nisi. Mauris at convallis metus. Sed in viverra dolor. Etiam suscipit nisl id vestibulum sodales. Phasellus dolor mi, elementum a scelerisque vestibulum, blandit sit amet ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris risus nunc, blandit ac leo eget, pulvinar rutrum tellus. Quisque vel congue est. + +Duis scelerisque tempus convallis. Donec condimentum gravida augue, sit amet hendrerit ligula dictum nec. Nam elementum eu erat id dignissim. Vestibulum pretium, nisl tempus cursus luctus, nisl lacus blandit odio, nec dictum massa dui sollicitudin nisi. Nam ornare eros eu leo cursus egestas. Nulla scelerisque metus a dictum condimentum. Aliquam scelerisque sapien eget eros efficitur, at maximus urna tincidunt. + +Morbi in tincidunt urna. In lacinia, quam non iaculis vulputate, elit ante placerat nisl, nec ornare justo eros fermentum elit. Integer id semper lectus. Ut ac tincidunt leo. Suspendisse nec nisi imperdiet, auctor dui sed, eleifend arcu. In nec turpis volutpat orci pulvinar lacinia. Sed nisi diam, dictum at ex nec, blandit maximus dolor. Ut vitae ullamcorper felis. Let's cite @knuth84. + +# Background + +Phasellus tempor et nulla et maximus. Nulla mattis placerat lacus, sed bibendum nibh ultricies rhoncus. Maecenas ex libero, gravida at feugiat in, hendrerit sed libero. Proin semper orci sem, sit amet aliquam urna elementum mattis. Morbi lacinia euismod metus sed sollicitudin. Sed interdum maximus turpis, a ultrices velit pharetra non. Etiam eu lorem ligula. Pellentesque leo magna, facilisis et magna sed, porta vestibulum augue. Pellentesque interdum neque et nisl gravida, id luctus ipsum eleifend. + +# Research Design + +## Data + +## Method + +# Results + +# Discussion + +# Conclusion + +Conclusions here. + +# Acknowlegments {.unnumbered} + +I would like to thank my advisor, [Advisor Name], for his guidance, constructive feedback, and steady support throughout this project. His expertise and encouragement were invaluable in shaping both the research and this publication. + +# Data availability {.unnumbered} + +Materials, Data and Code are made available at a public OSF-repository that can be accessed here: + +- https://osf.io/ + +# Funding {.unnumbered} + +This research received no external funding. + +# Conflict of interest {.unnumbered} + +The authors declare no conflict of interest. + +# Author Biography {.unnumbered} + +Jane doe is a scientist. + +# Bibliography {.unnumbered} + +::: {#refs} +::: \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..cab6d23 --- /dev/null +++ b/README @@ -0,0 +1,103 @@ +# ScientificManuscriptTemplate + +A multi-project Quarto template for a manuscript, a research report, and supplements, sharing one set of resources (bibliography, CSL style, author/affiliation data, reference docx) and rendered via [Task](https://taskfile.dev). + + +## Requirements + +- [Quarto](https://quarto.org) +- [Task](https://taskfile.dev) +- Python 3 (used for zipping/cleaning) + +Make sure that Quarto, Task and Python are on your PATH. + +## How to use + +Clone the repo and edit `*.qmd` files, update author information in `resources/author_profiles/_quarto-default.yml` include references in `resources/references.bib` and render all projects using `task finalize`. + +In any arch-based Linux distro, run `go-task finalize` instead. + +More on how to include more detail in the front matter can be found in the official [quarto manual](https://quarto.org/docs/authoring/front-matter.html). Their quick introduction into [Markdown Basics](https://quarto.org/docs/authoring/markdown-basics.html) is also worth reading. + +## Project layout + +Each of `Manuscript/`, `ResearchReport/`, and `Supplements/` is its own Quarto project with its own `_quarto.yml`, `index.qmd`, `data/`, and `figures/` folders. + +``` +ScientificManuscriptTemplate/ +├── Manuscript/ ← the paper itself +├── ResearchReport/ ← longer-form report +├── Supplements/ ← supplementary materialss +├── resources/ ← shared across all three projects +│ ├── references.bib ← biblatex references +│ ├── apa7.csl ← citation style, grab from https://www.zotero.org/styles/ +│ ├── custom-reference-doc.docx ← docx template +│ └── author_profiles/ +│ ├── _quarto-default.yml ← real author/affiliation metadata +│ └── _quarto-anonymized.yml ← anonymized-profile metadata +├── Taskfile.yml ← run commands from here for the whole project +└── finalized/ ← created by `task finalize`, date-stamped output +``` + +## Writing content + +Edit the `.qmd` file(s) in whichever project you're working on (e.g. `Manuscript/index.qmd`). Put source data in that project's `data/` folder and images/plots in `figures/`. These are per-project, not shared. + +Shared resources live once in `resources/` and are referenced via relative paths from each project's `_quarto.yml` (bibliography, CSL, reference docx, author metadata) - edit them there, not inside an individual project folder, so all three projects stay in sync. + +## Authors and affiliations + +Real author names and affiliations are defined once in `resources/author_profiles/_quarto-default.yml`. The anonymized counterpart lives in `_quarto-anonymized.yml` in the same older. Update uthor info there. It's picked up automatically by every project. + +## Rendering + +Each project has its own profile pair - `default` (real author info) and `anonymized` (for blind peer review) - selected via Quarto's `--profile` flag, which the Task commands below already handle for you. + +**Render one project**, from inside that project's folder: + +``` +cd Manuscript +task render # default profile, all formats +task render:anonymized # anonymized profile, all formats +task render:html # single format, default profile +task render:docx +task render:pdf +task render:jats +``` + +**Or run any project's task from the repo root**, using its namespace: + +``` +task manuscript:render +task researchreport:render:anonymized +task supplements:render:docx +``` + +**Render everything at once**, from the repo root: + +``` +task render:all # all three projects, default profile +task render:all:anonymized # all three projects, anonymized profile +``` + +## Packaging and finalizing + +``` +task manuscript:package # zip Manuscript's default output +task manuscript:package:data # zip Manuscript/data into data.zip +task package:all # package every project, both profiles, plus data +task finalize # render everything, package everything, + # collect it all into finalized// +``` + +`task finalize` is the one command to run before submitting: it renders both profiles for all three projects, zips each project's output, and copies every zip into a fresh `finalized/YYYY-MM-DD/` folder so you have a clean, dated record of exactly what was submitted. + +## Cleaning up + +> [!WARNING] +> Be careful using this: the command also cleans caches, meaning that all computations will have to be re-evaluated. + +``` +task manuscript:clean # remove Manuscript's _output, .quarto, and stray cache folders +task clean:all # same, for all three projects +``` \ No newline at end of file diff --git a/ResearchReport/.gitignore b/ResearchReport/.gitignore new file mode 100644 index 0000000..ad29309 --- /dev/null +++ b/ResearchReport/.gitignore @@ -0,0 +1,2 @@ +/.quarto/ +**/*.quarto_ipynb diff --git a/ResearchReport/Taskfile.yml b/ResearchReport/Taskfile.yml new file mode 100644 index 0000000..4b016b5 --- /dev/null +++ b/ResearchReport/Taskfile.yml @@ -0,0 +1,61 @@ +version: "3" + +vars: + PROJECT_NAME: ResearchReport + PYTHON: '{{if eq OS "windows"}}python{{else}}python3{{end}}' + UTILS: "../resources/scripts/task_utils.py" + +tasks: + default: + desc: "List available tasks" + cmd: task --list + + render: + desc: "Render with the default (non-anonymized) profile, all formats" + cmd: quarto render --profile=default --output-dir _output/default + + render:anonymized: + desc: "Render with the anonymized profile, all formats" + cmd: quarto render --profile=anonymized --output-dir _output/anonymized + + render:html: + desc: "Render to HTML only (default profile)" + cmd: quarto render --profile=default --to html --output-dir _output/default + + render:docx: + desc: "Render to docx only (default profile)" + cmd: quarto render --profile=default --to docx --output-dir _output/default + + render:pdf: + desc: "Render to PDF only (default profile) - requires pdf format configured in _quarto.yml" + cmd: quarto render --profile=default --to pdf --output-dir _output/default + + package: + desc: "Zip the default-profile rendered output into ResearchReport-default.zip" + deps: [render] + cmd: "{{.PYTHON}} {{.UTILS}} zip _output/default {{.PROJECT_NAME}}-default.zip" + sources: + - _output/default/**/* + generates: + - "{{.PROJECT_NAME}}-default.zip" + + package:anonymized: + desc: "Zip the anonymized-profile rendered output into ResearchReport-anonymized.zip" + deps: [render:anonymized] + cmd: "{{.PYTHON}} {{.UTILS}} zip _output/anonymized {{.PROJECT_NAME}}-anonymized.zip" + sources: + - _output/anonymized/**/* + generates: + - "{{.PROJECT_NAME}}-anonymized.zip" + + package:data: + desc: "Zip the data/ folder into data.zip (skips with a warning if data/ doesn't exist)" + cmd: "{{.PYTHON}} {{.UTILS}} zip-if-exists data data.zip" + sources: + - data/**/* + generates: + - data.zip + + clean: + desc: "Remove _output, .quarto, and stray *_files/*_cache folders" + cmd: "{{.PYTHON}} {{.UTILS}} clean-project ." diff --git a/ResearchReport/_quarto-anonymized.yml b/ResearchReport/_quarto-anonymized.yml new file mode 100644 index 0000000..590c0da --- /dev/null +++ b/ResearchReport/_quarto-anonymized.yml @@ -0,0 +1,5 @@ +project: + output-dir: _output/anonymized + +metadata-files: + - ../resources/author_profiles/_quarto-anonymized.yml \ No newline at end of file diff --git a/ResearchReport/_quarto-default.yml b/ResearchReport/_quarto-default.yml new file mode 100644 index 0000000..a26186b --- /dev/null +++ b/ResearchReport/_quarto-default.yml @@ -0,0 +1,5 @@ +project: + output-dir: _output/default + +metadata-files: + - ../resources/author_profiles/_quarto-default.yml \ No newline at end of file diff --git a/ResearchReport/_quarto.yml b/ResearchReport/_quarto.yml new file mode 100644 index 0000000..43d8d8b --- /dev/null +++ b/ResearchReport/_quarto.yml @@ -0,0 +1,26 @@ +project: + type: book + output-dir: _output + +book: + title: "Report Title" + author: "Norah Jones" + date: "17.6.2026" + chapters: + - index.qmd + - intro.qmd + - summary.qmd + - references.qmd + +bibliography: references.bib + +format: + html: + theme: + - cosmo + - brand + pdf: + documentclass: scrreprt + + + diff --git a/ResearchReport/cover.png b/ResearchReport/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..e1f5bc61d11049afe5b5dc2a67a3a32f406be964 GIT binary patch literal 51194 zcmeGEc|4SD-v^E}jk1(1(TY*FlxR`eGHD^Dh?$s5v}zCf)yz1~&-pn%`*s{Voafs2Qyiiw zBO}vqmc#V2X?wuKFvlE0Xa9b;zN0~?Q8lV2_81+HF!Hxu|%##&P=|Kqo= z_gI^fm;Zr`bf?s>*y$C)YI&h3O zQB!`6&C#FUrzd7dANr*$J5_0!c>kKj)m8__F%2@NEgbgi(9wxG`h&l4p6}m!^uAuN zLGzOj^*z~7H$`))$NnGVRcI6RA2BOl&9gpuiD7%M+KZtwEAspLs#RL=^TI!0t^1Hy z&I!+GZug0~`u$kecTPc7-R0o2A7QEC3r2OSFqly?vNXE<|9$vBBK)5u{GS&5f2sw% zFu5nqhfa^{LPGq7mQ=#+Xes*iqvr4!t%9&D&yF3$|qh{MYCEceD+)UDf>J%geLfGF}!FCFaLj zoZBz8enyPOcUA2*sp~shR{ct8u76i4;eLHzxY;N#>}kuR*v|G5<1cSsE1w-1kyH7z zzBaUZRFb4t$8T*xhhfzh{eq^X@#VpmU3N5Wwk(fzc$s8?^n1W|@$=2!G(s|`gngUQ za6(dWtwNX|Fu5)(rqjyu&5P+pKP$qr+Rl}5n_U~8Pqh6}eK@kQTrI7p~C((hhEaa??TXop6jefzH$0iOzNT7D)M_5Vj=+OMIrx~Z+L|E7BpI&EhxzF(Z! zjnGOURPxAWsPudM^y*BT7QWT5AAX%bn+rc5Y|AR#{BzSY(YqIWTlLR1Y?%?WBrd1z z?yF@xYy;MR`_Mn{M^5L55d()cjO<1!1Sox)$=B^dX;kA!+os}q8*87{_z#-$>3efS zbG_@Oy^~s+kG`6e+gaV*VDH~~sNAM`RGj4eqAnm}Jz1VaZ=#{9)CHLb%OIMTKJzhiH|z))Z#ua`NhYf_@&FWZU@7bVB8>FA80nUZ*H8EM3vW zkb)@NFP0R23VZhUgjHoW$3K7L+4h=+{D_$uMTJWS{Yd1vXuH7Ic z3i3k!&>dT(E|fP-Zeo(8O>17|*HnLYl6`E@C(CcwOZT)FzB(lEZ{OBn8u2a3v-8&~ z%LXSasoP~bV;^Pz_$E=Jm_4TPlA-61qCM=Q%@OZvcu&G-xpkVJU(k>l+4!sf&lA%d zJYu>$w&+Ndm^(IXsJfJbu5#KDua9L8{={!K0cC7gYTk8M3(j(4@%H z`m1xpA8ShYs={P?X?We?=urVcp8U^*)E_5wzTf{G@y#k`uQ(#u)MiC}O_6{5yJp+= zC7Ykco?pSKy4V#c@PrTm;dM<9U~D*S!sHIB_CXlN~qYgJJ*9dvEqyf4TXxYC`?! zK3yB58>Y)4Djl&`Vx$Ub*w1FByfZzpkyA^eFm4-+;|E=jY|O4E*USP&#To zORDE?deyc+jfcd{?_$nExtMEPD=pu+`Cn~zv2{`%G)22LB(?pH;bw`%w6ow?N??9a zcPOMUM`!Eje4HVLG)ym`xxW5gOZex=^01s=iCgCel%>;bH@;u8>D#=5_f?%4RaW2V zMP0&7Kcv!VB|PMO*{};^SFbFO4AZLc?;#3;4QeGDU++4<`GueD&r-urk$014B+u@$ zOLt7Fl?5+uJn15=vS#Z)I*S&Eb*3!H-#q!%DCH@4d9L)xmS+tQrUW!M>->5-($Ffl zOB~`CGQAQOK5dgyT0E6@gTM92d~LmK$8)Pqqy%T2ixL};Jaemy93!!0BzIP+Do5Wt zTV9H4JO@xXkHfm47|D7|jLr}1qm&VNmUBS*rX%_cQR1z-h?1J$xC_Na)Bk616p}fT)>Ka?Gu0w)vc?{V0B=1p!1|uP55n`;0&h<8yiMJnaNCe)!F$FmD^E z;@)h#OpBs0Z#a+~e&5`0cs76a5Uwuuk`(a8a_HF&6luh2SfT$|@YL0Zb!*UosZto~ zfHBEcixPI;ajZE0!hEekHh-NlcQ^$jPDx%kL?=yZX2tsnjAlW_LLZi7@_=a+j0)h9 zV>?ZYA_s2YHr8n0sM*3ISR1>7Tc3Fh({{9(I}Q^+yH zVTD>&o?c4PLv$8$=<-W*;y_N0nZCJngT>%ULVt&iQtBAUdb6A!oz2xuXGv;YhEYU1 zyM*b*>fG(-K%vD4)mdX>4((Loh_>C-j?cAq6rMK;m3iA2sV|$aCj~MO zK&s}rO_u_Jpt8*OXzo(w))r>5dfbpWY(&e+knnR~0>oe?rhZymoNJ7<9Whtf# zz*K!%{W*tp*1SiLl_*RdMl(c?eYqAC-OG+giTJn91-oRG@pp~oZlRcW66`%SDQ7sf z+{cmWE_r+JA9Om;mtIZ-NzUqP|2{W7HF zNCY{|EiN6~rO9cwUYsWty?r3ZJ}+gdv9tj>!j3FGY$KnMJ4|p|D!!qJF+#_$l1kZW zki%)Osa=zuK;HGq2nx5SBN(EJUT;=Qw{iemIkS4h%Uxysh9>SF3bzl~%Ew88bZYrK zJ8b3Fpb_S}**horyHd-$~24s-eR1 z)88aTP7AEG9L7IHNX|Hh1(o-MH%(*uytR{>@f7lRE#W2V@9-AJrNZE_^HF8>i!}R7 zDR>F{_j@p}nL=R^Q20qJ`^9GZv@)<1(8;?;d zCNQwV%fV5~$%Sxz>>CSc0~O^n#=L3j()9l@7i%GNi{$BWWf?uL>@mC}-&dP26=DRK z0uo^IB7kg!-7%@GCV(QwTDvb2ibRRoOn0(T1jOk*0Wog{NOG_3xl}(E88L*p@kIyd z%AmWJ@!QFiSUK-N4zqu%(N+riWK9)zie}Szo(JCKv1zW<%@Qyx@;*x4vN8;l*3CBz z+A`3k$FXXHawc^Dg%nKDY#=lHb`5>MynM!fGtM>&_8YkKx6L`y3}=u&LpbEtTQ8a` zpt!zGwx^7qBHV`J)aTOJ^n3}jl{*aUd*ei?dl_7{KGai+Bi!yxT$uJC)P3@&`)q^nT?bg&q?BmlD z`*V6o5Rkg5*->rJao`;~QNrk;2XZx(jW7O6}rBh}1<9=OA+}cC^;JL5iUk zmS~x2OL=+@-twGY#xyTgkgh8@;Jw3&cMGC^QCcd1l98<*R8!$3?7!5XvR$F@FK_2d zRq`l69Q87p?KK!6#(mmANXttDh;EYsjW0DpROQ(|UC;wQN zkF7>EaxZTP z$c+8waFWUi~Ixv+>S;L3e%flqjK0>k~Fh=GR&EBfLgJMd` zt%IoubO+4H4u%Q!*$;-MA~}h#u-<@?UB4!+f>;jT4~WQ*7&ax8GoiSYFtiO&;WS$; zSWE&C@pS0+^vP$)XXbN|<5Jz3FdDpFMz^=~0y((XkB+BEx(?*1>E$+smk)A8JXjDy zNDz<)6T&o#rC{g)#+2H#O0*Ouz|ax3kmtM#0Ha{v2nvQeU=YFP4FbUi1wGLxRS;js%feQ&4790jl|uDX`ng%rmqKHfmMpwX&}amr z#iy`TmbO?)UXZJuSt~ysIyd8J_7uX)YB_9GX+S;&p%M`CoZM{bc0ki^?~<>8upQ2I z=cFJlm@CFMSf86m%x5tYVR0*NHbc62VqhRHEGHf$45p>o(j!8ZVFn+ws5g1PiX9@D zrS}toEpr(5nC#JTkm&`MSHJQlF3<(saxuu5huzYlMskBLYAUEa1*I>k@)JtT1yBz#nn(JxHkXDcjQbwJH{k?`8`DC8>&+i;KQkw zj?cT{c;YmItjYTaAV}9RysS$;e}IYnxW8#KKJN$r_8;I-q@9nLYd)7lSy2PXxWOX} zVjlhsVx9q)XFL2THE0KurBwso8tB@ZY)vX|v;f^K!b&NB`3$6ewoQ|e=#L{=tqX>Q?kof?n2bDe-eJ?lkw5E~h2)Lyc*vGUoR1*ok6t8G z&SkvZ+#7tWDW7M$H>ciTRQ#UM$7~5`TUAC0WW2N3o~FK(vy%w8vij2)R#J0)zu1&l zMubd8det?&=rljdybXjg9MjT7nM*xHiTb^BNbU<8nbB<{XM#90w^$?-V5dQx)6Xr4 z&x(d_dW_KCjFR&tCo^g(nCtHw7w8(5sB%f;mrFJNXlvI?k zM03k!6a0D{s2pD++lDZhNpj$oUiXN_D1f0TxS&NyQ+*Hyalm#RB4UgbSdx@e3HV(k zg58HHdY!6Z3zfaM5Fg*Edl}*DNcG$#Nrj+@oMIIZ!CBNd-66bXB-y%5kjO*g82KZ zOGs>m2%6m$L60_MWOGU@OTmM8h_@si+s#o~;QfTC{Jgz^y!sTR$+6Fg(SV#i2KFFg zOFgI|zJV3deZ0c)^Jr7Ri0o}lR{v3HKL|V$vMvz@7!O1!GllUMW+KfTc=)Qjnv$PU z+vX7B;~q$2)YktT^QX7OMpO;%`GRdfFyXWhM#$;F0v&+1_DUeCL;l)WBh!g z-+UyqtVwEe1hzIrsB4o$KoavQ%(noNmJM99uXJEH*rcd?lON%2Dvl;NLb60xVBVTk zjfmmKCI#J_{3C?83R`eBIs-u~?>0<9T)#P2!Bd}k2q7x(yCG}my@m|EelwA{tUNF; zY}EK)CHKH*y>8s@d|7=$I2>!2>vw`W2`RpBXlnSroRTCBev>~ z5W;K$)60B8*$?t=B*v0fnFNAT3l#I?1Lr>Y*#Sc2IF~z>$P+?c?kcu1tP`^iVpiHm zXoH_&DBZgZr6nXJc$|YD5d|I4)Hdrek&u<(|4MZZAqRq5L03@wM+hOF0=`VqeL$!? z9$Q(}OQMYD+Q9y@R{8QncWe!ri3wcPCAScd&_) z&fUR8%f^EvI_o9a?YVrGDDi(sB$8wTVUR{^yMTW!~hv@9nF~wQTmM?;}Dqn?YrKGvy^=Gz9(1B@!NOe_m|3I$__~+LNtf*HBq_2YKL{{4672i#VNx93&nHt4h z1TMUI)<9Wolp!)uh9G!XpDjF=4YYY?q<0$eqw-pTZ zzuLqB z+V@!denTnI_TM;|84D}M7-UyCwmN#bAgDS1b0V?j6QC>;CaogUP3(_+mXrJk^&X9&*7by(Y;8PHo4?kfr|?NXwGTX#r*j!{7g*kd*qwxIOh zzhE@V5JIX9(N5pLjrH7V8=FL5qmAJ>4p!A-!Q@3KIbKN^fye%UtJhC(DM{gPxB=)R z)|(mH|0lk8)YyKL{u|%l*~lMomlL@Eg>S&`^2i@_Faq3N((2)#bhr%jaXD@kgy;{r z0|57yG|2yh4gvYVchkVVa3g=fb=MPCXzKqLFFe2t5B0so;Qi)>`vj~t{I9jY3o%`t zk%_vZd1*UE+=VBp7@ju+W_Q<@=S1mDVXHi|8%fx(6D6CSX3w{Yr||eU_6)Z2QtTfD0pBzSl@~{1mZm~{r>uF0ld=;u*nUZ>e@UYX3t3q3mo|exY2`Cc zSTXT$x-w84lUA?)(1x=0(B8R!ZHWnGU}f)UI4tugO?Qd7&;O<=&jBjt@aPFrCDIR? zam3HgE0wvxTXM-GohrocLbj#(_Ob;@2lpJGz$e+Dv`u!Y4=<0lIEH1oxbs%KZR@v> zf|7y#tA3@1YYYR?$MC{Um*oCzCB1!*^ZkTWwL_3#C0ry2O>xjegh*dKnD&*P+fT4| z<;Gug1v*2u+l5Iw-)(@3+>6z$gU?se<)ZWKW-RSJ-QgIMeBq)WYcy+HXohC)W^)Fu_)7ntBL zwHx%9Y16>O*l7|qS=tXQ_^~Eqju*20dfMo8iQMF4!=2}%qE%Wk7vYaFGVS%Eis8s{ z5WMG|(@>a$1XC-@Alp*rt}guxLhLU?pYvpRdk|o0^Eyy z#ql`~QR4N8F4tSFQgcAzJdrmtJCRrCMthHqzaO13J&LJN@8C34VV?rdEg-?uSX|V`MlrIPB@pj{hZCC6B+m0L>ZnhW+*~`+S z2r?iXazn3dKve=6M}_|zd72z3H8?(+J=ob~7R-E^v=Ah3gc9lG^(N{J(L$6RpWhx& zS40*+ZmCknxYwLS@hj}6Fk{%PsNZ8DC{*0wlk$xy3f@E}w~Q}y(L^47DUP%+#RDaI zv6;a%x+e;Ic|NbKXi5O7_*yALaq07&VpNhPYll97e}_{btrfK81qmWFl+qMIC)zR? zs;ITIX{%t}RykSQA$mZ&X$CaM2S(^!lW#uaY{`}^EZgqyODtbTm*qp?AtZsvHpKhU zT6wn{kO;BN`lnOF8a#=k4`s{5PM~6v*(L-=UA3KTE&$J{QRT2E^gT5lrHdKI@+%co zuFQbbQi|0Tm`{hS%39uszw(+qC>6mR)UQqqTkVbzu&i+#yI;TA=b+FTQiZ;PR$H*{UPA?ycaRuK;eh5c z9*KE$6*GnmOWYq$%7c?xHmVE}0{5K5cTm^pYHo5rqs%O6G>c~U>p$WtVa_btAUIfKCN~{i?}5Kn0V&IL?j#lNcuJa z2*y$K3+x;GsDZpPWi zFfqVkjqN=H;aN|rHURG@Qy;v=Sh;wd_CO8_Y`>cvUYI@P_CAIQGNVxl;~M-X(X2oP zD=+Jx#}QK#-QvkX7nNQ=PyC|{oknTDRP));{F`5qm>j0@j0vv0r>fHB=KxnHmmp+j z2vk@zuKLaNIt+_>cz00=oaQI&|sEdxGEzaF-gMihjyrMz?i;u&N1Nq3vB;g zKDWE9`a9w}g0@cL@!Da3hC1K|^1;staz5$@%J9^{TD9U9q_jt2ga@CBhGV6MaWHyx z0LUD8pB&nq$7rIkY;t2Q>Zhk+KTe;uh?T)W*$qA!C<{0XJ~)po(tBl04zm_O>2YiD@I`gu#^YjSWx4rk z9H(zVL(q%0llEf0jz#UImwpXG31kGY9U&U#$T%RLC=C1BYhI__X_L{jy)KDI>|MO^ zNBzV4qL}DkInQ=^z!jaNP0^mrD&0tz$LN;3bWp9kIE%ueh!hSV!kRwx;Or3hg{$jp zeMXI8hKU^W2M?an<%hwAP@%^-c<^z(7Eaj(#w!VCDEzJ;&w@LdHORz{l*qlQ61kBf z6myl|neN!aY$^yVTQU;%0FJ(d+QmRHYK*vP0M8C0W>- z2D}=8SF75p8zDL{_Fr4H31r!HiEUtJ2f(y@>3;&Q17IrtA~ivb`;6-DIb++>Nw(iS z5W&=tK@3qcM9d=Gst!>>cOb{^!?4&U1I~73xz(6|k~j^@*B7DjO8R&tMd`9rb^_Qb zLnZ@lLSuy!GrF1rs6+}$B@*Pw2009A*mDNivn-Nu%V+N@?@{&M^cfy;TuJebv;U3VKY(v$F_dJ<@03y9O` zuK67TwM=Y#X{ZbW)G=rVL-~Y6`Fa8s^gc-S@)-$*->yod(Y8jF6|aEfScAx7jh&Lp zcBtUa@xCcfV9NO+6O9G-*#CpkZfdZ08eu;Z4NOZh{N9Qu0a_V9wkrO_z@FxW}S5EFit%2G}9VBz28wL>JM+uANr6k3wq6q-+}R zJjk?o?}DH>z#cOA;5Y$Ruq-rZ+`8t3>!dBiR}oD82H5K zL0JaBVV=jz#c{6V(JK~^UU3pun2$A>(SlNU{pQ=2dOa*^Lusvf{Opu$(32ao!Pp=4 zl#~kHDsm7LkfAK`CQyFUv{5QuvsmW;UWpR%n`Dg(M#8sYnr=-2con%yFuuplr$vB^ z?c*O$ZHGdk>%X-H?EY9X=hk9qDm5&2f8gZAf^8az!92V|4_wdR^!a5~jz?x?S)dNr zu%KglCV-v&# z0ill~3Ys5tvwp;A`YssH+e6QPceS~`;N4lB3`|`xN!N$L*}~jKo6`F!2^N#0_R6+Q zbm_=8!r=JlAIT?5n%ZMJn`+e;3YV17+f<%zda(6-M5AwcgCwBv!e$g$8pq1=5=QZu zOi)Ff?t9e||DuuS-2L4S-=n9ws3EeTOCt;PRs^KC^0$37q+NrsT=TP@hSUqCSq2P? zahWKGlL3}g{A)D2`}+lafBniRj;R4-WPCeKp7sL|{)qcXT8bj7rPz~#c7RD8Gxso< zD4GmGO%mFTIdviI3#()M020cQ?`ud%D~>U>nd#1<%&c<=oYJJ)xz<%^Gc~+EIm4*`RUz+e4vw4ySqk|uw7q84~`_$)i zdv*Ewa)Hye#b=Xcc=~cLys1%QJ>-D;H?s%uc7Pl^0_Kj0M=?7=<O^_Xy9Do+aZHSbyqt4m<~;#{@Fb85-*Nc_xr9F*1LM_Amd{tC4v_L61o%9?SE% z5H87XJ6-y1(Bt+-i$ta}{-n(ERT~6)45@qTL$d&E3%86}QsGMLB4uC*HipwD>AgX& ze#%aFUjjhx&~q{JZpZ-mD+eg*qM|9HDw=2=3#ry|EY>Io1rF$%%YI@Ym98=fC_mkM zWDYU~*5wlt_i2C~6LaeETEKp}hrNu>N6^6$ie&NUUeo3;{Z8<<7fz)~;AQxOqwVCAL14?OTPNs_ zu#1k|=exu|u;%MxYsa*cc$gYcr^x9Ba`HnbJ1W83D30gGvH$w6c6KIO?IlJ7?5f$| zP=GQ&jC#mjBf{ll(OoO&9E6vq&J`rUl&b8)v5kp-MVY za^MEP>@cr(AXLf3TIRXBJgPQ|k+MDo2&q_$zdAe3!N2#fHst>GJ&{SO1Bs{850wF* zvYPTu`uNweclz$XzW1ed57?JuA7or?J7xiP+H8LL_jh$9pI%h*`B!A1{@3?u4Dm*DM|aXY!51-T1!OhHX}XO!1k!tE#=kqUT%*7J>c79!X{h|s z`Y&ndZjoa8Lqw)ONYRZ&if-M*p1)zf1VM9kF7zG>r876v)87D@sE@okq{qN9L_o5! zF~^fwKoVKa#S?RPwH{@nhe{25PX-|@OzLoj_S{5ZWkbwn=j1adx~{`e8v@ni<( z?Ej{SJ=_1^jXM!KY7Dl!T|93Repx&7+`bsllvGAuLa=fNpPD%Yl4NdeeM(&(^=n1z zO&N7veRv$P+Qy1?wAjO(0^Fx89Hl6Bo?$CoNB-Om~{$ToiNb3AuoW0^uU`poj9U!TWCR}u-yD@bG?)(iC6qVq6 z6(_98VE^@9t(&GgV<6-&iuch2L9oEPoWm%U-r$o`DFa0g-;(M|BsF)Rkx?4{ zLJCTMeV@~fX+CJ0Q*}p`9tcbWl@_LoBY|n;2z!+~z_i$8O~fCVf~Lf~D8Tj-d0g<< z_Z~t049Wd?si`k-J`kM$utm40((4G+M_EnX*nJm(jHt{Ej*^s=7VX9>kvF zTraR7$rKr9btmJj10ehwH!o@MwD2b~=Gwd8^ocQlPklf%4+sLzb-QV z^dZ=DFIarcFWkn_&fdP0uho`N?e{jEEcG!C87qv-+)PIBBW#$KgIiAImX zA-!AnX;HuV>ot^Z^E3C%=5^m)j_EQPXMoe0^EnE`Ksw9&cU>?s0Pfv7w)x1X=>Oji zMBYumdIXP@9=n4dFOu0OA3mY*N1g6-*t?wa{Iz+Welt_wlUX>rI!;K6c=o;v+%^1O zw`HJ`%&KvFJirP2BH!Jr7x%9W`PdN6N|HTe%VBa>^uAO01Ix@K*<$vPOQq8jv{23UGDur~_*DlTZFt*h7gKKg%* z$#+3Aq=&=0#O$VtgS$pZi)AJ@OqGTfKr6|2oQsp5i0o2_1y7+4H`0wpLgkHL+%aE7 z8bRdyaeSxFib2LOw>wiUlR-@nUm+1t#CR7MYy698;wz5$H({9z>T^=9^>l$Q?2Ji2 zD1u^%PLzkvz`x}C?-^&Q*3L@aLJc)P3IolXOJ}a=8ghOlJws@}u168%pa{l;wy50z z`ED$s$rwXgSY~v6759v7tn;wx@@__u&H$sl!+OH{h#PIbT}`N`*RY%K3JsZLerCkh z`IxKI(}M|KSV=C9?nY9DlAT&QMLtaj~*F3 z|AdH)`kz2mmG!8`b(0}>HMjSp z-8DoaH5l{OV~9{j$Vf1j>H=x&;oRfnMC?Cj$GOX{z*;&6)`6yeTgu1dDGCBI*noVT zI=1!}@4okdDM#-u>z#0qOy%{%!Xd-ZYWe>s!rx%n>-|sf+5kUBCV{$6sQnK}BC1A$ zo|7;}$oCswzXSD)os)xY%AvsIy8_IuBJO06 z-wiLc*Dk0_qUPT`PRb;07zwXFrYNysWQcSWB7*iwSYh~PBT7{-Jg5V)$|?b?B(e_5 zy79BCABPvFMzpkL^TdoVX>1r7Z}c6?5jSR)JDt_dLel_(n_9+9H7e{;2u5b z>o)_#e1=n18Ac?M!PFGpCNemCgHHx$18`Qf-dba?s*#@A*Sz#Hepzx@#Y``FC-v{+ zzRHbUXMSjeiYsho(5Kw>a?s>4qpC%OOTu&En4YRwlgnv~`TcZ}T5BnLJ$PoKP92|DD> zbKl%uP;Vb_=NoyZ?(P2Tqj;>qhnEK4|F-4v#GUmD-Gk%29?#aDkB3fWd? z;HfM0)f=1cn>xtO$eGhqHarQBeM&P&n>Pz@p0#G~@c5Z&Wn@Q*>w>TC6eC&R<0~vv zdU)mdFee6La^t7soQ0^d@ry4Q8FwABU9^w+>U)fxVCTvu3rErf6$TfXHqlGsHQ$vT zqSwPLky?BUDJP)9zJ{D!zIkN8GlAIdbH8YIo~QHpb~X1B`kIb!(Vp>~Rj#%;ttmah zD7~+tWY+KeO`aEBHB>QU=6&Phbeh2Ez?3r&@S@Ulcczg;f&bA{u>-a3_AGvsBk%SF zlw;kKbD5<@6FByE$=&Vf8Si-6&z8o*GyEa3OSfR{7G=-pIrz>^+8$=7;MRg?H0tZG zU3qq5S8B_ey|jcpMze#^kQNTkgzp$eW~N2d%=8D1r$TmBb9F>{eq^3!zp6H*QV(ew z`ID}H|8nZy-X#$q&L2*=Bw7MJ7V-TJJVx;w2c~fk?BrOWa@aPH4*uVS|AehYtkqE+VZ$*dA26{Xc}v(D>CK*04_BcfPXdoYc0>u zPCGzW=Z+D4kjM)!s+(p_H8gd&SN$x3Nm>Y&vqz~OLF|)wvsRBb3)~{tfp}#zR}l

sLQu|F-aZhE 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�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 Vyw!|9>LU1OnX%cT*addJ{|^#&e**vj literal 0 HcmV?d00001 diff --git a/ResearchReport/data/README b/ResearchReport/data/README new file mode 100644 index 0000000..4cf3206 --- /dev/null +++ b/ResearchReport/data/README @@ -0,0 +1 @@ +Put your figures in this folder. \ No newline at end of file diff --git a/ResearchReport/figures/README b/ResearchReport/figures/README new file mode 100644 index 0000000..4cf3206 --- /dev/null +++ b/ResearchReport/figures/README @@ -0,0 +1 @@ +Put your figures in this folder. \ No newline at end of file diff --git a/ResearchReport/index.qmd b/ResearchReport/index.qmd new file mode 100644 index 0000000..2062215 --- /dev/null +++ b/ResearchReport/index.qmd @@ -0,0 +1,5 @@ +# Preface {.unnumbered} + +This is a Quarto book. + +To learn more about Quarto books visit . diff --git a/ResearchReport/intro.qmd b/ResearchReport/intro.qmd new file mode 100644 index 0000000..efcf172 --- /dev/null +++ b/ResearchReport/intro.qmd @@ -0,0 +1,5 @@ +# Introduction + +This is a book created from markdown and executable code. + +See @knuth84 for additional discussion of literate programming. diff --git a/ResearchReport/references.bib b/ResearchReport/references.bib new file mode 100644 index 0000000..0220dbd --- /dev/null +++ b/ResearchReport/references.bib @@ -0,0 +1,19 @@ +@article{knuth84, + author = {Knuth, Donald E.}, + title = {Literate Programming}, + year = {1984}, + issue_date = {May 1984}, + publisher = {Oxford University Press, Inc.}, + address = {USA}, + volume = {27}, + number = {2}, + issn = {0010-4620}, + url = {https://doi.org/10.1093/comjnl/27.2.97}, + doi = {10.1093/comjnl/27.2.97}, + journal = {Comput. J.}, + month = may, + pages = {97–111}, + numpages = {15} +} + + diff --git a/ResearchReport/references.qmd b/ResearchReport/references.qmd new file mode 100644 index 0000000..925f7c4 --- /dev/null +++ b/ResearchReport/references.qmd @@ -0,0 +1,4 @@ +# References {.unnumbered} + +::: {#refs} +::: diff --git a/ResearchReport/summary.qmd b/ResearchReport/summary.qmd new file mode 100644 index 0000000..b450ab7 --- /dev/null +++ b/ResearchReport/summary.qmd @@ -0,0 +1,3 @@ +# Summary + +In summary, this book has no content whatsoever. diff --git a/Supplements/.gitignore b/Supplements/.gitignore new file mode 100644 index 0000000..ad29309 --- /dev/null +++ b/Supplements/.gitignore @@ -0,0 +1,2 @@ +/.quarto/ +**/*.quarto_ipynb diff --git a/Supplements/Taskfile.yml b/Supplements/Taskfile.yml new file mode 100644 index 0000000..91f8f15 --- /dev/null +++ b/Supplements/Taskfile.yml @@ -0,0 +1,62 @@ +# Supplements/Taskfile.yml +version: "3" + +vars: + PROJECT_NAME: Supplements + PYTHON: '{{if eq OS "windows"}}python{{else}}python3{{end}}' + UTILS: "../resources/scripts/task_utils.py" + +tasks: + default: + desc: "List available tasks" + cmd: task --list + + render: + desc: "Render with the default (non-anonymized) profile, all formats" + cmd: quarto render --profile=default --output-dir _output/default + + render:anonymized: + desc: "Render with the anonymized profile, all formats" + cmd: quarto render --profile=anonymized --output-dir _output/anonymized + + render:html: + desc: "Render to HTML only (default profile)" + cmd: quarto render --profile=default --to html --output-dir _output/default + + render:docx: + desc: "Render to docx only (default profile)" + cmd: quarto render --profile=default --to docx --output-dir _output/default + + render:pdf: + desc: "Render to PDF only (default profile) - requires pdf format configured in _quarto.yml" + cmd: quarto render --profile=default --to pdf --output-dir _output/default + + package: + desc: "Zip the default-profile rendered output into Supplements-default.zip" + deps: [render] + cmd: "{{.PYTHON}} {{.UTILS}} zip _output/default {{.PROJECT_NAME}}-default.zip" + sources: + - _output/default/**/* + generates: + - "{{.PROJECT_NAME}}-default.zip" + + package:anonymized: + desc: "Zip the anonymized-profile rendered output into Supplements-anonymized.zip" + deps: [render:anonymized] + cmd: "{{.PYTHON}} {{.UTILS}} zip _output/anonymized {{.PROJECT_NAME}}-anonymized.zip" + sources: + - _output/anonymized/**/* + generates: + - "{{.PROJECT_NAME}}-anonymized.zip" + + package:data: + desc: "Zip the data/ folder into data.zip (skips with a warning if data/ doesn't exist)" + cmd: "{{.PYTHON}} {{.UTILS}} zip-if-exists data data.zip" + sources: + - data/**/* + generates: + - data.zip + + clean: + desc: "Remove _output, .quarto, and stray *_files/*_cache folders" + cmd: "{{.PYTHON}} {{.UTILS}} clean-project ." diff --git a/Supplements/_quarto-anonymized.yml b/Supplements/_quarto-anonymized.yml new file mode 100644 index 0000000..590c0da --- /dev/null +++ b/Supplements/_quarto-anonymized.yml @@ -0,0 +1,5 @@ +project: + output-dir: _output/anonymized + +metadata-files: + - ../resources/author_profiles/_quarto-anonymized.yml \ No newline at end of file diff --git a/Supplements/_quarto-default.yml b/Supplements/_quarto-default.yml new file mode 100644 index 0000000..a26186b --- /dev/null +++ b/Supplements/_quarto-default.yml @@ -0,0 +1,5 @@ +project: + output-dir: _output/default + +metadata-files: + - ../resources/author_profiles/_quarto-default.yml \ No newline at end of file diff --git a/Supplements/_quarto.yml b/Supplements/_quarto.yml new file mode 100644 index 0000000..f671967 --- /dev/null +++ b/Supplements/_quarto.yml @@ -0,0 +1,22 @@ +project: + type: manuscript + output-dir: _output + +manuscript: + article: index.qmd + +format: + html: + comments: + hypothesis: true + docx: default + jats: default + + # (other formats) + # pdf: default + +execute: + freeze: true + + + diff --git a/Supplements/data/README b/Supplements/data/README new file mode 100644 index 0000000..4cf3206 --- /dev/null +++ b/Supplements/data/README @@ -0,0 +1 @@ +Put your figures in this folder. \ No newline at end of file diff --git a/Supplements/figures/README b/Supplements/figures/README new file mode 100644 index 0000000..4cf3206 --- /dev/null +++ b/Supplements/figures/README @@ -0,0 +1 @@ +Put your figures in this folder. \ No newline at end of file diff --git a/Supplements/index.qmd b/Supplements/index.qmd new file mode 100644 index 0000000..cfb9963 --- /dev/null +++ b/Supplements/index.qmd @@ -0,0 +1,12 @@ +--- +title: Supplementary Materials +authors: + - name: Norah Jones + affiliation: The University + roles: writing + corresponding: true +bibliography: references.bib +--- + +## Section +This is a simple placeholder for the manuscript's main document [@knuth84]. diff --git a/Supplements/references.bib b/Supplements/references.bib new file mode 100644 index 0000000..0220dbd --- /dev/null +++ b/Supplements/references.bib @@ -0,0 +1,19 @@ +@article{knuth84, + author = {Knuth, Donald E.}, + title = {Literate Programming}, + year = {1984}, + issue_date = {May 1984}, + publisher = {Oxford University Press, Inc.}, + address = {USA}, + volume = {27}, + number = {2}, + issn = {0010-4620}, + url = {https://doi.org/10.1093/comjnl/27.2.97}, + doi = {10.1093/comjnl/27.2.97}, + journal = {Comput. J.}, + month = may, + pages = {97–111}, + numpages = {15} +} + + diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..db70ee2 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,89 @@ +version: "3" + +vars: + PYTHON: '{{if eq OS "windows"}}python{{else}}python3{{end}}' + DATE: + sh: '{{if eq OS "windows"}}python{{else}}python3{{end}} ./resources/scripts/task_utils.py today' + FINALIZED_DIR: "finalized/{{.DATE}}" + +includes: + manuscript: + taskfile: ./Manuscript/Taskfile.yml + dir: ./Manuscript + researchreport: + taskfile: ./ResearchReport/Taskfile.yml + dir: ./ResearchReport + supplements: + taskfile: ./Supplements/Taskfile.yml + dir: ./Supplements + +tasks: + default: + desc: "List available tasks" + cmd: task --list + + render:all: + desc: "Render all three projects with the default profile" + cmds: + - task: manuscript:render + - task: researchreport:render + - task: supplements:render + + render:all:anonymized: + desc: "Render all three projects with the anonymized profile" + cmds: + - task: manuscript:render:anonymized + - task: researchreport:render:anonymized + - task: supplements:render:anonymized + + package:all: + desc: "Package every project: default zip, anonymized zip, and data zip" + cmds: + - task: manuscript:package + - task: manuscript:package:anonymized + - task: manuscript:package:data + - task: researchreport:package + - task: researchreport:package:anonymized + - task: researchreport:package:data + - task: supplements:package + - task: supplements:package:anonymized + - task: supplements:package:data + + clean:all: + desc: "Clean every project's rendered output and Quarto cache" + cmds: + - task: manuscript:clean + - task: researchreport:clean + - task: supplements:clean + - task: clean:zips + + clean:zips: + desc: "Clean every project's zip-packages within the project folders (but keep rendered output)" + cmds: + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py clean-zips Manuscript" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py clean-zips ResearchReport" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py clean-zips Supplements" + + finalize: + desc: "Full pipeline: render both profiles, package everything, collect into finalized//" + cmds: + - task: render:all + - task: render:all:anonymized + - task: package:all + - task: collect + - cmd: echo "Finalized bundle ready at {{.FINALIZED_DIR}}" + + collect: + internal: false + desc: "Copy all project zips into the date-stamped finalized folder" + cmds: + - cmd: '{{if eq OS "windows"}}if not exist "{{.FINALIZED_DIR}}" mkdir "{{.FINALIZED_DIR}}"{{else}}mkdir -p "{{.FINALIZED_DIR}}"{{end}}' + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists Manuscript/Manuscript-default.zip {{.FINALIZED_DIR}}/Manuscript-default.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists Manuscript/Manuscript-anonymized.zip {{.FINALIZED_DIR}}/Manuscript-anonymized.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists Manuscript/data.zip {{.FINALIZED_DIR}}/Manuscript-data.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists ResearchReport/ResearchReport-default.zip {{.FINALIZED_DIR}}/ResearchReport-default.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists ResearchReport/ResearchReport-anonymized.zip {{.FINALIZED_DIR}}/ResearchReport-anonymized.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists ResearchReport/data.zip {{.FINALIZED_DIR}}/ResearchReport-data.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists Supplements/Supplements-default.zip {{.FINALIZED_DIR}}/Supplements-default.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists Supplements/Supplements-anonymized.zip {{.FINALIZED_DIR}}/Supplements-anonymized.zip" + - cmd: "{{.PYTHON}} ./resources/scripts/task_utils.py copy-if-exists Supplements/data.zip {{.FINALIZED_DIR}}/Supplements-data.zip" diff --git a/resources/apa7.csl b/resources/apa7.csl new file mode 100644 index 0000000..84632ab --- /dev/null +++ b/resources/apa7.csl @@ -0,0 +1,2273 @@ + + diff --git a/resources/author-info-blocks.lua b/resources/author-info-blocks.lua new file mode 100644 index 0000000..dbe3f96 --- /dev/null +++ b/resources/author-info-blocks.lua @@ -0,0 +1,176 @@ +--[[ +affiliation-blocks – generate title components + +Copyright © 2017–2021 Albert Krewinkel + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +]] +local List = require 'pandoc.List' +local utils = require 'pandoc.utils' +local stringify = utils.stringify + +local default_marks +local default_marks = { + corresponding_author = FORMAT == 'latex' + and {pandoc.RawInline('latex', '*')} + or {pandoc.Str '✉'}, + equal_contributor = FORMAT == 'latex' + and {pandoc.RawInline('latex', '$\\dagger{}$')} + or {pandoc.Str '*'}, +} + +local function intercalate(lists, elem) + local result = List:new{} + for i = 1, (#lists - 1) do + result:extend(lists[i]) + result:extend(elem) + end + if #lists > 0 then + result:extend(lists[#lists]) + end + return result +end + +--- Check whether the given author is a corresponding author +local function is_corresponding_author(author) + return author.correspondence and author.email +end + +--- Create inlines for a single author (includes all author notes) +local function author_inline_generator (get_mark) + return function (author) + local author_marks = List:new{} + if author.equal_contributor then + author_marks[#author_marks + 1] = get_mark 'equal_contributor' + end + local idx_str + for _, idx in ipairs(author.institute) do + if type(idx) ~= 'table' then + idx_str = tostring(idx) + else + idx_str = stringify(idx) + end + author_marks[#author_marks + 1] = {pandoc.Str(idx_str)} + end + if is_corresponding_author(author) then + author_marks[#author_marks + 1] = get_mark 'corresponding_author' + end + local res = List.clone(author.name) + res[#res + 1] = pandoc.Superscript(intercalate(author_marks, {pandoc.Str ','})) + return res + end +end + +local function is_equal_contributor (author) + return author.equal_contributor +end + +--- Create equal contributors note. +local function create_equal_contributors_block(authors, mark) + local has_equal_contribs = List:new(authors):find_if(is_equal_contributor) + if not has_equal_contribs then + return nil + end + local contributors = { + pandoc.Superscript(mark'equal_contributor'), + pandoc.Space(), + pandoc.Str 'These authors contributed equally to this work.' + } + return List:new{pandoc.Para(contributors)} +end + +--- Generate a block list all affiliations, marked with arabic numbers. +local function create_affiliations_blocks(affiliations) + local affil_lines = List:new(affiliations):map( + function (affil, i) + local num_inlines = List:new{ + pandoc.Superscript{pandoc.Str(tostring(i))}, + pandoc.Space() + } + return num_inlines .. affil.name + end + ) + return {pandoc.Para(intercalate(affil_lines, {pandoc.LineBreak()}))} +end + +--- Generate a block element containing the correspondence information +local function create_correspondence_blocks(authors, mark) + local corresponding_authors = List:new{} + for _, author in ipairs(authors) do + if is_corresponding_author(author) then + local mailto = 'mailto:' .. pandoc.utils.stringify(author.email) + local author_with_mail = List:new( + author.name .. List:new{pandoc.Space(), pandoc.Str '<'} .. + author.email .. List:new{pandoc.Str '>'} + ) + local link = pandoc.Link(author_with_mail, mailto) + table.insert(corresponding_authors, {link}) + end + end + if #corresponding_authors == 0 then + return nil + end + local correspondence = List:new{ + pandoc.Superscript(mark'corresponding_author'), + pandoc.Space(), + pandoc.Str'Correspondence:', + pandoc.Space() + } + local sep = List:new{pandoc.Str',', pandoc.Space()} + return { + pandoc.Para(correspondence .. intercalate(corresponding_authors, sep)) + } +end + +--- Generate a list of inlines containing all authors. +local function create_authors_inlines(authors, mark) + local inlines_generator = author_inline_generator(mark) + local inlines = List:new(authors):map(inlines_generator) + local and_str = List:new{pandoc.Space(), pandoc.Str'and', pandoc.Space()} + + local last_author = inlines[#inlines] + inlines[#inlines] = nil + local result = intercalate(inlines, {pandoc.Str ',', pandoc.Space()}) + if #authors > 1 then + result:extend(List:new{pandoc.Str ","} .. and_str) + end + result:extend(last_author) + return result +end + +return { + { + Pandoc = function (doc) + local meta = doc.meta + local body = List:new{} + + local mark = function (mark_name) return default_marks[mark_name] end + + body:extend(create_equal_contributors_block(doc.meta.author, mark) or {}) + body:extend(create_affiliations_blocks(doc.meta.institute) or {}) + body:extend(create_correspondence_blocks(doc.meta.author, mark) or {}) + body:extend(doc.blocks) + + -- Overwrite authors with formatted values. We use a single, formatted + -- string for most formats. LaTeX output, however, looks nicer if we + -- provide a authors as a list. + meta.author = FORMAT:match 'latex' + and pandoc.MetaList(doc.meta.author):map(author_inline_generator(mark)) + or pandoc.MetaInlines(create_authors_inlines(doc.meta.author, mark)) + -- Institute info is now baked into the affiliations block. + meta.institute = nil + + return pandoc.Pandoc(body, meta) + end + } +} \ No newline at end of file diff --git a/resources/author_profiles/_quarto-anonymized.yml b/resources/author_profiles/_quarto-anonymized.yml new file mode 100644 index 0000000..030d4a7 --- /dev/null +++ b/resources/author_profiles/_quarto-anonymized.yml @@ -0,0 +1,2 @@ +authors: + - name: Anonymous diff --git a/resources/author_profiles/_quarto-default.yml b/resources/author_profiles/_quarto-default.yml new file mode 100644 index 0000000..207dd70 --- /dev/null +++ b/resources/author_profiles/_quarto-default.yml @@ -0,0 +1,27 @@ +authors: + - name: John Doe + affiliations: + - ref: jdct + corresponding: true + email: john.doe@jdct.edu + orcid: 0000-1111-2222-3333 + equal-contributor: true + - name: John Roe + affiliations: + - ref: jdct + orcid: 0000-3333-2222-1111 + - name: Jane Roe + affiliations: + - ref: jdct + - ref: iot + orcid: 0000-2222-1111-3333 + equal-contributor: true + +affiliations: + - id: jdct + name: John Doe Center for Technology, John Doe University, Doetown, Germany. + - id: iot + name: Institute of Technology, John Doe University, Doetown, Germany. + +filters: + - ../resources/authors_block/authors-block.lua diff --git a/resources/authors_block/authors-block.lua b/resources/authors_block/authors-block.lua new file mode 100644 index 0000000..c47d8de --- /dev/null +++ b/resources/authors_block/authors-block.lua @@ -0,0 +1,71 @@ +--[[ +authors-block – affiliations block extension for quarto + +Copyright (c) 2023 Lorenz A. Kapsner + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +]] + +local List = require 'pandoc.List' + +-- [import] +local from_utils = require "utils" +local normalize_affiliations = from_utils.normalize_affiliations +local normalize_authors = from_utils.normalize_authors +local normalize_latex_authors = from_utils.normalize_latex_authors + +local from_authors = require "from_author_info_blocks" +local default_marks = from_authors.default_marks +local create_equal_contributors_block = from_authors.create_equal_contributors_block +local create_affiliations_blocks = from_authors.create_affiliations_blocks +local create_correspondence_blocks = from_authors.create_correspondence_blocks +local is_corresponding_author = from_authors.is_corresponding_author +local author_inline_generator = from_authors.author_inline_generator +local create_authors_inlines = from_authors.create_authors_inlines +-- [/import] + +-- This is the main-part +function Pandoc(doc) + local meta = doc.meta + local body = List:new{} + + -- Support both `authors:` and `author:` YAML keys; skip if no valid author list + local authors = meta.authors or meta.author + if authors == nil or authors[1] == nil or authors[1].name == nil then + return doc + end + meta.authors = List:new(authors) + + local mark = function (mark_name) return default_marks[mark_name] end + + body:extend(create_equal_contributors_block(meta.authors, mark) or {}) + body:extend(create_affiliations_blocks(meta.affiliations) or {}) + body:extend(create_correspondence_blocks(meta.authors, mark) or {}) + body:extend(doc.blocks) + + for _i, author in ipairs(meta.authors) do + author.test = is_corresponding_author(author) + end + + meta.affiliations = normalize_affiliations(meta.affiliations) + meta.author = meta.authors:map(normalize_authors(meta.affiliations)) + + -- Overwrite authors with formatted values. We use a single, formatted + -- string for most formats. LaTeX output, however, looks nicer if we + -- provide a authors as a list. + meta.author = pandoc.MetaInlines(create_authors_inlines(meta.author, mark)) + -- Institute info is now baked into the affiliations block. + meta.affiliations = nil + + return pandoc.Pandoc(body, meta) +end diff --git a/resources/authors_block/from_author_info_blocks.lua b/resources/authors_block/from_author_info_blocks.lua new file mode 100644 index 0000000..8a39c31 --- /dev/null +++ b/resources/authors_block/from_author_info_blocks.lua @@ -0,0 +1,201 @@ +-- https://github.com/pandoc/lua-filters/commit/ca72210b453cc0d045360e0ae36448d019d7dfbf +--[[ +affiliation-blocks – generate title components + +Copyright © 2017–2021 Albert Krewinkel + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +]] + +-- from @kapsner +-- [import] +local from_utils = require "utils" +local has_key = from_utils.has_key +-- [/import] +local M = {} + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +local List = require 'pandoc.List' +local utils = require 'pandoc.utils' +local stringify = utils.stringify + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +local default_marks +local default_marks = { + corresponding_author = FORMAT == 'latex' + and {pandoc.RawInline('latex', '*')} + or {pandoc.Str '✉'}, + equal_contributor = FORMAT == 'latex' + and {pandoc.RawInline('latex', '$\\dagger{}$')} + or {pandoc.Str '*'}, +} +M.default_marks = default_marks + +-- modified by @kapsner +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +local function is_equal_contributor(author) + if has_key(author, "attributes") then + return author.attributes["equal-contributor"] + end + return nil +end + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +--- Create equal contributors note. +local function create_equal_contributors_block(authors, mark) + local has_equal_contribs = List:new(authors):find_if(is_equal_contributor) + if not has_equal_contribs then + return nil + end + local contributors = { + pandoc.Superscript(mark'equal_contributor'), + pandoc.Space(), + pandoc.Str 'These authors contributed equally to this work.' + } + return List:new{pandoc.Para(contributors)} +end +M.create_equal_contributors_block = create_equal_contributors_block + + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +local function intercalate(lists, elem) + local result = List:new{} + for i = 1, (#lists - 1) do + result:extend(lists[i]) + result:extend(elem) + end + if #lists > 0 then + result:extend(lists[#lists]) + end + return result +end + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +--- Check whether the given author is a corresponding author +local function is_corresponding_author(author) + if has_key(author, "attributes") then + if author.attributes["corresponding"] then + return author.email + end + end + return nil +end +M.is_corresponding_author = is_corresponding_author + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +--- Generate a block element containing the correspondence information +local function create_correspondence_blocks(authors, mark) + local corresponding_authors = List:new{} + for _, author in ipairs(authors) do + if is_corresponding_author(author) then + local mailto = 'mailto:' .. utils.stringify(author.email) + local author_with_mail = List:new( + -- modified by @kapsner + author.name.literal .. List:new{pandoc.Space(), pandoc.Str '<'} .. + author.email .. List:new{pandoc.Str '>'} + ) + local link = pandoc.Link(author_with_mail, mailto) + table.insert(corresponding_authors, {link}) + end + end + if #corresponding_authors == 0 then + return nil + end + local correspondence = List:new{ + pandoc.Superscript(mark'corresponding_author'), + pandoc.Space(), + pandoc.Str'Correspondence:', + pandoc.Space() + } + local sep = List:new{pandoc.Str',', pandoc.Space()} + return { + pandoc.Para(correspondence .. intercalate(corresponding_authors, sep)) + } +end +M.create_correspondence_blocks = create_correspondence_blocks + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +--- Create inlines for a single author (includes all author notes) +local function author_inline_generator (get_mark) + return function (author) + local author_marks = List:new{} + -- modified by @kapsner + if has_key(author, "attributes") then + if author.attributes["equal-contributor"] then + author_marks[#author_marks + 1] = get_mark 'equal_contributor' + end + end + local idx_str + for _, idx in ipairs(author.affiliations) do + if type(idx) ~= 'table' then + idx_str = tostring(idx) + else + idx_str = stringify(idx) + end + author_marks[#author_marks + 1] = {pandoc.Str(idx_str)} + end + if is_corresponding_author(author) then + author_marks[#author_marks + 1] = get_mark 'corresponding_author' + end + -- modified by @kapsner + if FORMAT:match 'latex' then + author.name.literal[#author.name.literal + 1] = pandoc.Superscript(intercalate(author_marks, {pandoc.Str ','})) + return author + else + local res = List.clone(author.name.literal) + res[#res + 1] = pandoc.Superscript(intercalate(author_marks, {pandoc.Str ','})) + return res + end + end +end +M.author_inline_generator = author_inline_generator + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +--- Generate a list of inlines containing all authors. +local function create_authors_inlines(authors, mark) + local inlines_generator = author_inline_generator(mark) + local inlines = List:new(authors):map(inlines_generator) + local and_str = List:new{pandoc.Space(), pandoc.Str'and', pandoc.Space()} + + local last_author = inlines[#inlines] + inlines[#inlines] = nil + local result = intercalate(inlines, {pandoc.Str ',', pandoc.Space()}) + if #authors > 1 then + if #authors == 2 then + result:extend(and_str) + else + result:extend(List:new{pandoc.Str ","} .. and_str) + end + end + result:extend(last_author) + return result +end +M.create_authors_inlines = create_authors_inlines + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/author-info-blocks/author-info-blocks.lua +--- Generate a block list all affiliations, marked with arabic numbers. +local function create_affiliations_blocks(affiliations) + local affil_lines = List:new(affiliations):map( + function (affil, i) + local num_inlines = List:new{ + pandoc.Superscript{pandoc.Str(affil.number)}, + pandoc.Space() + } + return num_inlines .. affil.name + end + ) + return {pandoc.Para(intercalate(affil_lines, {pandoc.LineBreak()}))} +end +M.create_affiliations_blocks = create_affiliations_blocks + +return M diff --git a/resources/authors_block/from_scholarly_metadata.lua b/resources/authors_block/from_scholarly_metadata.lua new file mode 100644 index 0000000..0ff7e81 --- /dev/null +++ b/resources/authors_block/from_scholarly_metadata.lua @@ -0,0 +1,59 @@ +--[[ +ScholarlyMeta – normalize author/affiliation meta variables + +Copyright (c) 2017-2021 Albert Krewinkel, Robert Winkler + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +]] + +local List = require 'pandoc.List' +local utils = require 'pandoc.utils' +local stringify = utils.stringify + +local M = {} + + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/scholarly-metadata/scholarly-metadata.lua +--- Returns a function which checks whether an object has the given ID. +local function has_id(id) + return function(x) return x.id == id end +end + + +-- taken from https://github.com/pandoc/lua-filters/blob/1660794b991c3553968beb993f5aabb99b317584/scholarly-metadata/scholarly-metadata.lua +--- Resolve institute placeholders to full named objects +local function resolve_institutes(institute, known_institutes) + local unresolved_institutes + if institute == nil then + unresolved_institutes = {} + elseif type(institute) == "string" or type(institute) == "number" then + unresolved_institutes = {institute} + else + unresolved_institutes = institute + end + + local result = List:new{} + for i, inst in ipairs(unresolved_institutes) do + -- this has been modified by @kapsner + --result[i] = + -- known_institutes[tonumber(inst)] or + -- known_institutes:find_if(has_id(pandoc.utils.stringify(inst))) or + -- to_named_object(inst) + intermed_val = known_institutes:find_if(has_id(stringify(inst))) + result[i] = pandoc.MetaString(stringify(intermed_val.index)) + end + return result +end +M.resolve_institutes = resolve_institutes + +return M \ No newline at end of file diff --git a/resources/authors_block/utils.lua b/resources/authors_block/utils.lua new file mode 100644 index 0000000..d0103ca --- /dev/null +++ b/resources/authors_block/utils.lua @@ -0,0 +1,62 @@ +--[[ +authors-block – affiliations block extension for quarto + +Copyright (c) 2023 Lorenz A. Kapsner + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +]] + +local List = require 'pandoc.List' +local utils = require 'pandoc.utils' +local stringify = utils.stringify + +-- [import] +local from_scholarly = require "from_scholarly_metadata" +local resolve_institutes = from_scholarly.resolve_institutes +-- [/import] + +local M = {} + +-- from @kapsner +local function normalize_affiliations(affiliations) + local affiliations_norm = List:new(affiliations):map( + function(affil, i) + affil.index = pandoc.MetaInlines(pandoc.Str(tostring(i))) + affil.id = pandoc.MetaString(stringify(affil.id)) + return affil + end + ) + return affiliations_norm +end +M.normalize_affiliations = normalize_affiliations + +-- from https://stackoverflow.com/a/2282547 +local function has_key(set, key) + return set[key] ~= nil +end +M.has_key = has_key + +-- from @kapsner +local function normalize_authors(affiliations) + return function(auth) + auth.id = pandoc.MetaString(stringify(auth.name)) + auth.affiliations = resolve_institutes( + auth.affiliations, + affiliations + ) + return auth + end +end +M.normalize_authors = normalize_authors + +return M diff --git a/resources/custom-reference-doc.docx b/resources/custom-reference-doc.docx new file mode 100644 index 0000000000000000000000000000000000000000..fd497d44d0044f7e7d4a959c4553a7f08fbea4e6 GIT binary patch literal 11040 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 DQbn3R literal 0 HcmV?d00001 diff --git a/resources/references.bib b/resources/references.bib new file mode 100644 index 0000000..0220dbd --- /dev/null +++ b/resources/references.bib @@ -0,0 +1,19 @@ +@article{knuth84, + author = {Knuth, Donald E.}, + title = {Literate Programming}, + year = {1984}, + issue_date = {May 1984}, + publisher = {Oxford University Press, Inc.}, + address = {USA}, + volume = {27}, + number = {2}, + issn = {0010-4620}, + url = {https://doi.org/10.1093/comjnl/27.2.97}, + doi = {10.1093/comjnl/27.2.97}, + journal = {Comput. J.}, + month = may, + pages = {97–111}, + numpages = {15} +} + + diff --git a/resources/scripts/split_titlepage.py b/resources/scripts/split_titlepage.py new file mode 100644 index 0000000..8982da8 --- /dev/null +++ b/resources/scripts/split_titlepage.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 +""" +split_titlepage.py + +Splits a Quarto-manuscript-rendered .docx into two files: + - -titlepage.docx : title, authors, affiliations (front matter) + - -body.docx : everything from the first section break onward + +Why this works: +Quarto's manuscript/scholarly docx title-block template emits a section +break ( inside a paragraph's ) immediately after the +title-block content, before the body begins. This script finds that first +section break in word/document.xml and splits there. + +Safety check: +Before writing output, the script verifies the "title page" portion +actually contains the document's title and at least one author name +(read from the source .qmd YAML front matter, or passed explicitly). +If this check fails, the script aborts with a clear error rather than +silently producing a wrong split - getting this wrong has real +deanonymization consequences for blind peer review. + +This script is self-contained (standard library only: zipfile, re, shutil) +and does NOT depend on any external docx-editing toolkit. It works directly +with the docx ZIP container, replacing only word/document.xml in each of +two copies of the original archive. + +Usage: + python split_titlepage.py INPUT.docx OUTDIR \ + --title "Title" --author "Jane Doe" [--author "John Q. Doe" ...] + +Exit codes: + 0 success + 1 split point not found + 2 safety check failed (title/author not found in detected title page) + 3 other error (bad args, file not found) +""" + +import argparse +import re +import shutil +import sys +import zipfile +from pathlib import Path + + +SECTPR_PATTERN = re.compile( + r']*>(?:(?!).)*?.*?', + re.DOTALL, +) + +# A bare sectPr also legitimately appears as the LAST element of body, +# as a direct child of (not inside a paragraph) -- that one +# describes the final/only section and is NOT a split point on its own. +# We only want sectPr that appears INSIDE a paragraph's pPr, which marks +# an explicit section break before the end of the document. + + +def find_first_section_break(document_xml: str) -> "tuple[int, int] | None": + """ + Returns (start, end) character offsets of the first paragraph + containing a section break, or None if not found. + """ + match = SECTPR_PATTERN.search(document_xml) + if not match: + return None + return match.span() + + +def strip_tags_for_text_check(xml_fragment: str) -> str: + """Crude tag stripping for a plain-text containment check.""" + text = re.sub(r'<[^>]+>', ' ', xml_fragment) + text = re.sub(r'\s+', ' ', text).strip() + return text + + +def read_document_xml(docx_path: Path) -> str: + with zipfile.ZipFile(docx_path, "r") as z: + return z.read("word/document.xml").decode("utf-8") + + +def write_docx_with_replaced_document_xml( + source_docx: Path, new_document_xml: str, dest_docx: Path +) -> None: + """Copy source_docx to dest_docx, replacing only word/document.xml.""" + with zipfile.ZipFile(source_docx, "r") as src: + with zipfile.ZipFile(dest_docx, "w", zipfile.ZIP_DEFLATED) as dst: + for item in src.infolist(): + data = src.read(item.filename) + if item.filename == "word/document.xml": + data = new_document_xml.encode("utf-8") + dst.writestr(item, data) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("input_docx", type=Path, help="Rendered anonymized .docx") + parser.add_argument("outdir", type=Path, help="Directory to write split output into") + parser.add_argument("--title", required=True, help="Document title, for the safety check") + parser.add_argument( + "--author", action="append", default=[], + help="Author name for the safety check; repeat flag for multiple authors" + ) + parser.add_argument( + "--authors", default=None, + help="Comma-separated author names for the safety check " + "(simpler alternative to repeating --author from a Taskfile)" + ) + parser.add_argument( + "--basename", default=None, + help="Base name for output files (default: input filename stem)" + ) + parser.add_argument( + "--allow-no-author-match", action="store_true", + help="Downgrade the author-match safety check from fatal to a warning" + ) + args = parser.parse_args() + + authors = list(args.author) + if args.authors: + authors.extend(a.strip() for a in args.authors.split(",") if a.strip()) + args.author = authors + + if not args.input_docx.exists(): + print(f"ERROR: input file not found: {args.input_docx}", file=sys.stderr) + sys.exit(3) + + basename = args.basename or args.input_docx.stem + args.outdir.mkdir(parents=True, exist_ok=True) + + print(f"Splitting title page from: {args.input_docx}") + + try: + xml = read_document_xml(args.input_docx) + except KeyError: + print("ERROR: word/document.xml not found inside the docx - is this a valid .docx?", + file=sys.stderr) + sys.exit(3) + + body_match = re.search(r"]*>(.*)", xml, re.DOTALL) + if not body_match: + print("ERROR: could not locate in document.xml", file=sys.stderr) + sys.exit(3) + body_start, body_end = body_match.span(1) + body_content = xml[body_start:body_end] + + split = find_first_section_break(body_content) + if split is None: + print( + "ERROR: no section break found in document body. " + "Expected Quarto's manuscript docx template to emit a " + "section break after the title block. Aborting split — " + "check that the source document actually came from the " + "manuscript title-block template.", + file=sys.stderr, + ) + sys.exit(1) + + _, split_end = split + titlepage_fragment = body_content[:split_end] + body_fragment = body_content[split_end:] + + # --- Safety check --- + titlepage_text = strip_tags_for_text_check(titlepage_fragment) + title_found = args.title.strip() != "" and args.title.strip() in titlepage_text + authors_found = [a for a in args.author if a.strip() and a.strip() in titlepage_text] + + print(f" Detected title page text (first 200 chars): {titlepage_text[:200]!r}") + + problems = [] + if not title_found: + problems.append(f"title {args.title!r} not found in detected title-page text") + if args.author and not authors_found: + problems.append( + f"none of the expected authors {args.author!r} found in detected title-page text" + ) + + if problems: + msg = ( + "SAFETY CHECK FAILED: the detected 'title page' section does not " + "appear to contain the expected title/author metadata:\n - " + + "\n - ".join(problems) + + "\nThis usually means the section-break detection found the " + "wrong split point. Refusing to write output to avoid a silent " + "deanonymization risk." + ) + if args.allow_no_author_match: + print(f"WARNING: {msg}\n(Continuing anyway because --allow-no-author-match was set.)", + file=sys.stderr) + else: + print(f"ERROR: {msg}", file=sys.stderr) + sys.exit(2) + else: + print(f" Safety check passed (title found: {title_found}, authors found: {authors_found})") + + def build_full_xml(body_inner: str) -> str: + return xml[:body_start] + body_inner + xml[body_end:] + + titlepage_out = args.outdir / f"{basename}-titlepage.docx" + body_out = args.outdir / f"{basename}-body.docx" + + write_docx_with_replaced_document_xml( + args.input_docx, build_full_xml(titlepage_fragment), titlepage_out + ) + write_docx_with_replaced_document_xml( + args.input_docx, build_full_xml(body_fragment), body_out + ) + + print(f"Done.\n Title page -> {titlepage_out}\n Body -> {body_out}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/resources/scripts/task_utils.py b/resources/scripts/task_utils.py new file mode 100644 index 0000000..96ef1f9 --- /dev/null +++ b/resources/scripts/task_utils.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +""" +task_utils.py — cross-platform file operations for the Taskfile pipeline. + +Replaces shell-specific commands (PowerShell Compress-Archive, Remove-Item, +etc.) with plain Python stdlib calls that behave identically on Windows, +Linux, and macOS. Called from Task as: + + python ../resources/scripts/task_utils.py [args...] + +Subcommands: + zip SRC_DIR DEST_ZIP + Zip the contents of SRC_DIR into DEST_ZIP (overwrites if it exists). + Fails with a clear message (exit 1) if SRC_DIR doesn't exist. + + zip-if-exists SRC_DIR DEST_ZIP + Same as `zip`, but exits 0 with a warning (no error) if SRC_DIR + doesn't exist, instead of failing. Used for optional things like + a project's data/ folder. + + clean-project PROJECT_DIR + Remove _output/, .quarto/, and any *_files/*_cache directories + found anywhere under PROJECT_DIR. Safe to call even if nothing + exists yet. + + copy-if-exists SRC DEST + Copy a single file from SRC to DEST if SRC exists; otherwise + print a warning and exit 0 (does not fail the pipeline). + + today + Print today's date as YYYY-MM-DD (used for the finalized/ folder + name). No platform-specific date command needed. +""" + +import shutil +import sys +import zipfile +from datetime import date +from pathlib import Path + + +def cmd_zip(src_dir: str, dest_zip: str, allow_missing: bool) -> int: + src = Path(src_dir) + dest = Path(dest_zip) + + if not src.exists() or not src.is_dir(): + msg = f"'{src}' does not exist or is not a directory" + if allow_missing: + print(f"WARNING: {msg} — skipping zip of {dest}") + return 0 + print(f"ERROR: {msg} — did you render first?", file=sys.stderr) + return 1 + + files = [p for p in src.rglob("*") if p.is_file()] + if not files: + msg = f"'{src}' exists but contains no files" + if allow_missing: + print(f"WARNING: {msg} — skipping zip of {dest}") + return 0 + print(f"ERROR: {msg}", file=sys.stderr) + return 1 + + dest.parent.mkdir(parents=True, exist_ok=True) + if dest.exists(): + dest.unlink() + + with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as zf: + for f in files: + zf.write(f, f.relative_to(src)) + + print(f"Created {dest} ({len(files)} files)") + return 0 + + +def cmd_clean_project(project_dir: str) -> int: + root = Path(project_dir) + + for name in ("_output", ".quarto"): + target = root / name + if target.exists(): + shutil.rmtree(target, ignore_errors=True) + print(f"Removed {target}") + + for pattern in ("*_files", "*_cache"): + for match in root.rglob(pattern): + if match.is_dir(): + shutil.rmtree(match, ignore_errors=True) + print(f"Removed {match}") + + return 0 + +def cmd_clean_zips(project_dir: str) -> int: + root = Path(project_dir) + + for match in root.rglob("*.zip"): + if match.is_file(): + shutil.rmtree(match, ignore_errors=True) + print(f"Removed {match}") + + return 0 + +def cmd_copy_if_exists(src: str, dest: str) -> int: + src_path = Path(src) + dest_path = Path(dest) + + if not src_path.exists(): + print(f"WARNING: '{src_path}' not found, skipping copy") + return 0 + + dest_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src_path, dest_path) + print(f"Copied {src_path} -> {dest_path}") + return 0 + + +def cmd_today() -> int: + print(date.today().isoformat()) + return 0 + + +def main() -> int: + if len(sys.argv) < 2: + print(__doc__, file=sys.stderr) + return 1 + + subcommand = sys.argv[1] + args = sys.argv[2:] + + if subcommand == "zip": + if len(args) != 2: + print("usage: task_utils.py zip SRC_DIR DEST_ZIP", file=sys.stderr) + return 1 + return cmd_zip(args[0], args[1], allow_missing=False) + + if subcommand == "zip-if-exists": + if len(args) != 2: + print("usage: task_utils.py zip-if-exists SRC_DIR DEST_ZIP", file=sys.stderr) + return 1 + return cmd_zip(args[0], args[1], allow_missing=True) + + if subcommand == "clean-project": + if len(args) != 1: + print("usage: task_utils.py clean-project PROJECT_DIR", file=sys.stderr) + return 1 + return cmd_clean_project(args[0]) + + if subcommand == "clean-zips": + if len(args) != 1: + print("usage: task_utils.py clean-zips PROJECT_DIR", file=sys.stderr) + return 1 + return cmd_clean_zips(args[0]) + + if subcommand == "copy-if-exists": + if len(args) != 2: + print("usage: task_utils.py copy-if-exists SRC DEST", file=sys.stderr) + return 1 + return cmd_copy_if_exists(args[0], args[1]) + + if subcommand == "today": + return cmd_today() + + print(f"ERROR: unknown subcommand '{subcommand}'", file=sys.stderr) + print(__doc__, file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file