Compare commits

...

61 commits

Author SHA1 Message Date
1e6c9059e8 feat(content): Add event logistics experience 2025-03-26 18:07:25 +01:00
434cb0717e fix(cv): Remove summary from CV 2025-03-19 16:21:22 +01:00
b061d853bc fix(cv): Fix CV creation 2025-03-19 14:17:28 +01:00
51b43f4d9c
ref(lib): Move all logic to lib
The *.typ files in root will only make use of the backing library,
invoking the bare mininum.
2025-03-19 13:50:14 +01:00
21d2010762
ref(repo): Refactor resume into single importable function
Moved all 'behind-the-scenes' structure to 'lib/' folder and made resume
importable as the main utility.
2025-03-19 12:53:42 +01:00
eace89411b
fix(content): Remove duplicate Roskilde University 2025-03-19 12:53:42 +01:00
1afc51a857
feat(resume): Add wrapit library to dynamically add sidebar
Removes issue that grid will be static throughout all pages and thus
empty space where the sidebar is on page 1. Now, the sidebar aligns
nicely along the first page but then we can use the full width for the
next few pages.
2025-03-19 12:53:41 +01:00
bb9606b2db
fix(content): Rephrase partial completion of BA 2025-03-19 12:53:41 +01:00
2970745b7d
ref(resume): Extract column creation from resume func
Extracted into their own functions called 'create_main' and
'create_sidebar' for now.
2025-03-19 12:53:40 +01:00
f404bf3c55
feat(sidebar): Make sidebar visible backgrounded
Just add a grey background for now.
2025-03-19 12:53:40 +01:00
72d40e5094
ref(smartypants): Move smartypants application to lib 2025-03-19 12:53:39 +01:00
df480875df
ref(lib): Rename skill_item to sidebar_entry
We use the function for all entries in the sidebar (volunteering,
languages, etc) not just skills.
2025-03-19 12:53:38 +01:00
c831b008b9
ref(resume): Move by_client and by_experience_type to lib
In the continuous process of moving everything away from the main resume
body, move these experience functions away.
2025-03-19 12:53:38 +01:00
37c59e71db
docs: Update README
Give light hints to how the section arrays work.
2025-03-19 12:53:37 +01:00
1a62b90df7
feat(resume): Add ability to reorder sections
Both in main and in sidebar, sections can be reordered simply by
changing the order they appar in the array adding them.

`#resume.with(main:("education", "experience"))` displays education
before experience items.
2025-03-19 12:53:37 +01:00
f60991344d
feat(resume): Choose experience display by client,type,chronological
Can be set by setting the point in 'main' array to
'experience_by_client', 'experience_by_type' or just 'experience'
respectively.
2025-03-19 12:53:36 +01:00
0dd715d806
fix(content): Rephrase ZeitRaum support consultations 2025-03-19 12:53:36 +01:00
948510fb13 Move element styling and smartypants to lib 2025-03-17 12:07:40 +01:00
b333e2f2db
ref(letter): Remove quarto letter 2025-03-17 12:07:40 +01:00
dd482390a2
Ensure build dir before make
Always ensure the build dir exists before trying to create files within.
Each target creates the directory if necessary.
2025-02-04 10:31:48 +01:00
bbde91c97e
Fix phrasing 2025-01-29 11:52:45 +01:00
ca33cb142f
Begin deduplicating code with a lib
Starting to move the separated efforts of functionality between CV and
resume into a library from which to import. Will take additional
simplification still.
2025-01-29 11:52:17 +01:00
35ef95331d
Make sidebar margin smaller 2025-01-29 11:16:04 +01:00
7eee35dcfc
Switch digital skills around 2025-01-29 11:15:36 +01:00
cfaba8e954
Move AFD research project up above Roskilde projects 2025-01-29 11:15:12 +01:00
ddf5f0d9bd
Update address 2025-01-29 11:14:47 +01:00
8788c0a647
Update content slightly 2025-01-28 21:43:33 +01:00
c36a5cde83
Remove sel_word_lang function 2025-01-28 21:39:43 +01:00
0beef3934b
Hide unused experience types 2025-01-28 21:39:28 +01:00
18df7051e7
Format with typstyle 2025-01-28 21:30:59 +01:00
64dffb43d6
Fix english spellink HTWK country 2025-01-28 21:29:21 +01:00
cfa3e8a625
Allow manually overriding main or sidebar sections 2025-01-28 21:29:00 +01:00
03acad7a44
Add experience types to data 2025-01-28 21:07:14 +01:00
a81276f89b
Add separation by experience type 2025-01-28 21:06:17 +01:00
484ea7512e
Update Makefile for typst letter 2025-01-28 10:01:13 +01:00
1ea7afdaa5
Fix page counter for typst update 2025-01-28 10:00:25 +01:00
9d4c195ce9
Fix spelling issue 2025-01-28 09:59:42 +01:00
6f5d5ee378
Add bottom sidebar margin 2024-09-26 11:15:30 +02:00
4b63eed9e4
Update skills order, job capitalizations 2024-09-26 11:15:01 +02:00
3181a18b8c
Update Makefile for typst 2024-09-26 11:14:16 +02:00
c0678dbdf3
Remove leftover quarto generation files 2024-09-26 11:14:03 +02:00
f6730e38ce
Update summary texts 2024-09-19 17:31:55 +02:00
7a503d61fb
Allow setting sidebar or not for cv 2024-09-19 17:21:03 +02:00
f19fd2540c
Add resume with sidebar style 2024-09-19 17:15:45 +02:00
097cd1263d
Decouple languages from skills
Both retain the same yaml structure but are not tightly coupled anymore
(like volunteering before).
2024-09-17 17:52:09 +02:00
5df8458b72
Add sidebar to document 2024-09-17 17:50:30 +02:00
43549c1f53
Fix master thesis german translation 2024-09-17 15:57:08 +02:00
e53d5ca386
Refactor typst cv generation to make use of generalized entries 2024-09-15 17:56:18 +02:00
d518eb9087
Extract volunteering from qualifications
They deserve their own sections, now that I have volunteered for over a
year.
2024-09-15 17:55:55 +02:00
25d9e7ce13
Rename thesis and education to title and place
To fit the generalized entry scheme. The only issue I have is to have
the actual 'title' of the thesis in the 'place' field which feels very
unwieldy.
2024-09-15 17:55:12 +02:00
698ef628b2
Rename client to place in work experience
To start generalizing cv entries, since every 'work' has a place,
whether it is a client or not.
2024-09-15 17:53:40 +02:00
656c3e37d3
Remove commented text size 2024-09-15 12:35:30 +02:00
28b63a6f17
Add compatibility options for smartypants and latex
Convert en/em-dashes and escaped ampersands.
2024-09-15 11:31:41 +02:00
372dee59cc
Expand footer to more details and full name 2024-09-15 11:22:02 +02:00
a345d36611
Rephrase english summary 2024-09-15 11:21:38 +02:00
bdf8abfe95
Add clickable links to header contact information 2024-09-15 11:21:23 +02:00
50c2900b04
Section headers correctly change language 2024-09-15 08:34:33 +02:00
0ed2aa801c
Change contact mail address
to actual 'contact@martyoeh.me' to be more generalizable.
2024-09-15 08:34:02 +02:00
318ea11ac6
Add simple typst cv replacement 2024-09-14 22:13:34 +02:00
ed31e70a13
Add simple contact information to content 2024-09-14 22:13:05 +02:00
844f582aae
Shorten and rephrase English summary 2024-09-13 22:29:24 +02:00
20 changed files with 1077 additions and 3547 deletions

2
.gitignore vendored
View file

@ -51,7 +51,6 @@ dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
@ -62,6 +61,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
# lib/
# PyInstaller
# Usually these files are written by a python script from a template

View file

@ -1,13 +1,22 @@
.PHONY: clean
.PHONY: clean all
all: resume_*.qmd templates/jb2resume.latex letter.qmd templates/letter.latex
poetry run quarto render
all: clean cv resume letter
cv: resume_de.qmd resume_en.qmd templates/jb2resume.latex
poetry run quarto render resume_de.qmd resume_en.qmd
letter: letter.qmd templates/letter.latex
poetry run quarto render letter.qmd
cv: cv.typ
mkdir -p build
typst compile --input lang=en cv.typ build/cv_en.pdf
typst compile --input lang=de cv.typ build/cv_de.pdf
resume: resume.typ
mkdir -p build
typst compile --input lang=en resume.typ build/resume_en.pdf
typst compile --input lang=de resume.typ build/resume_de.pdf
letter: letter.typ
mkdir -p build
typst compile --input lang=en letter.typ build/letter_en.pdf
typst compile --input lang=de letter.typ build/letter_de.pdf
clean:
rm -f *CV.aux *CV.bcf *CV.log *CV.out *CV.run.xml *CV.pdf short_CV.tex long_CV.tex *CV.bbl *CV.blg *yaml_CV.md

67
README.md Normal file
View file

@ -0,0 +1,67 @@
# Data-driven CV & resume
My personal CV and resume files, automatically generated from a multi-lingual
yaml data file.
The CV contains a full run-down of my educational and job experience to date,
while the resume is more compact, reduced to a single page
and can be tailored for a specific job area or expertise.
Is called like the following:
```typst
#resume(
yaml("content.yml"),
main: ("experience", "education", "volunteering", "skills", "languages"),
sidebar: ("volunteering", "skills")
)
```
This is the default invocation, though sidebar and main body sections can be exchanged at will.
The following sections currently exist:
- education
- experience, subdivided in "experience", "experience_by_client" and "experience_by_type"
- languages
- skills
- summary
- volunteering
Sections in the main body or sidebar can be reordered at will.
## Advanced experience settings
The experience section has 3 forms:
Purely chronological ("experience"), which is the default;
separated by client worked for ("experience_by_client");
separated by the type of work undertaken, then further separated by client worked for ("experience_by_client").
These options are intended especially for self-employed / entrepreneurial CVs.
They let you subdivide your work experience whichever way works best,
and additionally divide work undertaken for your own employ or salaried positions for example.
TODO:
- [x] move double-resume sources (per langauge) to a variable or similar
- [x] separate volunteering from skills section
- [_] one function per skill section
- [_] resume prep:
- [ ] make experience groupable by client / short version
- [ ] enable display/hiding of sections/entries by tags?
- [x] migrate to typst template?
- [x] ! Fix german summary to be like English summary
- [_] generalized entry?
Would have 'title', 'place', 'date', 'type'/'tags' + potential
'publication', 'bullets'
## Typst-driven branch
- [x] Fix publication '\&'s
- [x] Fix en-dash/em-dash (e.g. in years)
- [x] Producable from yaml content
- [x] Can be switched between Ger/En
- [x] Try sidebar version
- [ ] Generalize sidebar version through abstraction/extractions
- [x] unify items: experience/education/(thesis?)

View file

@ -1,15 +0,0 @@
project:
output-dir: _output
format:
html: default
pdf:
latex-auto-mk: false
pdf-engine: tectonic
template: templates/jb2resume.latex
include-in-header:
- text: |
\usepackage{xcolor}
execute:
echo: false

View file

@ -1,45 +1,57 @@
about:
fullname: Marty Oehme
contact:
- text: Pichelsdorfer Str. 133, 13595 Berlin, Germany
icon:
- text: contact@martyoeh.me
icon:
link: mailto:contact@martyoeh.me
- text: +49 177 377 4949
icon:
link: tel:+491773774949
- text: martyoeh.me
icon:
link: https://martyoeh.me
- text: github.com/marty-oehme
icon:
link: https://github.com/marty-oehme
summary:
de: |
Ich habe im September 2021 das EU-geförderte European Master of Global Studies Studienprogramm absolviert,
mit dem Schwerpunkt globale Prozesse der Raumaneignung, Nationenbildung und narrativer Ideologien.
Seit dem Abschluss des EU-geförderten European Master of Global Studies Erasmus Mundus Programms im Jahr 2021 habe ich als selbstständiger Forschungsberater gearbeitet und mich auf Prozesse der Ungleichheit und der Armutsreduktion, sowie deren räumliche Dimensionierung und kollektive Organisation konzentriert, hauptsächlich betrachtet durch das Prisma der Arbeitsmarktpolitik.
Seitdem habe ich die Produktion verschiedener Entwicklungs-Forschungsliteratur unterstützt,
mit einem Fokus auf Arbeitsmarktpolitiken, ihren Auswirkungen auf Armut und kollektive Organisation,
sowie multi-dimensionaler Ungleichheitsreduktion.
Ich besitze ein breites Spektrum an Fähigkeiten in Datenerfassung, -organisation und -analyse,
Manuskriptbearbeitung und Literaturverwaltung,
und konnte erste Einblicke in Veranstaltungsmanagement, Lehrassistenz, Website-verwaltung und -inhaltserstellung gewinnen.
Der Rahmen meiner akademischen Arbeit erstreckt sich über Entwicklungsstudien, sozialen Schutz, Öko-Tourismus, und Arbeitsmarktstudien.
Abseits meiner professionellen Tätigkeiten interessiere ich mich für,
und befürworte aktiv,
die Produktion von freier und offener Software sowie
die Schaffung von Bedingungen für eine offene und barrierefreie Wissensproduktion.
Durch die Erstellung der entwickelnden Forschungsliteratur habe ich ein breites Spektrum an Fähigkeiten im Bereich der Datenerfassung, Organisation und Visualisierung entwickelt, sowie Erfahrungen in Manuskriptbearbeitung und Referenzmanagement erworben. Zusätzlich habe ich Einblicke in Event Management, Lehrassistentenarbeit, Content Creation, Systemadministration und Website-Management gewonnen. Jenseits meines beruflichen Engagements fördere ich den Aufbau freier und offener Software und Offener Wissenschaft ohne Barrieren.
Ich bin offen für Gelegenheiten, die meine Expertise in diesen Bereichen vertiefen, jedoch auch für solche, die meine Kenntnisbereiche erweitern.
en: |
I graduated from the EU-funded European Master of Global Studies programme in September 2021
with a focus on global processes of spatialization, nation-building and narrative ideologies.
Since completing the EU-funded European Master of Global Studies Erasmus Mundus programme in 2021, I have acted as a research consultant focused on processes of inequality and poverty reduction, spatialization and collective organization, primarily through the lens of labour market policies.
Since then I helped produce a variety of development research literature,
with a focus on labor market policies, their effects on poverty and collective organization, and multi-dimensional inequality reduction.
Through producing the development research literature I have developed a broad range of skills in data acquisition, organization and visualization, as well as manuscript editing and reference management. Additionally, I have gained insights into event management, teaching assistance, content creation, system and web administration. Beyond professional work I strive to foster the development of free and open software and open science without barriers.
I have developed a broad range of skills in data acquisition, organization and analysis,
manuscript editing and reference management,
as well as first insights into event management, teaching assistance, content creation and website management.
The range of my academic work has spanned development studies, tourism studies, social protection, American studies and security studies.
I welcome opportunities to advance my expertise in these topics, in addition to those expanding my range of applicable skills.
Aside from academic work I am interested in and an active proponent
of free and open software production and
creating the conditions for an open and barrier-free science production.
experience_types:
1:
de: Selbstständiger Schriftsteller Forschung
en: Independent research consultant
2:
de: Honorararbeit
en: Salaried work
3:
de: Gewerbeschein
en: Trade license
experience:
- date:
- typeid: 1
date:
de: 2024
en: 2024
title:
de: Co-Autor, Formalisierung und sozialer Schutz, World Development
en: Co-Author, Formalization and social protection, World Development
de: Co-Autor, Formalisierung und sozialer Schutz
en: Co-Author, Formalization and social protection
place:
de: World Development
en: World Development
publication:
de: 'Torm, N., \& Oehme, M. (2024). Social protection and formalization in low-and middle-income countries: A scoping review of the literature. World Development, 181.'
en: 'Torm, N., \& Oehme, M. (2024). Social protection and formalization in low-and middle-income countries: A scoping review of the literature. World Development, 181.'
@ -53,12 +65,30 @@ experience:
- date:
de: 2023--2024
en: 2023--2024
client:
de: ILO
en: ILO
typeid: 2
title:
de: Eventlogistik, Eventverwaltung und Logistikkoordination
en: Event logistics, event management and logistics coordination
place:
de: Belantis & EmiR Entertainment
en: Belantis & EmiR Entertainment
bullets:
- de: Betreuung des Aufbaus von Publikumsevents zwischen 100 und 1000 Gästen
en: Event setup for public events accommodating between 100 and 1000 guests
- de: Durchführung von Logistikarbeiten zur Vorbereitung der Eventflächen
en: Execution of logistics tasks in preparation for the respective event areas
- de: Verlagerung und Platzierung von Dekorations- und funktionellen Elementen an verschiedenen Standorten
en: Relocation and placement of decorative and functinoal elements at various locations
- date:
de: 2023--2024
en: 2023--2024
typeid: 1
title:
de: Externer Forscher, Ungleichheiten auf dem Arbeitsmarkt
en: External researcher, Inequalities on the Labour market
en: External researcher, Inequalities on the labour market
place:
de: ILO
en: ILO
publication:
de: ILO (angenommen). Addressing Inequalities in the World of Work.
en: ILO (forthcoming). Addressing Inequalities in the World of Work.
@ -72,9 +102,13 @@ experience:
- date:
de: 2023
en: 2023
typeid: 1
title:
de: Consultant, Forschungsarbeit für nachhaltige Beschaffung in internationaler Logistik, Refinter Consulting
en: Consultant, Research on sustainable procurement in international logistics, Refinter Consulting
de: Consultant, Forschungsarbeit für nachhaltige Beschaffung in internationaler Logistik
en: Consultant, Research on sustainable procurement in international logistics
place:
en: Refinter Consulting
de: Refinter Consulting
bullets:
- de: Qualitative Gegenüberstellung verschiedener Forschungsperspektiven im Lieferkettenmanagement
en: Qualitative comparison of various research strands within supply chain management
@ -85,12 +119,34 @@ experience:
- date:
de: 2022
en: 2022
client:
de: Universität Roskilde
en: Roskilde University
typeid: 1
title:
de: Forschungsassistenz, Entwicklungsprojekte zur Reduzierung Ungleichheitstrends
en: Research Assistant, Development projects to reduce inequality trends
place:
de: UNU-WIDER
en: UNU-WIDER
publication:
de: Niño-Zarazúa, M., \& Morabito, C. (angenommen). Assessing the potential distributional impacts of development interventions. UNU-WIDER.
en: Niño-Zarazúa, M., \& Morabito, C. (forthcoming). Assessing the potential distributional impacts of development interventions. UNU-WIDER.
bullets: # TODO: add numerical description of quantity of data (>2mil. datapoints)
- de: Sammlung, Verarbeitung und Bereinigung von 4 quantitativen Datensätzen, u.a. der UN Ungleichheitstrends
en: Collected, processed, and cleaned 4 datasets, including UN World inequality trends
- de: Durchführen einer beschreibenden Analyse von Ungleichheitstrends und -treibern in 4 Ländern
en: Conducted descriptive analysis of inequality trends and drivers in 4 countries
- de: Erstellen visueller Abbildungen der Daten und beschreibender Analysen der Entwicklungshilfen und ihrer Verteilung
en: Produced basic time-series visualizations and descriptive analysis of development aid contributions and their distribution
link: https://www.afd.fr/en/carte-des-projets/distributional-impact-development-cooperation-projects
- date:
de: 2022
en: 2022
typeid: 1
title:
de: Consultant, Datenbankforschung internationale Hilfsgelder
en: Consultant, Database research international aid funds
place:
de: Universität Roskilde
en: Roskilde University
bullets:
- de: Präsentation zu Einblick in digitaler Forschung in Datenbanken und Kodierungssystemen
en: Presentation of introduction to digital research in databases and coding systems
@ -101,12 +157,13 @@ experience:
- date:
de: 2022
en: 2022
client:
de: Universität Roskilde
en: Roskilde University
typeid: 1
title:
de: Redaktionsarbeit, Soziale Absicherung und Widerstandsfähigkeit
en: Editorial work, Social Protection and Resilience, Roskilde University
en: Editorial work, Social Protection and Resilience
place:
de: Universität Roskilde
en: Roskilde University
publication:
de: 'Torm, N., Gundertofte, C. M., \& Thur, G. E. (2022). Social Protection and Resilience during COVID-19: An Interdisciplinary Analysis of the Role of Informal Worker Associations in Kenya. Roskilde Universitet. SECO Working Paper Series Vol. 2022 No. 6.'
en: 'Torm, N., Gundertofte, C. M., \& Thur, G. E. (2022). Social Protection and Resilience during COVID-19: An Interdisciplinary Analysis of the Role of Informal Worker Associations in Kenya. Roskilde Universitet. SECO Working Paper Series Vol. 2022 No. 6.'
@ -120,32 +177,13 @@ experience:
- date:
de: 2022
en: 2022
client:
de: UNU-WIDER
en: UNU-WIDER
title:
de: Forschungsassistenz, Entwicklungsprojekte zur Reduzierung Ungleichheitstrends
en: Research Assistant, Development projects to reduce inequality trends
publication:
de: Niño-Zarazúa, M., \& Morabito, C. (angenommen). Assessing the potential distributional impacts of development interventions. UNU-WIDER.
en: Niño-Zarazúa, M., \& Morabito, C. (forthcoming). Assessing the potential distributional impacts of development interventions. UNU-WIDER.
bullets:
- de: Sammlung, Verarbeitung und Bereinigung von 4 quantitativen Datensätzen, u.a. der UN Ungleichheitstrends
en: Collected, processed, and cleaned 4 datasets, including UN World inequality trends
- de: Durchführen einer beschreibenden Analyse von Ungleichheitstrends und -treibern in 4 Ländern
en: Conducted descriptive analysis of inequality trends and drivers in 4 countries
- de: Erstellen visueller Abbildungen der Daten und beschreibender Analysen der Entwicklungshilfen und ihrer Verteilung
en: Produced basic time-series visualizations and descriptive analysis of development aid contributions and their distribution
link: https://www.afd.fr/en/carte-des-projets/distributional-impact-development-cooperation-projects
- date:
de: 2022
en: 2022
client:
de: ILO
en: ILO
typeid: 1
title:
de: Consultant, Review Verknüpfung sozialer Schutz, Produktivität und Formalisierung
en: Consultant, Social Protection, Productivity and Formalization Nexus Review
place:
de: ILO
en: ILO
publication:
de: "Torm, N. (forthcoming). The Social Protection, Productivity and Formalization Nexus among low- and middle- income countries: A Scoping Review of the Literature. International Labour Office."
en: "Torm, N. (forthcoming). The Social Protection, Productivity and Formalization Nexus among low- and middle- income countries: A Scoping Review of the Literature. International Labour Office."
@ -159,12 +197,13 @@ experience:
- date:
de: 2022
en: 2022
client:
de: Universität Roskilde
en: Roskilde University
typeid: 1
title:
de: Consultant, Review Arbeitsmarktpolitiken in Asien und dem Pazifik
en: Consultant, Labour Market Policies Review in Asia and the Pacific
place:
de: Universität Roskilde
en: Roskilde University
publication:
de: 'Niño-Zarazúa, M., \& Torm, N. (2022). Active Labour Market Policies in Asia and the Pacific: A review of the literature. Roskilde Universitet. SECO Working Paper Series Vol. 2022 No. 4.'
en: 'Niño-Zarazúa, M., \& Torm, N. (2022). Active Labour Market Policies in Asia and the Pacific: A review of the literature. Roskilde Universitet. SECO Working Paper Series Vol. 2022 No. 4.'
@ -176,12 +215,13 @@ experience:
- date:
de: 2021
en: 2021
client:
typeid: 1
title:
de: Forschungsassistenz, Informelle Organisierung und Absicherung
en: Research Assistant, Informal Organization and Social Security
place:
de: Universität Roskilde
en: Roskilde University
title:
de: Forschungsassistenz, informelle Organisierung und Absicherung
en: Research Assistant, informal organization and social security
publication:
de: Riisgaard, L. (2020). Worker Organisation and Social Protection amongst Informal Petty Traders in Tanzania. Roskilde Universitet. CAE Working Paper No. 2020:4
en: Riisgaard, L. (2020). Worker Organisation and Social Protection amongst Informal Petty Traders in Tanzania. Roskilde Universitet. CAE Working Paper No. 2020:4
@ -195,12 +235,13 @@ experience:
- date:
de: 2021
en: 2021
client:
typeid: 1
title:
de: Redakteur, Soziale Absicherung informeller Arbeiter (SPIWORK)
en: Editorial Assistant, Social Protection of Informal Workers (SPIWORK)
place:
de: Universität Roskilde
en: Roskilde University
title:
de: Redaktionsassistenz, SPIWORK-Projekt
en: Editorial Assistant, SPIWORK Project
publication:
de: 'Riisgaard, L., Mitullah, W.V., \& Torm, N. (Eds.). (2021). Social Protection and Informal Workers in Sub-Saharan Africa: Lived Realities and Associational Experiences from Tanzania and Kenya (1st ed.). Routledge.'
en: 'Riisgaard, L., Mitullah, W.V., \& Torm, N. (Ed.). (2021). Social Protection and Informal Workers in Sub-Saharan Africa: Lived Realities and Associational Experiences from Tanzania and Kenya (1st ed.). Routledge.'
@ -214,9 +255,13 @@ experience:
- date:
de: 2018--2019
en: 2018--2019
typeid: 2
title:
de: Akademische Hilfskraft, Institut für Amerikastudien, Universität Leipzig
en: Academic Assistant, Institute of American Studies, University of Leipzig
de: Akademische Hilfskraft, Institut für Amerikastudien
en: Academic Assistant, Institute of American Studies
place:
de: Universität Leipzig
en: University of Leipzig
bullets:
- de: Digitalisierung und Aufbereitung von Unterrichts- und Forschungsmaterialien
en: Digitized and optimized teaching and research materials
@ -227,9 +272,13 @@ experience:
- date:
de: 2017--2019
en: 2017--2019
typeid: 2
title:
de: Studentische Hilfskraft, Professor Crister S. Garrett, Universität Leipzig
en: Student Assistant, Professor Crister S. Garrett, University of Leipzig
de: Studentische Hilfskraft, Professor Crister S. Garrett
en: Student Assistant, Professor Crister S. Garrett
place:
de: Universität Leipzig
en: University of Leipzig
bullets:
- de: Digitalisierung und Bearbeitung ausgewählter Arbeitsmaterialien
en: Digitized and prepared selected working material
@ -240,9 +289,13 @@ experience:
- date:
de: 2018
en: 2018
typeid: 2
title:
de: Lehrassistenz, Transatlantische Sommerschule Cultures of Security, Universität Leipzig
en: Teaching Assistant, Trans Atlantic Summer School Cultures of Security, University of Leipzig
de: Lehrassistenz, Transatlantische Sommerschule Cultures of Security
en: Teaching Assistant, Trans Atlantic Summer School Cultures of Security
place:
de: Universität Leipzig
en: University of Leipzig
bullets:
- de: Vorbereitung, Organisation und Umsetzung von Lehrveranstaltungen und Events
en: Prepared, organized, and implemented schedule for teaching and events
@ -253,9 +306,13 @@ experience:
- date:
de: 2017--2018
en: 2017--2018
typeid: 2
title:
de: Content-Management, Bachelor Plus/Alumni-System, Universität Leipzig
en: Content Management, Bachelor Plus/Alumni System, University of Leipzig
de: Content-Management, Bachelor Plus/Alumni-System
en: Content Management, Bachelor Plus/Alumni System
place:
de: Universität Leipzig
en: University of Leipzig
bullets:
- de: Gemeinsame Erstellung und Strukturierung von Inhalten im Content-Management-System von Wordpress
en: Co-created and structured content in Wordpress content management system
@ -266,9 +323,14 @@ experience:
- date:
de: 2014--2018
en: 2014--2018
typeid: 2
hidden: true # TODO: Allow hiding entries like this?
title:
de: Verkaufsassistent und Eventhelfer für historische Märkte, Heureka Gastronomie
en: Sales Assistant and Event Support for Historical Markets, Heureka Gastronomy
de: Verkaufsassistent und Eventhelfer für historische Märkte
en: Sales Assistant and Event Support for Historical Markets
place:
de: Heureka Gastronomie
en: Heureka Gastronomy
bullets:
- de: Betreuung mehrerer Verkaufsstände, darunter Glühwein und Getränke, Grillstände und Handbrote
en: Managed multiple sales stands, including mulled wine and beverages, grill, and handbread stands
@ -281,7 +343,7 @@ education:
- place:
de: Universität Leipzig, Deutschland
en: University of Leipzig, Germany
program:
title:
de: European Master of Global Studies, MA
en: European Master of Global Studies, MA
date:
@ -290,7 +352,7 @@ education:
- place:
de: Universität Roskilde, Dänemark
en: Roskilde University, Denmark
program:
title:
de: Global Studies, MSc
en: Global Studies, MSc
date:
@ -299,7 +361,7 @@ education:
- place:
de: Universität Leipzig, Deutschland
en: University of Leipzig, Germany
program:
title:
de: Amerikanistik, BA
en: American Studies, BA
date:
@ -307,131 +369,161 @@ education:
en: 2018
- place:
de: HTWK Leipzig, Deutschland
en: HTWK Leipzig, Deutschland
program:
de: Medieninformatik, BSc (nicht abgeschlossen)
en: Media Computer Science, BSc (not completed)
en: HTWK Leipzig, Germany
title:
de: Medieninformatik, BSc (nicht abg.)
en: Media Computer Science, BSc (incompl.)
date:
de: 2015
en: 2015
thesis:
- type:
de: Master Thesis
- title:
de: Masterarbeit
en: Master Thesis
title:
de: "Re-Evaluating Nature's Gifts: Economic and Experiential Value Productions in Namibia's Ecotourism"
en: "Re-Evaluating Nature's Gifts: Economic and Experiential Value Productions in Namibia's Ecotourism"
abstract:
place:
de: "Re-Evaluating Nature's Gifts: Economic and Experiential Value Productions in Namibia's Ecotourism."
en: "Re-Evaluating Nature's Gifts: Economic and Experiential Value Productions in Namibia's Ecotourism."
abstract: # TODO: Rephrase this complete abstract since it's not worded well
de: Unter Verwendung einer theoretischen Grundlage von Macht wurden die Mechanismen der Konsensbildung bei der Produktion von Räumen im Ökotourismus analysiert. Durch die Anwendung kritischer Diskursanalyse auf die Fallstudie Namibia wurden verschiedene Arten der Wertschöpfung zwischen ökonomischen und erfahrungsbasierten Werten im Tourismus untersucht.
en: Used a theoretical basis of power to analyze the mechanisms of consensus shaping the production of ecotourism space. Utilizing critical discourse analysis on the case study of Namibia, it explored various means of value production between economic and experiential values in tourism.
volunteering:
- title:
de: ZeitRaum
en: ZeitRaum
date:
de: 2023--2024
en: 2023--2024
place:
de: Heizhaus e.V.
en: Heizhaus association
bullets:
- de: Vermittlung digitaler Kompetenzen im Alter
en: Transferring Digital Competence in Aging
- de: Wöchentlicher Workshop zur Entwicklung von Selbstvertrauen und Kompetenz mit Smartphones
en: Weekly workshop on developing confidence and competence with smartphones
- de: Personalisierte technische Unterstützung und personalisierte Einzelberatungen
en: Personalized tech assistance appointments and individual technical support consultations
- title:
de: Verpixelt
en: Verpixelt
date:
de: 2023
en: 2023
place:
de: Urban Souls e.V.
en: Urban Souls association
bullets:
- de: Technische Assistenz zur Vermittlung digitaler Kompetenzen
en: Technical assistance for conveying digital competencies
- de: IT und Event Organisationsunterstützung
en: IT and event management services
skills:
- de: Digitales Toolset
en: Digital toolset
content:
- name:
de: Versionskontrollsoftware
en: Version control software
items:
- de: Git
en: git
- name:
de: Office-Suite
en: Office suite
items:
- de: Excel
en: Excel
- de: Word
en: Word
- de: Access
en: Access
- name:
de: Autorensoftware
en: Authoring software
items:
- de: LaTeX
en: LaTeX
- de: Pandoc
en: pandoc
- de: Quarto
en: quarto
- name:
de: Web Content Management
en: Web content management
items:
- de: Wordpress
en: Wordpress
- de: Hugo
en: Hugo
- de: Flask
en: Flask
- de: Astro
en: Astro
- de: HTML
en: HTML
- de: CSS
en: CSS
- de: JavaScript
en: JavaScript
- name:
de: Datenanalyse
en: Data Analysis
items:
- de: Python Pandas
en: Python pandas
- de: Plotly
en: Plotly
- name:
de: Datenmanagement
en: Data engineering
items:
- de: Web-Scraping/-Crawling
en: Web-scraping/-crawling
- de: SQL
en: SQL
- name:
de: Design Software
en: Design software
items:
- de: GIMP
en: GIMP
- de: Adobe Suite
en: Adobe suite
# Add date information for volunteer work
- de: Ehrenamt
en: Volunteering work
content:
- name:
de: Verpixelt, Urban Souls e.V.
en: Verpixelt, Urban Souls association
items:
- de: technische Assistenz zur Vermittlung digitaler Kompetenzen
en: technical assistance for conveying digital competencies
- name:
de: ZeitRaum, Heizhaus e.V.
en: ZeitRaum, Heizhaus association
items:
- de: Vermittlung digitaler Kompetenzen im Alter, Workshop und Fragestunde
en: Transferring Digital Competence in Aging, Workshop and individual sessions
- de: Sprachen
en: Languages
content:
- name:
de: Deutsch
en: German
items:
- de: Muttersprache
en: native
- name:
de: Englisch
en: English
items:
- de: fließend
en: fluent
- name:
de: Französisch
en: French
items:
- de: Grundkenntnisse
en: basics
- name:
de: Office-Suite
en: Office suite
items:
- de: Excel
en: Excel
- de: Word
en: Word
- de: Access
en: Access
- name:
de: Autorensoftware
en: Authoring software
items:
- de: Typst
en: Typst
- de: LaTeX
en: LaTeX
- de: Quarto
en: Quarto
- de: Pandoc
en: Pandoc
- name:
de: Datenmanagement
en: Data engineering
items:
- de: SQL
en: SQL
- de: Web-Scraping & Crawling
en: Web-scraping & crawling
- name:
de: Datenanalyse
en: Data analysis
items:
- de: Python Pandas & Polars
en: Python Pandas & Polars
- de: Seaborn
en: Seaborn
- name:
de: Programmieren
en: Programming
items:
- de: Python
en: Python
- de: Go
en: Go
- de: Bash
en: Bash
- de: Lua
en: Lua
- name:
de: Versionskontrollsoftware
en: Version control software
items:
- de: Git
en: Git
- de: Jujutsu
en: Jujutsu
# - de: Fossil
# en: Fossil
- name:
de: Web Content Management
en: Web content management
items:
# - de: Wordpress
# en: Wordpress
- de: Hugo
en: Hugo
- de: Flask
en: Flask
# - de: Astro
# en: Astro
- de: HTML
en: HTML
- de: CSS
en: CSS
- de: JavaScript
en: JavaScript
- name:
de: Design Software
en: Design software
items:
- de: GIMP
en: GIMP
- de: Adobe Suite
en: Adobe suite
languages:
- name:
de: Deutsch
en: German
items:
- de: Muttersprache
en: native
- name:
de: Englisch
en: English
items:
- de: fließend
en: fluent
- name:
de: Französisch
en: French
items:
- de: Grundkenntnisse
en: basics

7
cv.typ Normal file
View file

@ -0,0 +1,7 @@
#import "lib/resume.typ": resume
#resume.with(
main: ("experience", "education", "volunteering", "skills", "languages"),
sidebar:()
)(yaml("content.yml"))

View file

@ -1,53 +0,0 @@
---
backaddress: Marty Oehme, Körnerstraße 54, 04107 Leipzig
fromname: Marty Oehme
fromaddress: |
Körnerstraße 54
04107 Leipzig
fromphone: "0177 / 377 49 49"
place: Leipzig, DAY MONTH YEAR
placeseparator: " "
sendto: |
NAME OF COMPANY
ITS ADDRESS STREET AND NUMBER
LOCATION ZIPCODE
lang: en
subject: Bewerbung für JOBSTELLE
signature: Marty Oehme
opening: Dear CONTACTNAME
closing: Sincerely
format:
pdf:
template: templates/letter.latex
---
After two years of cooperation, I recently finished the final in a row of projects undertaken as consultant for UNU-WIDER and the ILO.
I am glad to have happened upon your job posting for the position of project officer as part-time worker with minimum 32 hours, as for me it may allow a more medium term stability than the previous short-term freelance positions did.
Over the previous two years, I have primarily provided research assistance for three major projects under the helm of the UN, the ILO and Roskilde University:
In addition to the descriptive analysis undertaken for all of these projects,
my consultancy for UNU-WIDER required the creation of a time-series visualization on the basis of empirical analysis over roughly 200.000 observations within the UN's WIID dataset.
The previous work for the ILO and Roskilde University instead consisted of deep research for the creation of wide-ranging scoping reviews,
which necessitated collecting, organizing and cleaning datasets of around 2000 source potentials.
I accomplished both of these tasks more efficiently with the help of Python and its data analysis modules which is also where my primary statistical programming focus lies.
Additionally, I have long been helping publish academic, particularly empirical, works,
first in the role of academic assistant and later on as editorial consultant.
Perhaps most personally beneficial for the current position was the publication of a large academic anthology under the SPIWORK project:
During this time I worked with clients located internationally,
collaborating directly to create clear and concise manuscripts for each individual topic,
before merging the divergent aspects into a final coherent whole while also fulfilling publisher's formal requirements.
I would love to bring both the analytical and editorial skillsets together in my new work,
to be able to push them forward in tandem.
Lastly, my skills of communication, especially international communication skills, have been honed throughout this time as I was both participant and leader of small (from 3 people) to medium-sized (up to 8 people) teams.
Collaboration in this way was both exciting and straightforward for me,
and I firmly believe concise and clear communication both engenders easier productivity flows
and is fundamental to the ability to precisely frame topics as complex as energy transition.
My interactions with processes of both long-term energy planning and renewables-based electrification of end-use sectors primarily stem from research undertaken in Vietnam and Benin under the helm of the Agence française de développement,
where the eventual distributional impact of access to clean water and new energy grids provided the project's focus.
I have, however, both the willingness and curiosity to dive deeper into these topics and their related issues of regulatory frameworks, financing and policy framing.
I will be happy to hear back from you and am confident that I could be a good match.
Should you agree that my profile is a good fit for the offered position then do not hesitate to contact me and I would be delighted to arrange a meeting.

182
lib/lib.typ Normal file
View file

@ -0,0 +1,182 @@
// transform md-similes to actual symbols
#let smartypants(it) = {
// smartypants and latex compatibility
show "--": [#sym.dash.en]
show "---": [#sym.dash.em]
show "\&": [#sym.amp]
it
}
// set some styles
#let style(it) = {
show heading: set text(font: "New Computer Modern")
show link: underline
show: smartypants
it
}
// Choose the compiled language through cli by doing
//
// $ typst compile --input lang=de cv.typ
//
#let lang = {
if "lang" in sys.inputs and sys.inputs.lang == "de" {
"de"
} else {
"en"
}
}
#let _columns_3(left_body, center_body, right_body) = {
block[
#box(width: 1fr)[
#align(left)[#left_body]
]
#box(width: 1fr)[
#align(center)[#center_body]
]
#box(width: 1fr)[
#align(right)[#right_body]
]
]
}
#let header(about, columns: (1.5fr, 1fr, 1fr)) = {
[= #about.fullname]
let contact_fields = (
for c in about.contact {
if "link" in c {
([#c.icon ~ #link(c.link)[#c.text]],)
} else {
([#c.icon ~ #c.text],)
}
}
)
grid(
columns: columns,
gutter: 5pt,
..contact_fields
)
}
#let subdued(body) = {
block(inset: 5%, width: 85%, text(fill: luma(150), body))
}
#let entry(item: ()) = {
if "title" in item {
[*#item.title.at(lang)*]
}
if "place" in item {
if "title" in item {
[, ]
}
[_#item.place.at(lang)_]
}
[#h(1fr)]
if "date" in item {
[ _#item.date.at(lang)_ \ ]
}
if "bullets" in item {
for bullet in item.bullets {
[- #bullet.at(lang)]
}
}
if "publication" in item {
subdued[#item.publication.at(lang) \ ]
}
if "abstract" in item {
subdued[#item.abstract.at(lang) \ ]
}
}
#let sidebar_entry(item: (), is_sidebar: false) = {
let side_list(body) = if is_sidebar { list(body) } else { par(body) }
for skill in item {
side_list({
[*#skill.name.at(lang)*]
if is_sidebar [\ ] else [ (]
for (i, v) in skill.items.enumerate() {
[#v.at(lang)]
if i < skill.items.len() - 1 {
[, ]
}
}
if not is_sidebar [)]
})
}
}
#let horizon_line() = {
v(-3pt)
line(length: 100%)
v(-5pt)
}
#let section_header(title) = {
[== #title]
horizon_line()
};
#let section(title: "Section", entries: (), body) = {
section_header(title)
if body == none or body == [] {
for e in entries {
entry(item: e)
}
} else {
body
}
};
// TODO: make it _return_ the data, not display it on its own
#let by_client(experience: ()) = {
let by_client = (:)
for item in experience {
let client = item.place.at(lang)
if client not in by_client {
by_client.insert(client, ())
}
by_client.at(client).push((title: item.title.at(lang), date: item.date.at(lang)))
}
for (client, jobs) in by_client {
[*#client*:]
for j in jobs {
[- #j.title #h(1fr) #j.date]
}
}
}
#let by_experience_type(type: (), experience: ()) = {
let by_ty = (:)
for (id, desc) in type {
let matching_exp_items = experience.filter(item => int(item.typeid) == int(id))
if matching_exp_items.len() == 0 {
return
}
[=== _#desc.at(lang)_]
by_client(experience: matching_exp_items)
}
}
// Slightly re-styled entry with PLACE first and TITLE second
#let education_entry(item: ()) = {
assert(
"place" in item and "title" in item and "date" in item,
message: "Education items require place, program and date.",
)
[*#item.place.at(lang)*, #item.title.at(lang) #h(1fr)]
[ _#item.date.at(lang)_ \ ]
}
// Restyled entry with PLACE not emphasized like usual, and no date but an abstract
#let thesis_entry(item: ()) = {
assert("title" in item and "place" in item, message: "Thesis items require type and title.")
[*#item.title.at(lang)* #item.place.at(lang) #h(1fr)]
[#par(item.abstract.at(lang))]
}

162
lib/resume.typ Normal file
View file

@ -0,0 +1,162 @@
#import "lib.typ": *
#import "wrapit.typ": *
#let create_body(main: (), contents: (:)) = {
for item in main {
if item == "summary" and "summary" in contents {
section(
title: "",
{
contents.summary.at(lang)
},
)
}
if item == "experience_by_type" and "experience" in contents {
let title = (en: "Professional Experience", de: "Berufserfahrung").at(lang)
section(title: title)[]
by_experience_type(experience: contents.experience, type: contents.experience_types)
}
if item == "experience_by_client" and "experience" in contents {
let title = (en: "Professional Experience", de: "Berufserfahrung").at(lang)
section(title: title)[]
by_client(experience: contents.experience)
}
if item == "experience" and "experience" in contents {
let title = (en: "Professional Experience", de: "Berufserfahrung").at(lang)
section(title: title, entries: contents.experience)[]
}
if item == "education" and "education" in contents {
let title = (en: "Education", de: "Ausbildung").at(lang)
section(title: title, entries: contents.thesis + contents.education)[]
}
if item == "volunteering" and "volunteering" in contents {
let title = (en: "Volunteer Work", de: "Ehrenamt").at(lang)
section(title: title, entries: contents.volunteering)[]
}
if item == "skills" and "skills" in contents {
let title = (en: "Qualifications", de: "Qualifikationen").at(lang)
section(
title: title,
{
sidebar_entry(item: contents.skills)
},
)
}
if item == "languages" and "languages" in contents {
let title = (en: "Languages", de: "Sprachen").at(lang)
section(
title: title,
{
sidebar_entry(item: contents.languages)
},
)
}
}
}
#let create_sidebar(sidebar: (), contents: (:)) = {
for item in sidebar {
if item == "volunteering" and "volunteering" in contents {
let title = (en: "Volunteer Work", de: "Ehrenamt").at(lang)
[== #title]
for e in contents.at("volunteering") {
[
- *#e.title.at(lang)* (#e.date.at(lang))
#par(e.bullets.at(0).at(lang)) \
]
}
}
if item == "languages" and "languages" in contents {
let title = (en: "Languages", de: "Sprachen").at(lang)
[== #title]
sidebar_entry(item: contents.languages, is_sidebar: true)
[\ ]
}
if item == "skills" and "skills" in contents {
let title = (en: "Qualifications", de: "Kenntnisse").at(lang)
[== #title]
sidebar_entry(item: contents.skills, is_sidebar: true)
}
}
}
#let resume(contents, main: ("experience_by_type", "education"), sidebar: ("volunteering", "languages", "skills")) = {
show: style
set text(lang: lang)
let date_formatting = {
if lang == "de" {
"[day]. [month repr:long] [year]"
} else {
"[month repr:long] [day], [year]"
}
}
set page(
paper: "a4",
margin: (x: 0.9cm, y: 1.3cm),
footer: [
#set text(
fill: luma(200),
size: 8pt,
)
#_columns_3[
#smallcaps[#datetime.today().display(date_formatting)]
][
#smallcaps[#contents.about.fullname]
][
#context counter(page).display()
]
],
)
set par(justify: true)
header(contents.about)
set block(above: 10pt)
show heading.where(level: 1): it => style(s => {
let h = text(size: 18pt, upper(it))
let dim = measure(h, s)
stack(
dir: ltr,
h,
place(
dy: 7pt,
dx: 10pt,
horizon + left,
line(stroke: accent-color, length: 100% - dim.width - 10pt),
),
)
})
let margin = 1pt
let sb = if sidebar.len() > 0 {
block(
fill: luma(230),
inset: (top: 15 * margin, left: 10 * margin, right: 15 * margin, bottom: 15 * margin),
{
show heading: it => align(right, upper(it))
set list(marker: "")
show list: it => {
set par(justify: false)
align(right, block(it))
}
create_sidebar(sidebar: sidebar, contents: contents)
},
)
} else { [] }
wrap-content(
sb,
create_body(main: main, contents: contents),
align: top + right,
columns: (auto, 30%),
)
}

340
lib/wrapit.typ Normal file
View file

@ -0,0 +1,340 @@
// https://github.com/ntjess/wrap-it?tab=readme-ov-file
#let styled = text(red)[lorem].func()
#let _gridded(dir, fixed, to-wrap, ..kwargs) = {
let dir-kwargs = (:)
if dir not in (ltr, rtl) {
panic("Specify either `rtl` or `ltr` as the wrap direction")
}
let args = if dir == rtl {
(to-wrap, fixed)
} else {
(fixed, to-wrap)
}
grid(..args, columns: 2, rows: 2, column-gutter: 1em, ..kwargs)
}
#let _grid-height(content, container-size) = {
measure(box(width: container-size.width, content)).height
}
#let _get-chunk(words, end, reverse, start: 0) = {
if end < 0 {
return words.join(" ")
}
if reverse {
words = words.rev()
}
let subset = words.slice(start, end)
if reverse {
subset = subset.rev()
}
subset.join(" ")
}
#let _get-wrap-index(height-func, words, goal-height, reverse) = {
for index in range(1, words.len(), step: 1) {
let cur-height = height-func(_get-chunk(words, index, reverse))
if cur-height > goal-height {
return index - 1
}
}
return -1
}
#let _rewrap(element, new-content) = {
let fields = element.fields()
for key in ("body", "text", "children", "child") {
if key in fields {
let _ = fields.remove(key)
}
}
let positional = (new-content,)
if "styles" in fields {
positional.push(fields.remove("styles"))
}
element.func()(..fields, ..positional)
}
#let split-other(body, height-func, goal-height, align, splitter-func) = {
(wrapped: none, rest: body)
}
#let split-has-text(body, height-func, goal-height, align, splitter-func) = {
let words = body.text.split(" ")
let reverse = align.y == bottom
let wrap-index = _get-wrap-index(height-func, words, goal-height, reverse)
let _rewrap = _rewrap.with(body)
if wrap-index > 0 {
let chunk = _rewrap(_get-chunk(words, wrap-index, reverse))
let end-chunk = _rewrap(_get-chunk(words, words.len(), reverse, start: wrap-index))
(
wrapped: context {
chunk
linebreak(justify: par.justify)
},
rest: end-chunk,
)
} else {
(wrapped: none, rest: body)
}
}
#let split-has-children(body, height-func, goal-height, align, splitter-func) = {
let reverse = align.y == bottom
let children = if reverse {
body.children.rev()
} else {
body.children
}
for (ii, child) in children.enumerate() {
let prev-children = children.slice(0, ii).join()
let new-height-func(child) = {
height-func((prev-children, child).join())
}
let height = new-height-func(child)
if height <= goal-height {
continue
}
// height func calculator should now account for prior children
let split = splitter-func(child, new-height-func, goal-height, align)
let new-children = (..children.slice(0, ii), split.wrapped)
let new-rest = children.slice(ii + 1)
if split.rest != none {
new-rest.insert(0, split.rest)
}
if reverse {
new-children = new-children.rev()
new-rest = new-rest.rev()
}
return (
wrapped: _rewrap(body, new-children),
rest: _rewrap(body, new-rest),
)
}
panic("This function should only be called if the seq child should be split")
}
#let split-has-body(body, height-func, goal-height, align, splitter-func) = {
// Elements that can be split and have a 'body' field.
let splittable = (strong, emph, underline, stroke, overline, highlight, list.item, styled)
let new-height-func(content) = {
height-func(_rewrap(body, content))
}
let args = (new-height-func, goal-height, align, splitter-func)
let body-text = body.at("body", default: body.at("child", default: none))
if body.func() in splittable {
let result = splitter-func(body-text, new-height-func, goal-height, align)
if result.wrapped != none {
return (wrapped: _rewrap(body, result.wrapped), rest: _rewrap(body, result.rest))
} else {
return split-other(body, ..args)
}
}
// Shape doesn't split nicely, so treat it as unwrappable
return split-other(body, ..args)
}
#let splitter(body, height-func, goal-height, align) = {
let self-height = height-func(body)
if self-height <= goal-height {
return (wrapped: body, rest: none)
}
if type(body) == str {
body = text(body)
}
let body-splitter = if body.has("text") {
split-has-text
} else if body.has("body") or body.has("child") {
split-has-body
} else if body.has("children") {
split-has-children
} else {
split-other
}
return body-splitter(body, height-func, goal-height, align, splitter)
}
#let _inner-wrap-content(to-wrap, y-align, grid-func, container-size, ..grid-kwargs) = {
let height-func(txt) = _grid-height(grid-func(txt), container-size)
let goal-height = height-func([])
if y-align == top {
goal-height += measure(v(1em)).height
}
let result = splitter(to-wrap, height-func, goal-height, y-align)
if y-align == top {
grid-func(result.wrapped)
result.rest
} else {
result.rest
grid-func(result.wrapped)
}
}
/// Places `to-wrap` next to `fixed`, wrapping `to-wrap` as its height overflows `fixed`.
///
/// *Basic Use:*
/// ```typ
/// #let body = lorem(40)
/// #wrap-content(rect(fill: teal), body)
/// ```
///
/// *Something More Fun:*
/// ```typ
/// #set par(justify: true)
/// // Helpers; not required
/// #let grad(map) = {
/// gradient.linear(
/// ..eval("color.map." + map)
/// )
/// }
/// #let make-fig(fill) = {
/// set figure.caption(separator: "")
/// fill = grad(fill)
/// figure(
/// rect(fill: fill, radius: 0.5em),
/// caption: [],
/// )
/// }
/// #let (fig1, fig2) = {
/// ("viridis", "plasma").map(make-fig)
/// }
/// #wrap-content(fig1, body, align: right)
/// #wrap-content(fig2, [#body #body], align: bottom)
/// ```
///
/// Note that you can increase the distance between a figure's bottom and the wrapped
/// text by boxing it with an inset:
/// ```typ
/// #let spaced = box(
/// make-fig("rocket"),
/// inset: (bottom: 0.3em)
/// )
/// #wrap-content(spaced, body)
/// ```
///
/// - fixed (content): Content that will not be wrapped, (i.e., a figure).
///
/// - to-wrap (content): Content that will be wrapped, (i.e., text). Currently, logic
/// works best with pure-text content, but hypothetically will work with any `content`.
///
/// - align (alignment): Alignment of `fixed` relative to `to-wrap`. `top` will align
/// the top of `fixed` with the top of `to-wrap`, and `bottom` will align the bottom of
/// `fixed` with the bottom of `to-wrap`. `left` and `right` alignments determine
/// horizontal alignment of `fixed` relative to `to-wrap`. Alignments can be combined,
/// i.e., `bottom + right` will align the bottom-right corner of `fixed` with the
/// bottom-right corner of `to-wrap`.
/// ```typ
/// #wrap-content(
/// make-fig("turbo"),
/// body,
/// align: bottom + right
/// )
/// ```
///
/// - size (size, auto): Size of the wrapping container. If `auto`, this will be set to
/// the current container size. Otherwise, wrapping logic will attempt to stay within
/// the provided constraints.
///
/// - ..grid-kwargs (any): Keyword arguments to pass to the underlying `grid` function.
/// Of note:
/// - `column-gutter` controls horizontal margin between `fixed` and `to-wrap`. Or,
/// you can surround the fixed content in a box with `(inset: ...)` for more
/// fine-grained control.
/// - `columns` can be set to force sizing of `fixed` and `to-wrap`. For instance,
/// `columns: (50%, 50%)` will force `fixed` and `to-wrap` to each take up half
/// of the available space. If content isn't this big, the fill will be blank
/// margin.
/// ```typ
/// #let spaced = box(
/// make-fig("mako"), inset: 0.5em
/// )
/// #wrap-content(spaced, body)
/// ```
/// ```typ
/// #wrap-content(
/// make-fig("spectral"),
/// body,
/// align: bottom,
/// columns: (50%, 50%),
/// )
/// ```
///
#let wrap-content(
fixed,
to-wrap,
align: top + left,
size: auto,
..grid-kwargs,
) = {
if center in (align.x, align.y) {
panic("Center alignment is not supported")
}
// "none" x alignment defaults to left
let dir = if align.x == right {
rtl
} else {
ltr
}
let gridded(..args) = box(_gridded(dir, fixed, ..grid-kwargs, ..args))
// "none" y alignment defaults to top
let y-align = if align.y == bottom {
bottom
} else {
top
}
if size != auto {
_inner-wrap-content(to-wrap, y-align, gridded, size, ..grid-kwargs)
} else {
layout(container-size => {
_inner-wrap-content(to-wrap, y-align, gridded, container-size, ..grid-kwargs)
})
}
}
/// Wrap a body of text around two pieces of content. The logic only works if enough text
/// exists to overflow both the top and bottom content. Use this instead of 2 separate
/// `wrap-content` calls if you want to avoid a paragraph break between the top and bottom
/// content.
///
/// *Example:*
/// ```typ
/// #let fig1 = make-fig("inferno")
/// #let fig2 = make-fig("rainbow")
/// #wrap-top-bottom(fig1, fig2, lorem(60))
/// ```
/// - top-fixed (content): Content that will not be wrapped, (i.e., a figure).
/// - bottom-fixed (content): Content that will not be wrapped, (i.e., a figure).
/// - body (content): Content that will be wrapped, (i.e., text)
/// - top-kwargs (any): Keyword arguments to pass to the underlying `wrap-content` function
/// for the top content. `x` alignment is kept (left/right), but `y` alignment is
/// overridden to `top`.
/// - bottom-kwargs (any): Keyword arguments to pass to the underlying `wrap-content` function
/// for the bottom content. `x` alignment is kept (left/right), but `y` alignment is
/// overridden to `bottom`.
///
#let wrap-top-bottom(
top-fixed,
bottom-fixed,
body,
top-kwargs: (:),
bottom-kwargs: (:),
) = {
top-kwargs = top-kwargs + (
align: top-kwargs.at("align", default: top + left).x + top,
)
bottom-kwargs = bottom-kwargs + (
align: bottom-kwargs.at("align", default: bottom + right).x + bottom,
)
layout(size => {
let wrapfig(..args) = wrap-content(size: size, ..args)
wrapfig(top-fixed, ..top-kwargs)[
#wrapfig(bottom-fixed, ..bottom-kwargs)[
#body
]
]
})
}

2295
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

View file

@ -1,92 +0,0 @@
from typing import Any
def summary_to_md(data: dict[str, Any], lang: str = "en", headline: str = ""):
if "summary" not in data:
return ""
md = f"{headline}\n\n {data['summary'][lang]}\n\n"
return md
def _publication_md(publication: str, subdued: bool):
md = "> "
if subdued:
md += "\\textcolor{publication}{"
md += publication
if subdued:
md += "}"
return f"{md}\n\n"
def experience_to_md(
data: dict[str, Any],
lang: str = "en",
headline: str = "",
subdued_publications: bool = True, # slightly off-color presentation
bulletpoints_show: bool = True, # display detailed bulletpoints per job
):
if "experience" not in data:
return ""
md = f"{headline}\n\n"
md += "\\definecolor{publication}{rgb}{0.5,0.5,0.5}\n\n"
for exp in data["experience"]:
client = exp["client"][lang] if "client" in exp else ""
title = exp["title"][lang] if "title" in exp else ""
md += (
# new python 3.12 f-string embedding niceness
f"## {title}{f", {client}" if client else ""}\\hfill{exp['date'][lang]}\n\n"
)
if "publication" in exp:
md += _publication_md(exp["publication"][lang], subdued_publications)
if bulletpoints_show:
for point in exp["bullets"]:
md += f"* {point[lang]}\n"
md += "\n\n"
return md
def thesis_to_md(data: dict[str, Any], lang: str = "en"):
md = ""
for thesis in data["thesis"]:
md += f"{thesis['type'][lang]}\n"
md += f": {thesis['title'][lang]}\n"
md += f": {thesis['abstract'][lang]}\n"
return f"{md}\n"
def education_to_md(
data: dict[str, Any], lang: str = "en", headline: str = "", thesis: bool = True
):
if "education" not in data:
return ""
md = f"{headline}\n\n"
if thesis and "thesis" in data:
md += thesis_to_md(data, lang)
for edu in data["education"]:
md += (
f"{edu['place'][lang]}\n\n: {edu['program'][lang]}; {edu['date'][lang]}\n\n"
)
return md
def qualifications_to_md(data: dict[str, Any], lang: str = "en", headline: str = ""):
if "skills" not in data:
return ""
md = f"{headline}\n\n"
for skillset in data["skills"]:
md += f"{skillset[lang]}\n\n"
for content in skillset["content"]:
md += f": {content['name'][lang]} ({', '.join([item[lang] for item in content['items']])})\n"
md += "\n"
return md

View file

@ -1,9 +0,0 @@
import yaml
DEFAULT_FILE = "content.yml"
def parse(fname: str = DEFAULT_FILE):
with open(fname, mode="rb") as f:
return yaml.safe_load(f)

View file

@ -1,22 +0,0 @@
[tool.poetry]
name = "resume"
version = "0.1.0"
description = "My personal curriculum vitae"
authors = ["Marty Oehme <marty.oehme@gmail.com>"]
license = "GPLv3"
packages = [
{ include = "processing"}
]
[tool.poetry.dependencies]
python = "^3.11"
PyYAML = "^6.0"
jupyter = "^1.0.0"
[tool.poetry.group.dev.dependencies]
pynvim = "^0.4.3"
pyperclip = "^1.8.2"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

3
resume.typ Normal file
View file

@ -0,0 +1,3 @@
#import "lib/resume.typ": resume
#resume.with()(yaml("content.yml"))

View file

@ -1,47 +0,0 @@
---
title: Lebenslauf
subtitle: Marty Oehme
name: Marty Oehme
lang: de
left-column:
- "Email: [marty.oehme@gmail.com](mailto:marty.oehme@gmail.com)"
- "Telefon: +49 177 377 4949"
right-column:
- "Homepage: [http://martyoeh.me/](http://martyoeh.me/)"
- "GitHub: [https://github.com/marty-oehme/](https://github.com/marty-oehme/)"
- 'Stand: \today'
---
```{python}
from processing import yml, content
from IPython.display import Markdown
data = yml.parse("content.yml")
lang = "de"
```
```{python}
#| label: summary
display(Markdown(content.summary_to_md(data, headline="# Zusammenfassung", lang=lang)))
```
```{python}
#| label: prof experience
display(
Markdown(content.experience_to_md(data, headline="# Berufserfahrung", lang=lang))
)
```
```{python}
#| label: education
display(Markdown(content.education_to_md(data, headline="# Ausbildung", lang=lang)))
```
```{python}
#| label: qualifications
display(
Markdown(
content.qualifications_to_md(data, headline="# Qualifikationen", lang=lang)
)
)
```

View file

@ -1,51 +0,0 @@
---
title: Curriculum Vitae
subtitle: Marty Oehme
name: Marty Oehme
lang: en
left-column:
- "Email: [marty.oehme@gmail.com](mailto:marty.oehme@gmail.com)"
- "Mobile: +49 177 377 4949"
right-column:
- "Homepage: [http://martyoeh.me/](http://martyoeh.me/)"
- "GitHub: [https://github.com/marty-oehme/](https://github.com/marty-oehme/)"
- 'Last Updated: \today'
---
```{python}
from processing import yml, content
from IPython.display import Markdown
data = yml.parse("content.yml")
lang = "en"
```
```{python}
#| label: summary
display(Markdown(content.summary_to_md(data, headline="# Summary", lang=lang)))
```
```{python}
#| label: prof experience
display(
Markdown(
content.experience_to_md(
data,
headline="# Professional experience",
lang=lang,
)
)
)
```
```{python}
#| label: education
display(Markdown(content.education_to_md(data, headline="# Education", lang=lang)))
```
```{python}
#| label: qualifications
display(
Markdown(content.qualifications_to_md(data, headline="# Qualifications", lang=lang))
)
```

View file

@ -1,103 +0,0 @@
% LaTeX Resume Pandoc Template jb2resume.latex
%
% Copyright (c) 2016-2017, John Bokma
% Based on Jason Blevins' LaTeX CV Template;
% http://jblevins.org/projects/cv-template/
%
% GitHub: https://github.com/john-bokma/resume-pandoc
\documentclass[$if(fontsize)$$fontsize$$else$10pt$endif$,letterpaper]{article}
\usepackage{hyperref}
\usepackage{geometry}
\usepackage{enumitem}
\usepackage{underscore}
\usepackage[parfill]{parskip}
\usepackage{lmodern}
\usepackage[svgnames]{xcolor}
\usepackage[utf8]{inputenc}
% Your name on the resume
\def\name{$name$}
% The following metadata will show up in the PDF properties
\hypersetup{
colorlinks = true,
urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$,
linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$,
pdfauthor = {\name},
pdfkeywords = {$keywords$},
pdftitle = {\name: Curriculum Vitae},
pdfsubject = {Curriculum Vitae},
pdfpagemode = UseNone
}
\geometry{
left=0.5in,
top=0.5in,
right=0.5in,
}
\renewcommand{\baselinestretch}{1}
% Fix for "! Undefined control sequence. <recently read> \tightlist",
% see: https://github.com/osener/markup.rocks/issues/4
% I have this issue with Pandoc 1.17.2
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
% Page number is top right, and it is possible to control the rest of
% the header.
\pagestyle{myheadings}
\markright{\name}
\thispagestyle{empty}
% Custom section fonts
\usepackage{sectsty}
$if(section-color)$
\sectionfont{\color{$section-color$}\sffamily\bfseries\Large}
$else$
\sectionfont{\rmfamily\mdseries\Large}
$endif$
\subsectionfont{\rmfamily\mdseries\itshape\large}
% Section numbers or not (default)
$if(numbersections)$
\setcounter{secnumdepth}{5}
$else$
\setcounter{secnumdepth}{0}
$endif$
% By putting an empty \item[] at the start of the list, the list
% starts on a new line.
\setlist[itemize]{leftmargin=1em,label={--},before=\item[]}
\setlist[description]{leftmargin=0em, style=sameline}
% Don't use monospace font for URLs
\urlstyle{same}
\begin{document}
% Place name at left
$if(name-color)$
{\huge\color{$name-color$}\sffamily\bfseries \name}
$else$
{\huge \name}
$endif$
\bigskip
$if(left-column)$
\begin{minipage}[t]{0.495\textwidth}
$for(left-column)$$left-column$$sep$ \\ $endfor$
\end{minipage} % Don't use empty lines after \end and the next \begin{minipage}.
$endif$
$if(right-column)$
\begin{minipage}[t]{0.495\textwidth}
$for(right-column)$$right-column$$sep$ \\ $endfor$
\end{minipage}
$endif$
$body$
\end{document}

View file

@ -1,645 +0,0 @@
%
% Options for packages loaded elsewhere
%
% taken with gratitude from:
% https://github.com/benedictdudel/pandoc-letter-din5008
%
\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
\PassOptionsToPackage{hyphens}{url}
$if(colorlinks)$
\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor}
$endif$
$if(CJKmainfont)$
\PassOptionsToPackage{space}{xeCJK}
$endif$
%
\documentclass[
$if(fontsize)$
$fontsize$,
$endif$
$if(papersize)$
$papersize$paper,
$endif$
$if(beamer)$
ignorenonframetext,
$if(handout)$
handout,
$endif$
$if(aspectratio)$
aspectratio=$aspectratio$,
$endif$
$endif$
$for(classoption)$
$classoption$$sep$,
$endfor$
]{scrlttr2}
$if(beamer)$
$if(background-image)$
\usebackgroundtemplate{%
\includegraphics[width=\paperwidth]{$background-image$}%
}
$endif$
\usepackage{pgfpages}
\setbeamertemplate{caption}[numbered]
\setbeamertemplate{caption label separator}{: }
\setbeamercolor{caption name}{fg=normal text.fg}
\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
$for(beameroption)$
\setbeameroption{$beameroption$}
$endfor$
% Prevent slide breaks in the middle of a paragraph
\widowpenalties 1 10000
\raggedbottom
$if(section-titles)$
\setbeamertemplate{part page}{
\centering
\begin{beamercolorbox}[sep=16pt,center]{part title}
\usebeamerfont{part title}\insertpart\par
\end{beamercolorbox}
}
\setbeamertemplate{section page}{
\centering
\begin{beamercolorbox}[sep=12pt,center]{part title}
\usebeamerfont{section title}\insertsection\par
\end{beamercolorbox}
}
\setbeamertemplate{subsection page}{
\centering
\begin{beamercolorbox}[sep=8pt,center]{part title}
\usebeamerfont{subsection title}\insertsubsection\par
\end{beamercolorbox}
}
\AtBeginPart{
\frame{\partpage}
}
\AtBeginSection{
\ifbibliography
\else
\frame{\sectionpage}
\fi
}
\AtBeginSubsection{
\frame{\subsectionpage}
}
$endif$
$endif$
$if(beamerarticle)$
\usepackage{beamerarticle} % needs to be loaded first
$endif$
\usepackage{amsmath,amssymb}
$if(linestretch)$
\usepackage{setspace}
$endif$
\usepackage{iftex}
\ifPDFTeX
\usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
$if(mathspec)$
\ifXeTeX
\usepackage{mathspec} % this also loads fontspec
\else
\usepackage{unicode-math} % this also loads fontspec
\fi
$else$
\usepackage{unicode-math} % this also loads fontspec
$endif$
\defaultfontfeatures{Scale=MatchLowercase}$-- must come before Beamer theme
\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
$if(fontfamily)$
$else$
$-- Set default font before Beamer theme so the theme can override it
\usepackage{lmodern}
$endif$
$-- Set Beamer theme before user font settings so they can override theme
$if(beamer)$
$if(theme)$
\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
$endif$
$if(colortheme)$
\usecolortheme{$colortheme$}
$endif$
$if(fonttheme)$
\usefonttheme{$fonttheme$}
$endif$
$if(mainfont)$
\usefonttheme{serif} % use mainfont rather than sansfont for slide text
$endif$
$if(innertheme)$
\useinnertheme{$innertheme$}
$endif$
$if(outertheme)$
\useoutertheme{$outertheme$}
$endif$
$endif$
$-- User font settings (must come after default font and Beamer theme)
$if(fontfamily)$
\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
$endif$
\ifPDFTeX\else
% xetex/luatex font selection
$if(mainfont)$
\setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
$endif$
$if(sansfont)$
\setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
$endif$
$if(monofont)$
\setmonofont[$for(monofontoptions)$$monofontoptions$$sep$,$endfor$]{$monofont$}
$endif$
$for(fontfamilies)$
\newfontfamily{$fontfamilies.name$}[$for(fontfamilies.options)$$fontfamilies.options$$sep$,$endfor$]{$fontfamilies.font$}
$endfor$
$if(mathfont)$
$if(mathspec)$
\ifXeTeX
\setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
\else
\setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
\fi
$else$
\setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
$endif$
$endif$
$if(CJKmainfont)$
\ifXeTeX
\usepackage{xeCJK}
\setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
\fi
$endif$
$if(luatexjapresetoptions)$
\ifLuaTeX
\usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
\fi
$endif$
$if(CJKmainfont)$
\ifLuaTeX
\usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
\setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
\fi
$endif$
\fi
$if(zero-width-non-joiner)$
%% Support for zero-width non-joiner characters.
\makeatletter
\def\zerowidthnonjoiner{%
% Prevent ligatures and adjust kerning, but still support hyphenating.
\texorpdfstring{%
\TextOrMath{\nobreak\discretionary{-}{}{\kern.03em}%
\ifvmode\else\nobreak\hskip\z@skip\fi}{}%
}{}%
}
\makeatother
\ifPDFTeX
\DeclareUnicodeCharacter{200C}{\zerowidthnonjoiner}
\else
\catcode`^^^^200c=\active
\protected\def ^^^^200c{\zerowidthnonjoiner}
\fi
%% End of ZWNJ support
$endif$
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
\usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
$if(indent)$
$else$
\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
$endif$
$if(verbatim-in-note)$
\usepackage{fancyvrb}
$endif$
\usepackage{xcolor}
$if(geometry)$
$if(beamer)$
\geometry{$for(geometry)$$geometry$$sep$,$endfor$}
$else$
\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
$endif$
$endif$
$if(beamer)$
\newif\ifbibliography
$endif$
$if(listings)$
\usepackage{listings}
\newcommand{\passthrough}[1]{#1}
\lstset{defaultdialect=[5.3]Lua}
\lstset{defaultdialect=[x86masm]Assembler}
$endif$
$if(lhs)$
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
$endif$
$if(highlighting-macros)$
$highlighting-macros$
$endif$
$if(tables)$
\usepackage{longtable,booktabs,array}
$if(multirow)$
\usepackage{multirow}
$endif$
\usepackage{calc} % for calculating minipage widths
$if(beamer)$
\usepackage{caption}
% Make caption package work with longtable
\makeatletter
\def\fnum@table{\tablename~\thetable}
\makeatother
$else$
% 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}
$endif$
$endif$
$if(graphics)$
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
$endif$
$if(svg)$
\usepackage{svg}
$endif$
$if(strikeout)$
$-- also used for underline
\usepackage{soul}
$endif$
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
$if(numbersections)$
\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
$else$
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
$endif$
$if(beamer)$
$else$
$if(block-headings)$
% Make \paragraph and \subparagraph free-standing
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
$endif$
$endif$
$if(pagestyle)$
\pagestyle{$pagestyle$}
$endif$
$if(csl-refs)$
\newlength{\cslhangindent}
\setlength{\cslhangindent}{1.5em}
\newlength{\csllabelwidth}
\setlength{\csllabelwidth}{3em}
\newlength{\cslentryspacingunit} % times entry-spacing
\setlength{\cslentryspacingunit}{\parskip}
\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
{% don't indent paragraphs
\setlength{\parindent}{0pt}
% turn on hanging indent if param 1 is 1
\ifodd #1
\let\oldpar\par
\def\par{\hangindent=\cslhangindent\oldpar}
\fi
% set entry spacing
\setlength{\parskip}{#2\cslentryspacingunit}
}%
{}
\usepackage{calc}
\newcommand{\CSLBlock}[1]{#1\hfill\break}
\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
$endif$
$if(lang)$
\ifLuaTeX
\usepackage[bidi=basic]{babel}
\else
\usepackage[bidi=default]{babel}
\fi
$if(babel-lang)$
\babelprovide[main,import]{$babel-lang$}
$endif$
$for(babel-otherlangs)$
\babelprovide[import]{$babel-otherlangs$}
$endfor$
% get rid of language-specific shorthands (see #6817):
\let\LanguageShortHands\languageshorthands
\def\languageshorthands#1{}
$endif$
$for(header-includes)$
$header-includes$
$endfor$
\ifLuaTeX
\usepackage{selnolig} % disable illegal ligatures
\fi
$if(dir)$
\ifPDFTeX
\TeXXeTstate=1
\newcommand{\RL}[1]{\beginR #1\endR}
\newcommand{\LR}[1]{\beginL #1\endL}
\newenvironment{RTL}{\beginR}{\endR}
\newenvironment{LTR}{\beginL}{\endL}
\fi
$endif$
$if(natbib)$
\usepackage[$natbiboptions$]{natbib}
\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
$endif$
$if(biblatex)$
\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
$for(bibliography)$
\addbibresource{$bibliography$}
$endfor$
$endif$
$if(nocite-ids)$
\nocite{$for(nocite-ids)$$it$$sep$, $endfor$}
$endif$
$if(csquotes)$
\usepackage{csquotes}
$endif$
\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\urlstyle{$if(urlstyle)$$urlstyle$$else$same$endif$}
$if(links-as-notes)$
% Make links footnotes instead of hotlinks:
\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
$endif$
$if(verbatim-in-note)$
\VerbatimFootnotes % allow verbatim text in footnotes
$endif$
\hypersetup{
$if(title-meta)$
pdftitle={$title-meta$},
$endif$
$if(author-meta)$
pdfauthor={$author-meta$},
$endif$
$if(lang)$
pdflang={$lang$},
$endif$
$if(subject)$
pdfsubject={$subject$},
$endif$
$if(keywords)$
pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
$endif$
$if(colorlinks)$
colorlinks=true,
linkcolor={$if(linkcolor)$$linkcolor$$else$Maroon$endif$},
filecolor={$if(filecolor)$$filecolor$$else$Maroon$endif$},
citecolor={$if(citecolor)$$citecolor$$else$Blue$endif$},
urlcolor={$if(urlcolor)$$urlcolor$$else$Blue$endif$},
$else$
$if(boxlinks)$
$else$
hidelinks,
$endif$
$endif$
pdfcreator={LaTeX via pandoc}}
$if(title)$
\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
$endif$
$if(subtitle)$
$if(beamer)$
$else$
\usepackage{etoolbox}
\makeatletter
\providecommand{\subtitle}[1]{% add subtitle to \maketitle
\apptocmd{\@title}{\par {\large #1 \par}}{}{}
}
\makeatother
$endif$
\subtitle{$subtitle$}
$endif$
\author{$for(author)$$author$$sep$ \and $endfor$}
\date{$date$}
$if(beamer)$
$if(institute)$
\institute{$for(institute)$$institute$$sep$ \and $endfor$}
$endif$
$if(titlegraphic)$
\titlegraphic{\includegraphics{$titlegraphic$}}
$endif$
$if(logo)$
\logo{\includegraphics{$logo$}}
$endif$
$endif$
% OVERRIDES
\newkomavar{opening}
\newkomavar{closing}
\KOMAoptions{fromemail=false}
\KOMAoptions{fromfax=false}
\KOMAoptions{fromlogo=false}
\KOMAoptions{frommobilephone=false}
\KOMAoptions{fromphone=false}
\KOMAoptions{fromurl=false}
\KOMAoptions{fromalign=right}
\setkomavar{opening}{Sehr geehrte Damen und Herren,}
\setkomavar{closing}{Mit freundlichen Grüßen}
\setkomavar*{enclseparator}{Anlagen}
$for(letteroption)$
\LoadLetterOption{$letteroption$}
$endfor$
$if(addresseeimage)$\setkomavar{addresseeimage}{$addresseeimage$}$endif$
$if(backaddress)$\setkomavar{backaddress}{$backaddress$}\KOMAoptions{backaddress=true}$endif$
$if(backaddressseparator)$\setkomavar{backaddressseparator}{$backaddressseparator$}$endif$
$if(ccseparator)$\setkomavar{ccseparator}{$ccseparator$}$endif$
$if(customer)$\setkomavar{customer}{$customer$}$endif$
% $if(date)$\setkomavar{date}{$date$}$endif$
$if(emailseparator)$\setkomavar{emailseparator}{$emailseparator$}$endif$
$if(enclseparator)$\setkomavar{enclseparator}{$enclseparator$}$endif$
$if(faxseparator)$\setkomavar{faxseparator}{$faxseparator$}$endif$
$if(firstfoot)$\setkomavar{firstfoot}{$firstfoot$}$endif$
$if(firsthead)$\setkomavar{firsthead}{$firsthead$}$endif$
$if(fromaddress)$\setkomavar{fromaddress}{$fromaddress$}$endif$
$if(frombank)$\setkomavar{frombank}{$frombank$}$endif$
$if(fromemail)$\setkomavar{fromemail}{$fromemail$}\KOMAoptions{fromemail=true}$endif$
$if(fromfax)$\setkomavar{fromfax}{$fromfax$}\KOMAoptions{fromfax=true}$endif$
$if(fromlogo)$\setkomavar{fromlogo}{$fromlogo$}\KOMAoptions{fromlogo=true}$endif$
$if(frommobilephone)$\setkomavar{frommobilephone}{$frommobilephone$}\KOMAoptions{frommobilephone=true}$endif$
$if(fromname)$\setkomavar{fromname}{$fromname$}$endif$
$if(fromphone)$\setkomavar{fromphone}{$fromphone$}\KOMAoptions{fromphone=true}$endif$
$if(fromurl)$\setkomavar{fromurl}{$fromurl$}\KOMAoptions{fromurl=true}$endif$
$if(fromzipcode)$\setkomavar{fromzipcode}{$fromzipcode$}$endif$
$if(invoice)$\setkomavar{invoice}{$invoice$}$endif$
$if(location)$\setkomavar{location}{$location$}$endif$
$if(myref)$\setkomavar{myref}{$myref$}$endif$
$if(nextfoot)$\setkomavar{nextfoot}{$nextfoot$}$endif$
$if(nexthead)$\setkomavar{nexthead}{$nexthead$}$endif$
$if(phoneseparator)$\setkomavar{phoneseparator}{$phoneseparator$}$endif$
$if(place)$\setkomavar{place}{$place$}$endif$
$if(placeseparator)$\setkomavar{placeseparator}{$placeseparator$}$endif$
$if(PPdatamatrix)$\setkomavar{PPdatamatrix}{$PPdatamatrix$}$endif$
$if(PPcode)$\setkomavar{PPcode}{$PPcode$}$endif$
$if(signature)$\setkomavar{signature}{$signature$}\renewcommand*{\raggedsignature}{\raggedright}$endif$
$if(specialmail)$\setkomavar{specialmail}{$specialmail$}$endif$
$if(subject)$\setkomavar{subject}{$subject$}$endif$
$if(subjectseparator)$\setkomavar{placeseparator}{$placeseparator$}$endif$
$if(title)$\setkomavar{title}{$title$}$endif$
$if(toaddress)$\setkomavar{toaddress}{$toaddress$}\KOMAoptions{toaddress=true}$endif$
$if(toname)$\setkomavar{toname}{$toname$}\KOMAoptions{toname=true}$endif$
$if(yourmail)$\setkomavar{yourmail}{$yourmail$}$endif$
$if(yourref)$\setkomavar{yourref}{$yourref$}$endif$
$if(zipcodeseparator)$\setkomavar{zipcodeseparator}{$zipcodeseparator$}$endif$
$if(enclseparator)$\setkomavar{enclseparator}{$enclseparator$}$endif$
$if(fromalign)$\KOMAoptions{fromalign=$fromalign$}$endif$
$if(customername)$\setkomavar*{customer}{$customername$}$endif$
% $if(datename)$\setkomavar*{date}{$datename$}$endif$
$if(invoicename)$\setkomavar*{invoice}{$invoicename$}$endif$
$if(myrefname)$\setkomavar*{myref}{$myrefname$}$endif$
$if(yourmailname)$\setkomavar*{yourmail}{$yourmailname$}$endif$
$if(yourrefname)$\setkomavar*{yourref}{$yourrefname$}$endif$
$if(opening)$\setkomavar{opening}{$opening$}$endif$
$if(closing)$\setkomavar{closing}{$closing$}$endif$
$if(enclseparator)$\setkomavar*{enclseparator}{$enclseparator$}$endif$
% END OVERRIDES
\begin{document}
$if(has-frontmatter)$
\frontmatter
$endif$
$if(title)$
$if(beamer)$
\frame{\titlepage}
$else$
\maketitle
$endif$
$if(abstract)$
\begin{abstract}
$abstract$
\end{abstract}
$endif$
$endif$
$for(include-before)$
$include-before$
$endfor$
$if(toc)$
$if(toc-title)$
\renewcommand*\contentsname{$toc-title$}
$endif$
$if(beamer)$
\begin{frame}[allowframebreaks]
$if(toc-title)$
\frametitle{$toc-title$}
$endif$
\tableofcontents[hideallsubsections]
\end{frame}
$else$
{
$if(colorlinks)$
\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
$endif$
\setcounter{tocdepth}{$toc-depth$}
\tableofcontents
}
$endif$
$endif$
$if(lof)$
\listoffigures
$endif$
$if(lot)$
\listoftables
$endif$
$if(linestretch)$
\setstretch{$linestretch$}
$endif$
$if(has-frontmatter)$
\mainmatter
$endif$
% OVERRIDES
\begin{letter}{%
$sendto$
}
\opening{\usekomavar{opening}}
% END OVERRIDES
$body$
% OVERRIDES
\closing{\usekomavar{closing}}
$if(ps)$\ps{$ps$}$endif$
$if(encl)$\encl{$encl$}$endif$
% END OVERRIDES
$if(has-frontmatter)$
\backmatter
$endif$
$if(natbib)$
$if(bibliography)$
$if(biblio-title)$
$if(has-chapters)$
\renewcommand\bibname{$biblio-title$}
$else$
\renewcommand\refname{$biblio-title$}
$endif$
$endif$
$if(beamer)$
\begin{frame}[allowframebreaks]{$biblio-title$}
\bibliographytrue
$endif$
\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
$if(beamer)$
\end{frame}
$endif$
$endif$
$endif$
$if(biblatex)$
$if(beamer)$
\begin{frame}[allowframebreaks]{$biblio-title$}
\bibliographytrue
\printbibliography[heading=none]
\end{frame}
$else$
\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
$endif$
$endif$
$for(include-after)$
$include-after$
$endfor$
% OVERRIDES
$if(cc)$
\cc{$cc$}
$endif$
\end{letter}
% END OVERRIDES
\end{document}