hasanbasbunar commited on
Commit
c13005e
·
0 Parent(s):

Initial commit

Browse files
.gitignore ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # LaTeX build artifacts
2
+ *.aux
3
+ *.fdb_latexmk
4
+ *.fls
5
+ *.log
6
+ *.out
7
+ *.toc
8
+ *.synctex.gz
9
+
10
+ # Local builds
11
+ build/
12
+
13
+ # Python
14
+ .venv/
15
+ __pycache__/
16
+ *.pyc
17
+ # Python-generated files
18
+ __pycache__/
19
+ *.py[oc]
20
+ build/
21
+ dist/
22
+ wheels/
23
+ *.egg-info
24
+
25
+ # Virtual environments
26
+ .venv
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.13
Dockerfile ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM debian:stable-slim
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+
5
+ RUN apt-get update -y && apt-get install -y --no-install-recommends \
6
+ ca-certificates curl git make \
7
+ python3 python3-venv python3-pip \
8
+ texlive-base texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended \
9
+ fonts-lmodern \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ WORKDIR /app
13
+
14
+ # Installer uv
15
+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
16
+ ln -s ~/.cargo/bin/uv /usr/local/bin/uv
17
+
18
+ COPY pyproject.toml ./
19
+ RUN uv sync --frozen
20
+
21
+ COPY . .
22
+
23
+ CMD ["uv", "run", "python", "generate_resume.py", "--template", "classic.tex.j2", "--input-json", "example_inputs/sample.json", "--out-dir", "build"]
24
+
25
+
README.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ cd "/Users/hasanbasbunar/resume-mcp" && uv run python generate_resume.py --template template.tex.j2 --input-json example_inputs/senior_ai_mistral.json --out-tex output.tex --out-pdf output.pdf | cat && test -f output.pdf && open output.pdf
2
+
3
+ uv run python generate_resume.py --template template.tex.j2 --input-json example_inputs/senior_ai_mistral.json --out-dir build
4
+ # ou avec un nom custom
5
+ uv run python generate_resume.py --template template.tex.j2 --input-json example_inputs/senior_ai_mistral.json --out-dir build --basename mistral_senior_fr
6
+
example_inputs/sample.json ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "meta": {
3
+ "pdf_title": "Mon CV",
4
+ "pdf_author": "John Doe",
5
+ "last_updated_text": "Septembre 2025"
6
+ },
7
+ "header": {
8
+ "name": "John Doe",
9
+ "location": "Paris, FR",
10
+ "email": "john@example.com",
11
+ "phone": "+33 6 12 34 56 78",
12
+ "website_url": "https://example.com",
13
+ "website_label": "example.com",
14
+ "linkedin_url": "https://linkedin.com/in/johndoe",
15
+ "linkedin_handle": "johndoe",
16
+ "github_url": "https://github.com/johndoe",
17
+ "github_handle": "johndoe"
18
+ },
19
+ "intro_paragraphs": [
20
+ "Texte d'introduction en une ligne."
21
+ ],
22
+ "quick_guide_items": [
23
+ "Point 1",
24
+ "Point 2"
25
+ ],
26
+ "education": [
27
+ {
28
+ "degree": "BS",
29
+ "date_range": "2015 - 2019",
30
+ "institution": "Université X",
31
+ "field_of_study": "Informatique",
32
+ "highlights": [
33
+ "Mention Bien",
34
+ "Cours: Algo, Réseaux"
35
+ ]
36
+ }
37
+ ],
38
+ "experience": [
39
+ {
40
+ "company": "Entreprise A",
41
+ "role": "Software Engineer",
42
+ "location": "Paris",
43
+ "date_range": "2020 - Présent",
44
+ "highlights": [
45
+ "Implémenté X",
46
+ "Réduit Y"
47
+ ]
48
+ }
49
+ ],
50
+ "publications": [
51
+ {
52
+ "date": "Jan 2024",
53
+ "title": "Titre de la publication",
54
+ "authors": ["Auteur 1", "Auteur 2"],
55
+ "doi_url": "https://doi.org/10.1234/abcd",
56
+ "doi_label": "10.1234/abcd"
57
+ }
58
+ ],
59
+ "projects": [
60
+ {
61
+ "title": "Projet 1",
62
+ "repo_url": "https://github.com/name/repo",
63
+ "repo_label": "github.com/name/repo",
64
+ "highlights": ["Feature A", "Tech: Python, Flask"]
65
+ }
66
+ ],
67
+ "technologies_section": {
68
+ "languages": ["Python", "TypeScript"],
69
+ "technologies": ["FastAPI", "PostgreSQL", "Docker"]
70
+ }
71
+ }
72
+
example_inputs/senior_ai_mistral.json ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "meta": {
3
+ "pdf_title": "CV - Ingénieur IA Sénior",
4
+ "pdf_author": "Alexandre Martin",
5
+ "last_updated_text": "Septembre 2025"
6
+ },
7
+ "header": {
8
+ "name": "Alexandre Martin",
9
+ "location": "Paris, France",
10
+ "email": "alexandre.martin@example.com",
11
+ "phone": "+33 6 12 34 56 78",
12
+ "website_url": "https://alexandre-ml.fr",
13
+ "website_label": "alexandre-ml.fr",
14
+ "linkedin_url": "https://www.linkedin.com/in/alexandre-martin-ai",
15
+ "linkedin_handle": "alexandre-martin-ai",
16
+ "github_url": "https://github.com/alexandre-ml",
17
+ "github_handle": "alexandre-ml"
18
+ },
19
+ "intro_paragraphs": [
20
+ "Ingénieur IA sénior avec dix ans d'expérience en apprentissage profond, modèles de langage et plateformes MLOps. Passionné par les LLM compacts et efficaces, l'optimisation serveur et l'inférence à faible latence.",
21
+ "Motivé pour rejoindre Mistral et contribuer à la recherche appliquée, à l'optimisation et au déploiement massif de modèles en production, avec un souci permanent de qualité et de frugalité."
22
+ ],
23
+ "quick_guide_items": [
24
+ "Expertise LLM, optimisation et quantification",
25
+ "Conception d'API d'inférence et observabilité",
26
+ "MLOps de bout en bout, reproductibilité et fiabilité"
27
+ ],
28
+ "education": [
29
+ {
30
+ "degree": "Master of Science",
31
+ "date_range": "2013 - 2015",
32
+ "institution": "Ecole Polytechnique",
33
+ "field_of_study": "Mathématiques Appliquées et Informatique",
34
+ "highlights": [
35
+ "Major Projet: optimisation convexe pour réseaux de neurones",
36
+ "Moyenne: 17 sur 20"
37
+ ]
38
+ },
39
+ {
40
+ "degree": "Licence",
41
+ "date_range": "2010 - 2013",
42
+ "institution": "Université Paris Saclay",
43
+ "field_of_study": "Informatique",
44
+ "highlights": [
45
+ "Classement top 5 pour le département",
46
+ "Projet open source en vision par ordinateur"
47
+ ]
48
+ }
49
+ ],
50
+ "experience": [
51
+ {
52
+ "company": "ScaleAI Labs",
53
+ "role": "Senior Staff Machine Learning Engineer",
54
+ "location": "Paris",
55
+ "date_range": "2022 - Présent",
56
+ "highlights": [
57
+ "Conçu une pile d'inférence LLM haute performance avec mise en lots dynamique, gestion des tokens et ordonnanceur mémoire pour réduire la latence p95 de 30 pourcent",
58
+ "Mené la quantification post entraînement et la distillation de modèles 7B vers 3B avec une perte de qualité négligeable sur benchmarks internes",
59
+ "Mis en place une observabilité complète: traces, métriques et journaux corrélés pour la détection d'incidents d'inférence",
60
+ "Piloté l'intégration de modèles Mistral pour des cas d'usage de génération et d'outillage développeur"
61
+ ]
62
+ },
63
+ {
64
+ "company": "DeepVision",
65
+ "role": "Lead Machine Learning Engineer",
66
+ "location": "Lyon",
67
+ "date_range": "2018 - 2022",
68
+ "highlights": [
69
+ "Déployé des services de classification et détection en temps réel avec accélération GPU",
70
+ "Industrialisation MLOps: registres de modèles, pipelines d'entraînement et validations",
71
+ "Réduction du coût par prédiction grâce au partage de GPU et à l'optimisation du lot"
72
+ ]
73
+ },
74
+ {
75
+ "company": "DataCraft",
76
+ "role": "Machine Learning Engineer",
77
+ "location": "Paris",
78
+ "date_range": "2015 - 2018",
79
+ "highlights": [
80
+ "Mise en place d'un pipeline de traitement de texte pour recherche sémantique",
81
+ "Amélioration continue des modèles avec validation croisée et suivi expérimental"
82
+ ]
83
+ }
84
+ ],
85
+ "publications": [
86
+ {
87
+ "date": "Juin 2024",
88
+ "title": "Compression pratique de modèles de langage pour inférence frugale",
89
+ "authors": ["Alexandre Martin", "Claire Dupont", "Hugo Leroy"],
90
+ "doi_url": "https://doi.org/10.1234/comp-llm-2024",
91
+ "doi_label": "10.1234/comp-llm-2024"
92
+ },
93
+ {
94
+ "date": "Mars 2022",
95
+ "title": "Optimisation de l'ordonnancement pour services d'inférence",
96
+ "authors": ["Alexandre Martin", "Nina Robert"],
97
+ "doi_url": "https://doi.org/10.2345/sched-infer-2022",
98
+ "doi_label": "10.2345/sched-infer-2022"
99
+ }
100
+ ],
101
+ "projects": [
102
+ {
103
+ "title": "Serveur d'inférence LLM minimaliste",
104
+ "repo_url": "https://github.com/alexandre-ml/llm-infer-min",
105
+ "repo_label": "github.com/alexandre-ml/llm-infer-min",
106
+ "highlights": [
107
+ "Planification des requêtes et contrôle du débit",
108
+ "Support pour modèles quantifiés et streaming de tokens"
109
+ ]
110
+ },
111
+ {
112
+ "title": "Kit de distillation pour modèles français",
113
+ "repo_url": "https://github.com/alexandre-ml/distill-fr",
114
+ "repo_label": "github.com/alexandre-ml/distill-fr",
115
+ "highlights": [
116
+ "Scripts de distillation assistée pour domaines spécialisés",
117
+ "Evaluation automatique avec corpus français"
118
+ ]
119
+ },
120
+ {
121
+ "title": "Observabilité pour pipelines ML",
122
+ "repo_url": "https://github.com/alexandre-ml/ml-observabilite",
123
+ "repo_label": "github.com/alexandre-ml/ml-observabilite",
124
+ "highlights": [
125
+ "Tableau de bord métriques et alertes",
126
+ "Traces distribuées pour étapes d'entraînement et d'inférence"
127
+ ]
128
+ }
129
+ ],
130
+ "technologies_section": {
131
+ "languages": [
132
+ "Python",
133
+ "C plus plus",
134
+ "Rust",
135
+ "Go",
136
+ "Scala",
137
+ "Bash"
138
+ ],
139
+ "technologies": [
140
+ "PyTorch",
141
+ "TensorFlow",
142
+ "JAX",
143
+ "Transformers",
144
+ "Ray",
145
+ "MLflow",
146
+ "Docker",
147
+ "Kubernetes",
148
+ "Airflow",
149
+ "Prometheus",
150
+ "Grafana",
151
+ "NGINX",
152
+ "PostgreSQL",
153
+ "Redis",
154
+ "S3",
155
+ "GCP",
156
+ "Azure"
157
+ ]
158
+ }
159
+ }
160
+
161
+
generate_resume.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import subprocess
5
+ import platform
6
+ import sys
7
+ from pathlib import Path
8
+ from typing import Any, Dict
9
+ import uuid
10
+
11
+ from jinja2 import Environment, FileSystemLoader
12
+ from pydantic import ValidationError
13
+
14
+ from pydantic_model import Resume
15
+
16
+ PROJECT_ROOT = Path(__file__).parent
17
+ TEMPLATES_DIR = PROJECT_ROOT / "templates"
18
+ TEMPLATE_NAME = "classic.tex.j2"
19
+ OUTPUT_DIR = PROJECT_ROOT / "build"
20
+
21
+
22
+ def render_tex(resume_data: Dict[str, Any], output_tex_path: Path, template_name: str = TEMPLATE_NAME) -> None:
23
+ try:
24
+ resume = Resume.model_validate(resume_data)
25
+ except ValidationError as e:
26
+ print("Erreur de validation Pydantic:")
27
+ print(e)
28
+ sys.exit(1)
29
+
30
+ env = Environment(
31
+ loader=FileSystemLoader(str(TEMPLATES_DIR)),
32
+ autoescape=False,
33
+ trim_blocks=True,
34
+ lstrip_blocks=True,
35
+ )
36
+ # Configure custom delimiters to avoid clashes with LaTeX
37
+ env.block_start_string = "<<%"
38
+ env.block_end_string = "%>>"
39
+ env.variable_start_string = "<<"
40
+ env.variable_end_string = ">>"
41
+ env.comment_start_string = "<#!"
42
+ env.comment_end_string = "!#>"
43
+ template = env.get_template(template_name)
44
+ rendered = template.render(resume=resume.model_dump())
45
+
46
+ output_tex_path.parent.mkdir(parents=True, exist_ok=True)
47
+ output_tex_path.write_text(rendered, encoding="utf-8")
48
+
49
+
50
+ def run_tectonic(tex_path: Path, outdir: Path) -> None:
51
+ cmd = [
52
+ "tectonic",
53
+ "--outdir",
54
+ str(outdir),
55
+ str(tex_path),
56
+ ]
57
+ subprocess.run(cmd, check=True)
58
+
59
+
60
+ def run_latexmk(tex_path: Path, outdir: Path) -> None:
61
+ # latexmk -pdf -synctex=1 -interaction=nonstopmode -output-directory=outdir tex
62
+ cmd = [
63
+ "latexmk",
64
+ "-pdf",
65
+ "-synctex=1",
66
+ "-interaction=nonstopmode",
67
+ f"-output-directory={outdir}",
68
+ str(tex_path),
69
+ ]
70
+ subprocess.run(cmd, check=True)
71
+
72
+
73
+ def compile_pdf(output_tex_path: Path, output_pdf_path: Path, engine_preference: str = "tectonic") -> None:
74
+ outdir = output_pdf_path.parent
75
+ outdir.mkdir(parents=True, exist_ok=True)
76
+
77
+ if engine_preference == "latexmk":
78
+ try:
79
+ run_latexmk(output_tex_path, outdir)
80
+ except (FileNotFoundError, subprocess.CalledProcessError):
81
+ run_tectonic(output_tex_path, outdir)
82
+ else:
83
+ # default: try tectonic first, then fallback
84
+ try:
85
+ run_tectonic(output_tex_path, outdir)
86
+ except (FileNotFoundError, subprocess.CalledProcessError):
87
+ run_latexmk(output_tex_path, outdir)
88
+
89
+ if not output_pdf_path.exists():
90
+ raise RuntimeError(f"PDF introuvable après compilation: {output_pdf_path}")
91
+
92
+
93
+ def main() -> None:
94
+ import argparse
95
+
96
+ parser = argparse.ArgumentParser(description="Générer le CV PDF depuis des données JSON")
97
+ parser.add_argument(
98
+ "--input-json",
99
+ type=Path,
100
+ required=True,
101
+ help="Chemin du fichier JSON d'entrée (conforme au modèle Resume)",
102
+ )
103
+ parser.add_argument(
104
+ "--template",
105
+ type=str,
106
+ default=TEMPLATE_NAME,
107
+ help="Nom du fichier template (dans le dossier templates)",
108
+ )
109
+ parser.add_argument(
110
+ "--out-dir",
111
+ type=Path,
112
+ default=OUTPUT_DIR,
113
+ help="Dossier de sortie pour les fichiers générés (.tex, .pdf, artefacts LaTeX)",
114
+ )
115
+ parser.add_argument(
116
+ "--basename",
117
+ type=str,
118
+ default=None,
119
+ help="Nom de base des fichiers générés (défaut: UUID aléatoire)",
120
+ )
121
+ parser.add_argument(
122
+ "--engine",
123
+ type=str,
124
+ choices=["tectonic", "latexmk"],
125
+ default=None,
126
+ help="Moteur de compilation LaTeX à privilégier (par défaut: latexmk sous Linux, sinon tectonic)",
127
+ )
128
+ parser.add_argument(
129
+ "--out-tex",
130
+ type=Path,
131
+ default=None,
132
+ help="Chemin du fichier .tex rendu (défaut: build/output.tex)",
133
+ )
134
+ parser.add_argument(
135
+ "--out-pdf",
136
+ type=Path,
137
+ default=None,
138
+ help="Chemin du PDF de sortie (défaut: build/output.pdf)",
139
+ )
140
+ args = parser.parse_args()
141
+
142
+ data = json.loads(args.input_json.read_text(encoding="utf-8"))
143
+
144
+ # Résoudre le nom de base (UUID si non fourni)
145
+ base_name = (args.basename or uuid.uuid4().hex).strip()
146
+ if not base_name:
147
+ base_name = uuid.uuid4().hex
148
+
149
+ # Résoudre les chemins de sortie par défaut si non fournis
150
+ out_tex = args.out_tex or (args.out_dir / f"{base_name}.tex")
151
+ out_pdf = args.out_pdf or (args.out_dir / f"{base_name}.pdf")
152
+
153
+ render_tex(data, out_tex, template_name=args.template)
154
+
155
+ # Choix du moteur par défaut selon l'OS
156
+ preferred_engine = args.engine
157
+ if preferred_engine is None:
158
+ preferred_engine = "latexmk" if platform.system() == "Linux" else "tectonic"
159
+
160
+ compile_pdf(out_tex, out_pdf, engine_preference=preferred_engine)
161
+ print(f"PDF généré: {out_pdf}")
162
+
163
+ if __name__ == "__main__":
164
+ main()
165
+
166
+
pydantic_model.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional
2
+ from pydantic import BaseModel, EmailStr, HttpUrl
3
+
4
+
5
+ class DocumentMeta(BaseModel):
6
+ pdf_title: str
7
+ pdf_author: str
8
+ last_updated_text: Optional[str] = None # ex: "September 2024"
9
+
10
+
11
+ class Header(BaseModel):
12
+ name: str
13
+ location: str
14
+ email: EmailStr
15
+ phone: str
16
+ website_url: Optional[HttpUrl] = None
17
+ website_label: Optional[str] = None # ex: "yourwebsite.com"
18
+ linkedin_url: Optional[HttpUrl] = None
19
+ linkedin_handle: Optional[str] = None # ex: "yourusername"
20
+ github_url: Optional[HttpUrl] = None
21
+ github_handle: Optional[str] = None # ex: "yourusername"
22
+
23
+
24
+ class EducationEntry(BaseModel):
25
+ degree: str # ex: "BS"
26
+ date_range: str # ex: "Sept 2000 – May 2005"
27
+ institution: str # ex: "University of Pennsylvania"
28
+ field_of_study: Optional[str] = None # ex: "Computer Science"
29
+ highlights: List[str] = [] # puces
30
+
31
+
32
+ class ExperienceEntry(BaseModel):
33
+ company: str # ex: "Apple"
34
+ role: str # ex: "Software Engineer"
35
+ location: str # ex: "Cupertino, CA"
36
+ date_range: str # ex: "June 2005 – Aug 2007"
37
+ highlights: List[str] = []
38
+
39
+
40
+ class PublicationEntry(BaseModel):
41
+ date: str # ex: "Jan 2004"
42
+ title: str # ex: "3D Finite Element Analysis of ..."
43
+ authors: List[str] # ex: ["Frodo Baggins", "John Doe", "Samwise Gamgee"]
44
+ doi_url: Optional[HttpUrl] = None # ex: "https://doi.org/10.1109/..."
45
+ doi_label: Optional[str] = None # ex: "10.1109/TASC.2023.3340648"
46
+
47
+
48
+ class ProjectEntry(BaseModel):
49
+ title: str # ex: "Multi-User Drawing Tool"
50
+ repo_url: Optional[HttpUrl] = None # ex: "https://github.com/name/repo"
51
+ repo_label: Optional[str] = None # ex: "github.com/name/repo"
52
+ highlights: List[str] = []
53
+
54
+
55
+ class Technologies(BaseModel):
56
+ languages: List[str] = [] # ex: ["C++", "C", "Java", ...]
57
+ technologies: List[str] = [] # ex: [".NET", "SQL Server", "XCode", ...]
58
+
59
+
60
+ class Resume(BaseModel):
61
+ meta: DocumentMeta
62
+ header: Header
63
+
64
+ # Sections correspondant au contenu du template fourni
65
+ intro_paragraphs: List[str] = [] # section "Welcome to RenderCV!" (paragraphes)
66
+ quick_guide_items: List[str] = [] # puces "Quick Guide"
67
+
68
+ education: List[EducationEntry] = []
69
+ experience: List[ExperienceEntry] = []
70
+ publications: List[PublicationEntry] = []
71
+ projects: List[ProjectEntry] = []
72
+ technologies_section: Technologies
pyproject.toml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "resume-mcp"
3
+ version = "0.1.0"
4
+ description = "Génération de CV PDF via LaTeX + Jinja2 + Pydantic"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "jinja2>=3.1",
9
+ "pydantic[email]>=2.7",
10
+ ]
11
+
12
+ [tool.uv]
13
+ dev-dependencies = []
templates/classic.tex.j2 ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ \documentclass[10pt, letterpaper]{article}
2
+
3
+ % Packages:
4
+ \usepackage[
5
+ ignoreheadfoot, % set margins without considering header and footer
6
+ top=2 cm, % seperation between body and page edge from the top
7
+ bottom=2 cm, % seperation between body and page edge from the bottom
8
+ left=2 cm, % seperation between body and page edge from the left
9
+ right=2 cm, % seperation between body and page edge from the right
10
+ footskip=1.0 cm, % seperation between body and footer
11
+ % showframe % for debugging
12
+ ]{geometry} % for adjusting page geometry
13
+ \usepackage[explicit]{titlesec} % for customizing section titles
14
+ \usepackage{tabularx} % for making tables with fixed width columns
15
+ \usepackage{array} % tabularx requires this
16
+ \usepackage[dvipsnames]{xcolor} % for coloring text
17
+ \definecolor{primaryColor}{RGB}{0, 79, 144} % define primary color
18
+ \usepackage{enumitem} % for customizing lists
19
+ \usepackage{fontawesome5} % for using icons
20
+ \usepackage{amsmath} % for math
21
+ \usepackage[
22
+ pdftitle={John Doe's CV},
23
+ pdfauthor={John Doe},
24
+ pdfcreator={LaTeX with RenderCV},
25
+ colorlinks=true,
26
+ urlcolor=primaryColor
27
+ ]{hyperref} % for links, metadata and bookmarks
28
+ \usepackage[pscoord]{eso-pic} % for floating text on the page
29
+ \usepackage{calc} % for calculating lengths
30
+ \usepackage{bookmark} % for bookmarks
31
+ \usepackage{lastpage} % for getting the total number of pages
32
+ \usepackage{changepage} % for one column entries (adjustwidth environment)
33
+ \usepackage{paracol} % for two and three column entries
34
+ \usepackage{ifthen} % for conditional statements
35
+ \usepackage{needspace} % for avoiding page brake right after the section title
36
+ \usepackage{iftex} % check if engine is pdflatex, xetex or luatex
37
+
38
+ % Ensure that generate pdf is machine readable/ATS parsable:
39
+ \ifPDFTeX
40
+ \input{glyphtounicode}
41
+ \pdfgentounicode=1
42
+ \usepackage[T1]{fontenc}
43
+ \usepackage[utf8]{inputenc}
44
+ \usepackage{lmodern}
45
+ \fi
46
+
47
+ \usepackage[default, type1]{sourcesanspro}
48
+
49
+ % Some settings:
50
+ \AtBeginEnvironment{adjustwidth}{\partopsep0pt} % remove space before adjustwidth environment
51
+ \pagestyle{empty} % no header or footer
52
+ \setcounter{secnumdepth}{0} % no section numbering
53
+ \setlength{\parindent}{0pt} % no indentation
54
+ \setlength{\topskip}{0pt} % no top skip
55
+ \setlength{\columnsep}{0.15cm} % set column seperation
56
+ \makeatletter
57
+ \let\ps@customFooterStyle\ps@plain % Copy the plain style to customFooterStyle
58
+ \patchcmd{\ps@customFooterStyle}{\thepage}{
59
+ \color{gray}\textit{\small << resume.header.name >> - Page \thepage{} of \pageref*{LastPage}}
60
+ }{}{} % replace number by desired string
61
+ \makeatother
62
+ \pagestyle{customFooterStyle}
63
+
64
+ \titleformat{\section}{
65
+ % avoid page braking right after the section title
66
+ \needspace{4\baselineskip}
67
+ % make the font size of the section title large and color it with the primary color
68
+ \Large\color{primaryColor}
69
+ }{
70
+ }{
71
+ }{
72
+ % print bold title, give 0.15 cm space and draw a line of 0.8 pt thickness
73
+ % from the end of the title to the end of the body
74
+ \textbf{#1}\hspace{0.15cm}\titlerule[0.8pt]\hspace{-0.1cm}
75
+ }[] % section title formatting
76
+
77
+ \titlespacing{\section}{
78
+ % left space:
79
+ -1pt
80
+ }{
81
+ % top space:
82
+ 0.3 cm
83
+ }{
84
+ % bottom space:
85
+ 0.2 cm
86
+ } % section title spacing
87
+
88
+ % \renewcommand\labelitemi{$\vcenter{\hbox{\small$\bullet$}}$} % custom bullet points
89
+ \newenvironment{highlights}{
90
+ \begin{itemize}[
91
+ topsep=0.10 cm,
92
+ parsep=0.10 cm,
93
+ partopsep=0pt,
94
+ itemsep=0pt,
95
+ leftmargin=0.4 cm + 10pt
96
+ ]
97
+ }{
98
+ \end{itemize}
99
+ } % new environment for highlights
100
+
101
+ \newenvironment{highlightsforbulletentries}{
102
+ \begin{itemize}[
103
+ topsep=0.10 cm,
104
+ parsep=0.10 cm,
105
+ partopsep=0pt,
106
+ itemsep=0pt,
107
+ leftmargin=10pt
108
+ ]
109
+ }{
110
+ \end{itemize}
111
+ } % new environment for highlights for bullet entries
112
+
113
+
114
+ \newenvironment{onecolentry}{
115
+ \begin{adjustwidth}{
116
+ 0.2 cm + 0.00001 cm
117
+ }{
118
+ 0.2 cm + 0.00001 cm
119
+ }
120
+ }{
121
+ \end{adjustwidth}
122
+ } % new environment for one column entries
123
+
124
+ \newenvironment{twocolentry}[2][]{
125
+ \onecolentry
126
+ \def\secondColumn{#2}
127
+ \setcolumnwidth{\fill, 4.5 cm}
128
+ \begin{paracol}{2}
129
+ }{
130
+ \switchcolumn \raggedleft \secondColumn
131
+ \end{paracol}
132
+ \endonecolentry
133
+ } % new environment for two column entries
134
+
135
+ \newenvironment{threecolentry}[3][]{
136
+ \onecolentry
137
+ \def\thirdColumn{#3}
138
+ \setcolumnwidth{1 cm, \fill, 4.5 cm}
139
+ \begin{paracol}{3}
140
+ {\raggedright #2} \switchcolumn
141
+ }{
142
+ \switchcolumn \raggedleft \thirdColumn
143
+ \end{paracol}
144
+ \endonecolentry
145
+ } % new environment for three column entries
146
+
147
+ \newenvironment{header}{
148
+ \setlength{\topsep}{0pt}\par\kern\topsep\centering\color{primaryColor}\linespread{1.5}
149
+ }{
150
+ \par\kern\topsep
151
+ } % new environment for the header
152
+
153
+ \newcommand{\placelastupdatedtext}{ % \placetextbox{<horizontal pos>}{<vertical pos>}{<stuff>}
154
+ \AddToShipoutPictureFG*{ % Add <stuff> to current page foreground
155
+ \put(
156
+ \LenToUnit{\paperwidth-2 cm-0.2 cm+0.05cm},
157
+ \LenToUnit{\paperheight-1.0 cm}
158
+ ){\vtop{{\null}\makebox[0pt][c]{
159
+ \small\color{gray}\textit{Last updated in << resume.meta.last_updated_text | default('') >>}\hspace{\widthof{Last updated in << resume.meta.last_updated_text | default('') >> }}
160
+ }}}%
161
+ }%
162
+ }%
163
+
164
+ % save the original href command in a new command:
165
+ \let\hrefWithoutArrow\href
166
+
167
+ % new command for external links:
168
+ \renewcommand{\href}[2]{\hrefWithoutArrow{#1}{\ifthenelse{\equal{#2}{}}{ }{#2 }\raisebox{.15ex}{\footnotesize \faExternalLink*}}}
169
+
170
+
171
+ \begin{document}
172
+ \newcommand{\AND}{\unskip
173
+ \cleaders\copy\ANDbox\hskip\wd\ANDbox
174
+ \ignorespaces
175
+ }
176
+ \newsavebox\ANDbox
177
+ \sbox\ANDbox{}
178
+
179
+ \hypersetup{
180
+ pdftitle=<< '{' >><< resume.meta.pdf_title >><< '}' >>,
181
+ pdfauthor=<< '{' >><< resume.meta.pdf_author >><< '}' >>
182
+ }
183
+ \placelastupdatedtext
184
+ \begin{header}
185
+ \fontsize{30 pt}{30 pt}
186
+ \textbf{ << resume.header.name >> }
187
+
188
+ \vspace{0.3 cm}
189
+
190
+ \normalsize
191
+ \mbox{{\footnotesize\faMapMarker*}\hspace*{0.13cm}<< resume.header.location >>}%
192
+ \kern 0.25 cm%
193
+ \AND%
194
+ \kern 0.25 cm%
195
+ \mbox{\hrefWithoutArrow{mailto:<< resume.header.email >>}{{\footnotesize\faEnvelope[regular]}\hspace*{0.13cm}<< resume.header.email >>}}%
196
+ \kern 0.25 cm%
197
+ \AND%
198
+ \kern 0.25 cm%
199
+ \mbox{\hrefWithoutArrow{tel:<< resume.header.phone | replace(' ', '') | replace('-', '') >>}{{\footnotesize\faPhone*}\hspace*{0.13cm}<< resume.header.phone >>}}%
200
+ <<% if resume.header.website_url %>>
201
+ \kern 0.25 cm%
202
+ \AND%
203
+ \kern 0.25 cm%
204
+ \mbox{\hrefWithoutArrow{ << resume.header.website_url >> }{{\footnotesize\faLink}\hspace*{0.13cm}<< resume.header.website_label or resume.header.website_url >>}}%
205
+ <<% endif %>>
206
+ <<% if resume.header.linkedin_url %>>
207
+ \kern 0.25 cm%
208
+ \AND%
209
+ \kern 0.25 cm%
210
+ \mbox{\hrefWithoutArrow{ << resume.header.linkedin_url >> }{{\footnotesize\faLinkedinIn}\hspace*{0.13cm}<< resume.header.linkedin_handle or resume.header.linkedin_url >>}}%
211
+ <<% endif %>>
212
+ <<% if resume.header.github_url %>>
213
+ \kern 0.25 cm%
214
+ \AND%
215
+ \kern 0.25 cm%
216
+ \mbox{\hrefWithoutArrow{ << resume.header.github_url >> }{{\footnotesize\faGithub}\hspace*{0.13cm}<< resume.header.github_handle or resume.header.github_url >>}}%
217
+ <<% endif %>>
218
+ \end{header}
219
+
220
+ \vspace{0.3 cm - 0.3 cm}
221
+
222
+
223
+ \section{About}
224
+
225
+ <<% for p in resume.intro_paragraphs %>>
226
+ \begin{onecolentry}
227
+ << p >>
228
+ \end{onecolentry}
229
+ <<% if not loop.last %>>
230
+ \vspace{0.2 cm}
231
+ <<% endif %>>
232
+ <<% endfor %>>
233
+
234
+
235
+
236
+
237
+ \section{Highlights}
238
+
239
+ \begin{onecolentry}
240
+ \begin{highlightsforbulletentries}
241
+ <<% for item in resume.quick_guide_items %>>
242
+ \item << item >>
243
+ <<% endfor %>>
244
+ \end{highlightsforbulletentries}
245
+ \end{onecolentry}
246
+
247
+ \section{Education}
248
+
249
+
250
+ <<% for edu in resume.education %>>
251
+ \begin{threecolentry}{\textbf{ << edu.degree >> }}{
252
+ << edu.date_range >>
253
+ }
254
+ \textbf{ << edu.institution >> }<<% if edu.field_of_study %>>, << edu.field_of_study >><<% endif %>>
255
+ <<% if edu.highlights %>>
256
+ \begin{highlights}
257
+ <<% for h in edu.highlights %>>
258
+ \item << h >>
259
+ <<% endfor %>>
260
+ \end{highlights}
261
+ <<% endif %>>
262
+ \end{threecolentry}
263
+ <<% endfor %>>
264
+
265
+
266
+ \section{Experience}
267
+
268
+
269
+ <<% for exp in resume.experience %>>
270
+ \begin{twocolentry}{
271
+ << exp.location >>
272
+
273
+ << exp.date_range >>
274
+ }
275
+ \textbf{ << exp.company >> }, << exp.role >>
276
+ <<% if exp.highlights %>>
277
+ \begin{highlights}
278
+ <<% for h in exp.highlights %>>
279
+ \item << h >>
280
+ <<% endfor %>>
281
+ \end{highlights}
282
+ <<% endif %>>
283
+ \end{twocolentry}
284
+ <<% if not loop.last %>>
285
+ \vspace{0.2 cm}
286
+ <<% endif %>>
287
+ <<% endfor %>>
288
+
289
+
290
+
291
+ \section{Publications}
292
+
293
+
294
+ <<% for pub in resume.publications %>>
295
+ \begin{samepage}
296
+ \begin{twocolentry}{
297
+ << pub.date >>
298
+ }
299
+ \textbf{ << pub.title >> }
300
+
301
+ \vspace{0.10 cm}
302
+
303
+ << pub.authors | join(', ') >>
304
+ \vspace{0.10 cm}
305
+ <<% if pub.doi_url %>>
306
+ \href{ << pub.doi_url >> }{ << pub.doi_label or pub.doi_url >> }
307
+ <<% endif %>>
308
+ \end{twocolentry}
309
+ \end{samepage}
310
+ <<% endfor %>>
311
+
312
+
313
+ \section{Projects}
314
+
315
+
316
+ <<% for pr in resume.projects %>>
317
+ \begin{twocolentry}{
318
+ <<% if pr.repo_url %>>\href{ << pr.repo_url >> }{ << pr.repo_label or pr.repo_url >> }<<% endif %>>
319
+ }
320
+ \textbf{ << pr.title >> }
321
+ <<% if pr.highlights %>>
322
+ \begin{highlights}
323
+ <<% for h in pr.highlights %>>
324
+ \item << h >>
325
+ <<% endfor %>>
326
+ \end{highlights}
327
+ <<% endif %>>
328
+ \end{twocolentry}
329
+ <<% if not loop.last %>>
330
+ \vspace{0.2 cm}
331
+ <<% endif %>>
332
+ <<% endfor %>>
333
+
334
+
335
+ \section{Technologies}
336
+
337
+
338
+ \begin{onecolentry}
339
+ \textbf{Languages:} << resume.technologies_section.languages | join(', ') >>
340
+ \end{onecolentry}
341
+
342
+ \vspace{0.2 cm}
343
+
344
+ \begin{onecolentry}
345
+ \textbf{Technologies:} << resume.technologies_section.technologies | join(', ') >>
346
+ \end{onecolentry}
347
+
348
+
349
+ \end{document}
350
+
351
+
templates/clean.tex.j2 ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ % Clean CV/Resume Template adapted for Jinja2 (Resume schema)
2
+ \documentclass[oneside]{article}
3
+
4
+ \usepackage{wallpaper}
5
+ \usepackage{geometry}
6
+ \usepackage[
7
+ unicode=true,
8
+ bookmarks=true,
9
+ bookmarksnumbered=false,
10
+ bookmarksopen=true,
11
+ bookmarksopenlevel=1,
12
+ breaklinks=false,
13
+ pdfborder={0 0 0},
14
+ backref=false,
15
+ colorlinks=false
16
+ ]{hyperref}
17
+ \usepackage{lastpage}
18
+ \usepackage{hyphenat}
19
+ \usepackage{hyphsubst}
20
+ \usepackage{tabularx}
21
+ \usepackage{moresize}
22
+ \usepackage[document]{ragged2e}
23
+ % \usepackage{parskip}
24
+
25
+ \usepackage[scaled]{helvet}
26
+ \usepackage{fontawesome5}
27
+ \usepackage[defaultfam,tabular,oldstyle]{montserrat}
28
+ \usepackage[T1]{fontenc}
29
+ \renewcommand*\oldstylenums[1]{{\fontfamily{Montserrat-TOsF}\selectfont #1}}
30
+
31
+ \usepackage{titlesec}
32
+ \usepackage{xcolor}
33
+ \usepackage{tikz}
34
+
35
+ \setlength{\parindent}{0pt}
36
+ \titleformat{\section}{\normalfont}{}{0pt}{}
37
+
38
+ \renewcommand{\arraystretch}{1.4}
39
+
40
+ \setlength\fboxrule{0pt}
41
+ \setlength\fboxsep{12pt}
42
+ % \setlength{\parskip}{.5\baselineskip plus 2pt}
43
+ % \renewcommand{\baselinestretch}{1.1}
44
+
45
+ \titlespacing{\section}{0pt}{1.5ex plus .1ex minus .2ex}{1pc}
46
+
47
+ \newcolumntype{Y}{>{\RaggedRight\arraybackslash}X}
48
+
49
+ % PDF Meta Info
50
+ \hypersetup{
51
+ pdftitle=<< '{' >><< resume.meta.pdf_title >><< '}' >>,
52
+ pdfauthor=<< '{' >><< resume.meta.pdf_author >><< '}' >>,
53
+ pdfsubject={CV}
54
+ }
55
+
56
+ % Paper size
57
+ \geometry{
58
+ a4paper,
59
+ left=0pt,
60
+ right=0pt,
61
+ top=0pt,
62
+ bottom=0pt,
63
+ nohead,
64
+ % includefoot,
65
+ nomarginpar
66
+ }
67
+
68
+ % Colors
69
+ \definecolor{sidebg}{cmyk}{1, 0.02, 0, 0.56}
70
+ \definecolor{mainbg}{cmyk}{0, 0, 0.07, 0.04}
71
+ \definecolor{maintext}{cmyk}{1, 0.02, 0, 0.8}
72
+ \definecolor{sidetext}{cmyk}{0, 0, 0.07, 0.04}
73
+
74
+ \pagecolor{mainbg}
75
+
76
+ \begin{document}
77
+ \setlength{\topskip}{0pt}\setlength{\footskip}{0pt}%
78
+ \fcolorbox{red}{sidebg}{%
79
+ \begin{minipage}[t][\textheight-2\fboxsep-2\fboxrule][t]{\dimexpr0.40\textwidth-2\fboxrule-2\fboxsep\relax}
80
+ \color{sidetext}
81
+ % Name
82
+ {\bfseries\scshape\HUGE << resume.header.name >>} \\
83
+ \vspace{.5cm}
84
+ % Contact
85
+ \phantomsection{}
86
+ \addcontentsline{toc}{section}{Contact}
87
+ \section*{\large Contact}
88
+ \begin{tabularx}{\textwidth}{cY}
89
+ \faMapMarker{} & << resume.header.location >> \\
90
+ \faPhone{} & << resume.header.phone >> \\
91
+ \faEnvelope{} & \href{mailto:<< resume.header.email >>}{<< resume.header.email >>} \\
92
+ <<% if resume.header.website_url %>>\faLink{} & \href{ << resume.header.website_url >> }{ << resume.header.website_label or resume.header.website_url >> } \\<<% endif %>>
93
+ \end{tabularx}
94
+ \vspace{.3cm} \\
95
+ \rule{\linewidth}{0.4pt} \\
96
+ % Links
97
+ \phantomsection{}
98
+ \addcontentsline{toc}{section}{Links}
99
+ \section*{\large Links}
100
+ \begin{tabular}{cl}
101
+ <<% if resume.header.github_url %>>\faGithub{} & \href{ << resume.header.github_url >> }{ << resume.header.github_handle or resume.header.github_url >> } \\<<% endif %>>
102
+ <<% if resume.header.linkedin_url %>>\faLinkedin{} & \href{ << resume.header.linkedin_url >> }{ << resume.header.linkedin_handle or resume.header.linkedin_url >> } \\<<% endif %>>
103
+ \end{tabular}
104
+ \vspace{10pt} \\
105
+ \rule{\linewidth}{0.4pt} \\
106
+ % Technologies
107
+ \phantomsection{}
108
+ \addcontentsline{toc}{section}{Technologies}
109
+ \section*{\large Technologies}
110
+ \begin{tabularx}{\textwidth}{cY}
111
+ \faCode{} & \textbf{Languages:} << resume.technologies_section.languages | join(', ') >> \\
112
+ \faCogs{} & \textbf{Technologies:} << resume.technologies_section.technologies | join(', ') >> \\
113
+ \end{tabularx}
114
+ \vspace{1pt} \\
115
+ \rule{\linewidth}{0.4pt}
116
+ \vfill
117
+ {\tiny Last updated in << resume.meta.last_updated_text | default('') >>}
118
+ \end{minipage}
119
+ }
120
+ \hfill
121
+ \fcolorbox{red}{mainbg}{%
122
+ \begin{minipage}[t][\dimexpr\textheight-2\fboxrule-2\fboxsep\relax][t]{\dimexpr0.6\textwidth-2\fboxrule-2\fboxsep\relax}
123
+ \color{maintext}
124
+ % About
125
+ \phantomsection{}
126
+ \addcontentsline{toc}{section}{About}
127
+ \section*{\scshape\Large About \rule{\linewidth}{0.4pt}}
128
+ <<% for p in resume.intro_paragraphs %>><< p >>\\<<% endfor %>>
129
+
130
+ % Highlights
131
+ \phantomsection{}
132
+ \addcontentsline{toc}{section}{Highlights}
133
+ \section*{\scshape\Large Highlights \rule{\linewidth}{0.4pt}}
134
+ \begin{itemize}
135
+ <<% for item in resume.quick_guide_items %>>\item << item >>
136
+ <<% endfor %>>
137
+ \end{itemize}
138
+
139
+ % Work Experience
140
+ \phantomsection{}
141
+ \addcontentsline{toc}{section}{Experience}
142
+ \section*{\scshape\Large Experience \rule{\linewidth}{0.4pt}}
143
+ <<% for exp in resume.experience %>>
144
+ {\large \textbf{ << exp.company >> }} \\
145
+ {\fontseries{medium}\selectfont << exp.role >>} \\
146
+ {\scshape\fontseries{light}\selectfont\footnotesize << exp.location >> \qquad << exp.date_range >>}
147
+ \begin{itemize}
148
+ \setlength{\itemsep}{-3pt}
149
+ <<% for h in exp.highlights %>>\item << h >>
150
+ <<% endfor %>>
151
+ \end{itemize}
152
+ <<% endfor %>>
153
+
154
+ % Education
155
+ \phantomsection{}
156
+ \addcontentsline{toc}{section}{Education}
157
+ \section*{\scshape\Large Education \rule{\linewidth}{0.4pt}}
158
+ <<% for edu in resume.education %>>
159
+ {\large \textbf{ << edu.institution >> }} \\
160
+ {\fontseries{medium}\selectfont << edu.degree >><<% if edu.field_of_study %>>, << edu.field_of_study >><<% endif %>>} \\
161
+ {\scshape\fontseries{light}\selectfont\footnotesize << edu.date_range >>} \\
162
+ <<% if edu.highlights %>><<% for h in edu.highlights %>>{\footnotesize << h >>} \\<<% endfor %>><<% endif %>>
163
+ \vspace{1ex}
164
+ <<% endfor %>>
165
+
166
+ % Publications
167
+ <<% if resume.publications %>>
168
+ \phantomsection{}
169
+ \addcontentsline{toc}{section}{Publications}
170
+ \section*{\scshape\Large Publications \rule{\linewidth}{0.4pt}}
171
+ <<% for pub in resume.publications %>>
172
+ {\large \textbf{ << pub.title >> }} \\
173
+ {\scshape\fontseries{light}\selectfont\footnotesize << pub.authors | join(', ') >> \qquad << pub.date >>} \\
174
+ <<% if pub.doi_url %>>\href{ << pub.doi_url >> }{ << pub.doi_label or pub.doi_url >> }<<% endif %>>
175
+ \vspace{1ex}
176
+ <<% endfor %>>
177
+ <<% endif %>>
178
+
179
+ % Projects
180
+ <<% if resume.projects %>>
181
+ \phantomsection{}
182
+ \addcontentsline{toc}{section}{Projects}
183
+ \section*{\scshape\Large Projects \rule{\linewidth}{0.4pt}}
184
+ <<% for pr in resume.projects %>>
185
+ {\large \textbf{ << pr.title >> }} \\
186
+ <<% if pr.repo_url %>>\href{ << pr.repo_url >> }{ << pr.repo_label or pr.repo_url >> }\\<<% endif %>>
187
+ \begin{itemize}
188
+ \setlength{\itemsep}{-3pt}
189
+ <<% for h in pr.highlights %>>\item << h >>
190
+ <<% endfor %>>
191
+ \end{itemize}
192
+ <<% endfor %>>
193
+ <<% endif %>>
194
+
195
+ \vfill% footer
196
+ {\hfill\small\fontseries{extralight}\selectfont Page \thepage~of~\pageref{LastPage}\hfill}
197
+ \end{minipage}
198
+ }%
199
+ \end{document}
templates/template.tex ADDED
@@ -0,0 +1,370 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ \documentclass[10pt, letterpaper]{article}
2
+
3
+ % Packages:
4
+ \usepackage[
5
+ ignoreheadfoot, % set margins without considering header and footer
6
+ top=2 cm, % seperation between body and page edge from the top
7
+ bottom=2 cm, % seperation between body and page edge from the bottom
8
+ left=2 cm, % seperation between body and page edge from the left
9
+ right=2 cm, % seperation between body and page edge from the right
10
+ footskip=1.0 cm, % seperation between body and footer
11
+ % showframe % for debugging
12
+ ]{geometry} % for adjusting page geometry
13
+ \usepackage[explicit]{titlesec} % for customizing section titles
14
+ \usepackage{tabularx} % for making tables with fixed width columns
15
+ \usepackage{array} % tabularx requires this
16
+ \usepackage[dvipsnames]{xcolor} % for coloring text
17
+ \definecolor{primaryColor}{RGB}{0, 79, 144} % define primary color
18
+ \usepackage{enumitem} % for customizing lists
19
+ \usepackage{fontawesome5} % for using icons
20
+ \usepackage{amsmath} % for math
21
+ \usepackage[
22
+ pdftitle={John Doe's CV},
23
+ pdfauthor={John Doe},
24
+ pdfcreator={LaTeX with RenderCV},
25
+ colorlinks=true,
26
+ urlcolor=primaryColor
27
+ ]{hyperref} % for links, metadata and bookmarks
28
+ \usepackage[pscoord]{eso-pic} % for floating text on the page
29
+ \usepackage{calc} % for calculating lengths
30
+ \usepackage{bookmark} % for bookmarks
31
+ \usepackage{lastpage} % for getting the total number of pages
32
+ \usepackage{changepage} % for one column entries (adjustwidth environment)
33
+ \usepackage{paracol} % for two and three column entries
34
+ \usepackage{ifthen} % for conditional statements
35
+ \usepackage{needspace} % for avoiding page brake right after the section title
36
+ \usepackage{iftex} % check if engine is pdflatex, xetex or luatex
37
+
38
+ % Ensure that generate pdf is machine readable/ATS parsable:
39
+ \ifPDFTeX
40
+ \input{glyphtounicode}
41
+ \pdfgentounicode=1
42
+ \usepackage[T1]{fontenc}
43
+ \usepackage[utf8]{inputenc}
44
+ \usepackage{lmodern}
45
+ \fi
46
+
47
+ \usepackage[default, type1]{sourcesanspro}
48
+
49
+ % Some settings:
50
+ \AtBeginEnvironment{adjustwidth}{\partopsep0pt} % remove space before adjustwidth environment
51
+ \pagestyle{empty} % no header or footer
52
+ \setcounter{secnumdepth}{0} % no section numbering
53
+ \setlength{\parindent}{0pt} % no indentation
54
+ \setlength{\topskip}{0pt} % no top skip
55
+ \setlength{\columnsep}{0.15cm} % set column seperation
56
+ \makeatletter
57
+ \let\ps@customFooterStyle\ps@plain % Copy the plain style to customFooterStyle
58
+ \patchcmd{\ps@customFooterStyle}{\thepage}{
59
+ \color{gray}\textit{\small {{ resume.header.name }} - Page \thepage{} of \pageref*{LastPage}}
60
+ }{}{} % replace number by desired string
61
+ \makeatother
62
+ \pagestyle{customFooterStyle}
63
+
64
+ \titleformat{\section}{
65
+ % avoid page braking right after the section title
66
+ \needspace{4\baselineskip}
67
+ % make the font size of the section title large and color it with the primary color
68
+ \Large\color{primaryColor}
69
+ }{
70
+ }{
71
+ }{
72
+ % print bold title, give 0.15 cm space and draw a line of 0.8 pt thickness
73
+ % from the end of the title to the end of the body
74
+ \textbf{#1}\hspace{0.15cm}\titlerule[0.8pt]\hspace{-0.1cm}
75
+ }[] % section title formatting
76
+
77
+ \titlespacing{\section}{
78
+ % left space:
79
+ -1pt
80
+ }{
81
+ % top space:
82
+ 0.3 cm
83
+ }{
84
+ % bottom space:
85
+ 0.2 cm
86
+ } % section title spacing
87
+
88
+ % \renewcommand\labelitemi{$\vcenter{\hbox{\small$\bullet$}}$} % custom bullet points
89
+ \newenvironment{highlights}{
90
+ \begin{itemize}[
91
+ topsep=0.10 cm,
92
+ parsep=0.10 cm,
93
+ partopsep=0pt,
94
+ itemsep=0pt,
95
+ leftmargin=0.4 cm + 10pt
96
+ ]
97
+ }{
98
+ \end{itemize}
99
+ } % new environment for highlights
100
+
101
+ \newenvironment{highlightsforbulletentries}{
102
+ \begin{itemize}[
103
+ topsep=0.10 cm,
104
+ parsep=0.10 cm,
105
+ partopsep=0pt,
106
+ itemsep=0pt,
107
+ leftmargin=10pt
108
+ ]
109
+ }{
110
+ \end{itemize}
111
+ } % new environment for highlights for bullet entries
112
+
113
+
114
+ \newenvironment{onecolentry}{
115
+ \begin{adjustwidth}{
116
+ 0.2 cm + 0.00001 cm
117
+ }{
118
+ 0.2 cm + 0.00001 cm
119
+ }
120
+ }{
121
+ \end{adjustwidth}
122
+ } % new environment for one column entries
123
+
124
+ \newenvironment{twocolentry}[2][]{
125
+ \onecolentry
126
+ \def\secondColumn{#2}
127
+ \setcolumnwidth{\fill, 4.5 cm}
128
+ \begin{paracol}{2}
129
+ }{
130
+ \switchcolumn \raggedleft \secondColumn
131
+ \end{paracol}
132
+ \endonecolentry
133
+ } % new environment for two column entries
134
+
135
+ \newenvironment{threecolentry}[3][]{
136
+ \onecolentry
137
+ \def\thirdColumn{#3}
138
+ \setcolumnwidth{1 cm, \fill, 4.5 cm}
139
+ \begin{paracol}{3}
140
+ {\raggedright #2} \switchcolumn
141
+ }{
142
+ \switchcolumn \raggedleft \thirdColumn
143
+ \end{paracol}
144
+ \endonecolentry
145
+ } % new environment for three column entries
146
+
147
+ \newenvironment{header}{
148
+ \setlength{\topsep}{0pt}\par\kern\topsep\centering\color{primaryColor}\linespread{1.5}
149
+ }{
150
+ \par\kern\topsep
151
+ } % new environment for the header
152
+
153
+ \newcommand{\placelastupdatedtext}{ % \placetextbox{<horizontal pos>}{<vertical pos>}{<stuff>}
154
+ \AddToShipoutPictureFG*{ % Add <stuff> to current page foreground
155
+ \put(
156
+ \LenToUnit{\paperwidth-2 cm-0.2 cm+0.05cm},
157
+ \LenToUnit{\paperheight-1.0 cm}
158
+ ){\vtop{{\null}\makebox[0pt][c]{
159
+ \small\color{gray}\textit{Last updated in {{ resume.meta.last_updated_text | default('') }}}\hspace{\widthof{Last updated in {{ resume.meta.last_updated_text | default('') }} }}
160
+ }}}%
161
+ }%
162
+ }%
163
+
164
+ % save the original href command in a new command:
165
+ \let\hrefWithoutArrow\href
166
+
167
+ % new command for external links:
168
+ \renewcommand{\href}[2]{\hrefWithoutArrow{#1}{\ifthenelse{\equal{#2}{}}{ }{#2 }\raisebox{.15ex}{\footnotesize \faExternalLink*}}}
169
+
170
+
171
+ \begin{document}
172
+ \newcommand{\AND}{\unskip
173
+ \cleaders\copy\ANDbox\hskip\wd\ANDbox
174
+ \ignorespaces
175
+ }
176
+ \newsavebox\ANDbox
177
+ \sbox\ANDbox{}
178
+
179
+ \hypersetup{
180
+ pdftitle={{ '{' }}{{ resume.meta.pdf_title }}{{ '}' }},
181
+ pdfauthor={{ '{' }}{{ resume.meta.pdf_author }}{{ '}' }}
182
+ }
183
+ \placelastupdatedtext
184
+ \begin{header}
185
+ \fontsize{30 pt}{30 pt}
186
+ \textbf{ {{ resume.header.name }} }
187
+
188
+ \vspace{0.3 cm}
189
+
190
+ \normalsize
191
+ \mbox{{\footnotesize\faMapMarker*}\hspace*{0.13cm}{{ resume.header.location }}}%
192
+ \kern 0.25 cm%
193
+ \AND%
194
+ \kern 0.25 cm%
195
+ \mbox{\hrefWithoutArrow{mailto:{{ resume.header.email }}}{{\footnotesize\faEnvelope[regular]}\hspace*{0.13cm}{{ resume.header.email }}}}%
196
+ \kern 0.25 cm%
197
+ \AND%
198
+ \kern 0.25 cm%
199
+ \mbox{\hrefWithoutArrow{tel:{{ resume.header.phone | replace(' ', '') | replace('-', '') }}}{{\footnotesize\faPhone*}\hspace*{0.13cm}{{ resume.header.phone }}}}%
200
+ {% if resume.header.website_url %}
201
+ \kern 0.25 cm%
202
+ \AND%
203
+ \kern 0.25 cm%
204
+ \mbox{\hrefWithoutArrow{ {{ resume.header.website_url }} }{{\footnotesize\faLink}\hspace*{0.13cm}{{ resume.header.website_label or resume.header.website_url }}}}%
205
+ {% endif %}
206
+ {% if resume.header.linkedin_url %}
207
+ \kern 0.25 cm%
208
+ \AND%
209
+ \kern 0.25 cm%
210
+ \mbox{\hrefWithoutArrow{ {{ resume.header.linkedin_url }} }{{\footnotesize\faLinkedinIn}\hspace*{0.13cm}{{ resume.header.linkedin_handle or resume.header.linkedin_url }}}}%
211
+ {% endif %}
212
+ {% if resume.header.github_url %}
213
+ \kern 0.25 cm%
214
+ \AND%
215
+ \kern 0.25 cm%
216
+ \mbox{\hrefWithoutArrow{ {{ resume.header.github_url }} }{{\footnotesize\faGithub}\hspace*{0.13cm}{{ resume.header.github_handle or resume.header.github_url }}}}%
217
+ {% endif %}
218
+ \end{header}
219
+
220
+ \vspace{0.3 cm - 0.3 cm}
221
+
222
+
223
+ \section{Welcome to RenderCV!}
224
+
225
+ {% for p in resume.intro_paragraphs %}
226
+ \begin{onecolentry}
227
+ {{ p }}
228
+ \end{onecolentry}
229
+ {% if not loop.last %}
230
+ \vspace{0.2 cm}
231
+ {% endif %}
232
+ {% endfor %}
233
+
234
+
235
+
236
+
237
+
238
+ \section{Quick Guide}
239
+
240
+ \begin{onecolentry}
241
+ \begin{highlightsforbulletentries}
242
+ {% for item in resume.quick_guide_items %}
243
+ \item {{ item }}
244
+ {% endfor %}
245
+ \end{highlightsforbulletentries}
246
+ \end{onecolentry}
247
+
248
+ \section{Education}
249
+
250
+
251
+
252
+
253
+ {% for edu in resume.education %}
254
+ \begin{threecolentry}{\textbf{ {{ edu.degree }} }}{
255
+ {{ edu.date_range }}
256
+ }
257
+ \textbf{ {{ edu.institution }} }{% if edu.field_of_study %}, {{ edu.field_of_study }}{% endif %}
258
+ {% if edu.highlights %}
259
+ \begin{highlights}
260
+ {% for h in edu.highlights %}
261
+ \item {{ h }}
262
+ {% endfor %}
263
+ \end{highlights}
264
+ {% endif %}
265
+ \end{threecolentry}
266
+ {% endfor %}
267
+
268
+
269
+
270
+ \section{Experience}
271
+
272
+
273
+
274
+
275
+ {% for exp in resume.experience %}
276
+ \begin{twocolentry}{
277
+ {{ exp.location }}
278
+
279
+ {{ exp.date_range }}
280
+ }
281
+ \textbf{ {{ exp.company }} }, {{ exp.role }}
282
+ {% if exp.highlights %}
283
+ \begin{highlights}
284
+ {% for h in exp.highlights %}
285
+ \item {{ h }}
286
+ {% endfor %}
287
+ \end{highlights}
288
+ {% endif %}
289
+ \end{twocolentry}
290
+ {% if not loop.last %}
291
+ \vspace{0.2 cm}
292
+ {% endif %}
293
+ {% endfor %}
294
+
295
+
296
+
297
+
298
+ \section{Publications}
299
+
300
+
301
+
302
+
303
+ {% for pub in resume.publications %}
304
+ \begin{samepage}
305
+ \begin{twocolentry}{
306
+ {{ pub.date }}
307
+ }
308
+ \textbf{ {{ pub.title }} }
309
+
310
+ \vspace{0.10 cm}
311
+
312
+ {{ pub.authors | join(', ') }}
313
+ \vspace{0.10 cm}
314
+ {% if pub.doi_url %}
315
+ \href{ {{ pub.doi_url }} }{ {{ pub.doi_label or pub.doi_url }} }
316
+ {% endif %}
317
+ \end{twocolentry}
318
+ \end{samepage}
319
+ {% endfor %}
320
+
321
+
322
+
323
+ \section{Projects}
324
+
325
+
326
+
327
+
328
+ {% for pr in resume.projects %}
329
+ \begin{twocolentry}{
330
+ {% if pr.repo_url %}\href{ {{ pr.repo_url }} }{ {{ pr.repo_label or pr.repo_url }} }{% endif %}
331
+ }
332
+ \textbf{ {{ pr.title }} }
333
+ {% if pr.highlights %}
334
+ \begin{highlights}
335
+ {% for h in pr.highlights %}
336
+ \item {{ h }}
337
+ {% endfor %}
338
+ \end{highlights}
339
+ {% endif %}
340
+ \end{twocolentry}
341
+ {% if not loop.last %}
342
+ \vspace{0.2 cm}
343
+ {% endif %}
344
+ {% endfor %}
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+ \section{Technologies}
353
+
354
+
355
+
356
+
357
+ \begin{onecolentry}
358
+ \textbf{Languages:} {{ resume.technologies_section.languages | join(', ') }}
359
+ \end{onecolentry}
360
+
361
+ \vspace{0.2 cm}
362
+
363
+ \begin{onecolentry}
364
+ \textbf{Technologies:} {{ resume.technologies_section.technologies | join(', ') }}
365
+ \end{onecolentry}
366
+
367
+
368
+
369
+
370
+ \end{document}
templates/template_pe.tex ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ %%%%%%%%%%%%%%%%%
2
+ % * <shrabanipanigrahi@gmail.com> 2018-06-25T16:57:48.502Z:
3
+ %
4
+ % ^.
5
+ % This is an sample CV template created using altacv.cls
6
+ % (v1.1.3, 30 April 2017) written by LianTze Lim (liantze@gmail.com). Now compiles with pdfLaTeX, XeLaTeX and LuaLaTeX.
7
+ %
8
+ %% It may be distributed and/or modified under the
9
+ %% conditions of the LaTeX Project Public License, either version 1.3
10
+ %% of this license or (at your option) any later version.
11
+ %% The latest version of this license is in
12
+ %% http://www.latex-project.org/lppl.txt
13
+ %% and version 1.3 or later is part of all distributions of LaTeX
14
+ %% version 2003/12/01 or later.
15
+ %%%%%%%%%%%%%%%%
16
+
17
+ %% If you need to pass whatever options to xcolor
18
+ \PassOptionsToPackage{dvipsnames}{xcolor}
19
+
20
+ %% If you are using \orcid or academicons
21
+ %% icons, make sure you have the academicons
22
+ %% option here, and compile with XeLaTeX
23
+ %% or LuaLaTeX.
24
+ % \documentclass[10pt,a4paper,academicons]{altacv}
25
+
26
+ %% Use the "normalphoto" option if you want a normal photo instead of cropped to a circle
27
+ % \documentclass[10pt,a4paper,normalphoto]{altacv}
28
+
29
+ \documentclass[10pt,a4paper]{altacv}
30
+
31
+ %% AltaCV uses the fontawesome and academicon fonts
32
+ %% and packages.
33
+ %% See texdoc.net/pkg/fontawecome and http://texdoc.net/pkg/academicons for full list of symbols.
34
+ %%
35
+ %% Compile with LuaLaTeX for best results. If you
36
+ %% want to use XeLaTeX, you may need to install
37
+ %% Academicons.ttf in your operating system's font
38
+ %% folder.
39
+
40
+
41
+ % Change the page layout if you need to
42
+ \geometry{left=1cm,right=9cm,marginparwidth=6.8cm,marginparsep=1.2cm,top=1.25cm,bottom=1.25cm,footskip=2\baselineskip}
43
+
44
+ % Change the font if you want to.
45
+
46
+ % If using pdflatex:
47
+ \usepackage[utf8]{inputenc}
48
+ \usepackage[T1]{fontenc}
49
+ \usepackage[default]{lato}
50
+ \usepackage{hyperref}
51
+
52
+ % If using xelatex or lualatex:
53
+ % \setmainfont{Lato}
54
+
55
+ % Change the colours if you want to
56
+ \definecolor{darkblue}{HTML}{00394d}
57
+ \definecolor{Mulberry}{HTML}{005c99}
58
+ \definecolor{SlateGrey}{HTML}{000000}
59
+ \definecolor{LightGrey}{HTML}{333333}
60
+ \colorlet{heading}{darkblue}
61
+ \colorlet{accent}{Mulberry}
62
+ \colorlet{emphasis}{SlateGrey}
63
+ \colorlet{body}{LightGrey}
64
+
65
+ % Change the bullets for itemize and rating marker
66
+ % for \cvskill if you want to
67
+ \renewcommand{\itemmarker}{{\small\textbullet}}
68
+ \renewcommand{\ratingmarker}{\faCircle}
69
+
70
+ %% sample.bib contains your publications
71
+ \addbibresource{sample.bib}
72
+
73
+ \begin{document}
74
+ \name{Pierre-Emmanuel DIOT}
75
+ \tagline{Data Scientist \& Founder}
76
+ \photo{3cm}{photo_cv}
77
+ \personalinfo{%
78
+ % Not all of these are required!
79
+ % You can add your own with \printinfo{symbol}{detail}
80
+ \mailaddress{p.emmanuel.diot@gmail.com}
81
+ \linkedin{\href{https://www.linkedin.com/in/pierre-emmanuel-diot/}{pierre-emmanuel diot}}
82
+ \github{\href{https://github.com/PeDiot}{github}}
83
+ % \homepage{\href{https://fr.pinterest.com/shoprecove/}{pinterest}}
84
+ %% You MUST add the academicons option to \documentclass, then compile with LuaLaTeX or XeLaTeX, if you want to use \orcid or other academicons commands.
85
+ % \orcid{orcid.org/0000-0000-0000-0000}
86
+ }
87
+
88
+ %% Make the header extend all the way to the right, if you want.
89
+ \begin{fullwidth}
90
+ \makecvheader
91
+ \end{fullwidth}
92
+
93
+ %% Provide the file name containing the sidebar contents as an optional parameter to \cvsection.
94
+ %% You can always just use \marginpar{...} if you do
95
+ %% not need to align the top of the contents to any
96
+ %% \cvsection title in the "main" bar.
97
+
98
+ \cvsection[page1sidebar]{Work Experience}
99
+
100
+ \vspace{.2cm}
101
+
102
+ \cvevent{\textbf{Co-Founder \& CTO}}{\href{https://shoprecove.com}{Recove}, Paris}{Since January 2025}
103
+
104
+ \vspace{.1cm}
105
+
106
+ \textit{Co-founded and scaled a fashion discovery application that connects Pinterest inspiration with Vinted's marketplace, growing the platform to 80,000+ total users and driving over 600,000 clicks to Vinted.}
107
+
108
+ \vspace{.1cm}
109
+
110
+ \begin{itemize}
111
+ \item[--] Engineered and deployed a production-grade multimodal search engine, implementing retrieval and ranking algorithms to query a vector database of over 20 million Vinted listings.
112
+ \item[--] Designed and built the data infrastructure on Google Cloud Platform \& Pinecone, creating automated ETL pipelines to ingest, process, and continuously update listings data.
113
+ \item[--] Developed a scalable REST API with Django to serve model predictions and data to both web and mobile clients.
114
+ \item[--] Owned the full product lifecycle, from technical architecture and model development to deployment and iteration based on user feedback.
115
+ \item[--] \textbf{Tech Stack}: Python, Vector Database (Pinecone), Google Cloud Platform (BigQuery, Cloud Run), Docker, Django, React, Git.
116
+ \end{itemize}
117
+
118
+ \divider
119
+
120
+ \cvevent{\textbf{Lead Data Science}}{HelloSafe, Paris}{June 2023 -- August 2024}
121
+
122
+ \vspace{.1cm}
123
+
124
+ \textit{Built the company's core data infrastructure and developed key machine learning models to drive product strategy and marketing efficiency.}
125
+
126
+ \vspace{.1cm}
127
+
128
+ \begin{itemize}
129
+ \item[--] Architected and built the company's first central data warehouse, integrating multiple sources (website analytics, Typeform conversions, revenue data) to create a single source of truth for all product and business reporting.
130
+ \item[--] Developed a classification model to predict user conversion based on web behavior, providing actionable insights that improved marketing campaign retargeting.
131
+ \item[--] \textbf{Tech Stack}: Python (Scikit-learn, Pandas), SQL (Google BigQuery)
132
+ \end{itemize}
133
+
134
+ \divider
135
+
136
+ \cvevent{\textbf{Data Scientist R\&D}}{Epsilon France (Publicis Groupe), Paris}{April 2022 -- Aug. 2022}
137
+
138
+ \vspace{.1cm}
139
+
140
+ \begin{itemize}
141
+ \item[--] Led an R\&D project to design and build a standardized toolkit in R for Marketing Mix Modeling (MMM), a key method for measuring marketing impact.
142
+ \item[--] The tool automated the end-to-end modeling process, from data transformation and econometric modeling to parameter optimization, ensuring scientific rigor and reproducibility for future analyses.
143
+ \item[--] \textbf{Tech Stack}: R, Git.
144
+ \end{itemize}
145
+
146
+ \end{document}
uv.lock ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.10"
4
+
5
+ [[package]]
6
+ name = "annotated-types"
7
+ version = "0.7.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
10
+ wheels = [
11
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
12
+ ]
13
+
14
+ [[package]]
15
+ name = "dnspython"
16
+ version = "2.8.0"
17
+ source = { registry = "https://pypi.org/simple" }
18
+ sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
19
+ wheels = [
20
+ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
21
+ ]
22
+
23
+ [[package]]
24
+ name = "email-validator"
25
+ version = "2.3.0"
26
+ source = { registry = "https://pypi.org/simple" }
27
+ dependencies = [
28
+ { name = "dnspython" },
29
+ { name = "idna" },
30
+ ]
31
+ sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" }
32
+ wheels = [
33
+ { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" },
34
+ ]
35
+
36
+ [[package]]
37
+ name = "idna"
38
+ version = "3.10"
39
+ source = { registry = "https://pypi.org/simple" }
40
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
41
+ wheels = [
42
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
43
+ ]
44
+
45
+ [[package]]
46
+ name = "jinja2"
47
+ version = "3.1.6"
48
+ source = { registry = "https://pypi.org/simple" }
49
+ dependencies = [
50
+ { name = "markupsafe" },
51
+ ]
52
+ sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
53
+ wheels = [
54
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
55
+ ]
56
+
57
+ [[package]]
58
+ name = "markupsafe"
59
+ version = "3.0.2"
60
+ source = { registry = "https://pypi.org/simple" }
61
+ sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" }
62
+ wheels = [
63
+ { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" },
64
+ { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" },
65
+ { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" },
66
+ { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" },
67
+ { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" },
68
+ { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" },
69
+ { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" },
70
+ { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" },
71
+ { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" },
72
+ { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" },
73
+ { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" },
74
+ { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" },
75
+ { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" },
76
+ { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" },
77
+ { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" },
78
+ { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" },
79
+ { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" },
80
+ { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" },
81
+ { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" },
82
+ { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" },
83
+ { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" },
84
+ { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" },
85
+ { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" },
86
+ { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" },
87
+ { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" },
88
+ { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" },
89
+ { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" },
90
+ { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" },
91
+ { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" },
92
+ { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" },
93
+ { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" },
94
+ { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" },
95
+ { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" },
96
+ { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" },
97
+ { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" },
98
+ { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" },
99
+ { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" },
100
+ { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" },
101
+ { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" },
102
+ { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" },
103
+ { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" },
104
+ { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" },
105
+ { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" },
106
+ { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" },
107
+ { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" },
108
+ { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" },
109
+ { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" },
110
+ { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" },
111
+ { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" },
112
+ { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" },
113
+ ]
114
+
115
+ [[package]]
116
+ name = "pydantic"
117
+ version = "2.11.9"
118
+ source = { registry = "https://pypi.org/simple" }
119
+ dependencies = [
120
+ { name = "annotated-types" },
121
+ { name = "pydantic-core" },
122
+ { name = "typing-extensions" },
123
+ { name = "typing-inspection" },
124
+ ]
125
+ sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
126
+ wheels = [
127
+ { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
128
+ ]
129
+
130
+ [package.optional-dependencies]
131
+ email = [
132
+ { name = "email-validator" },
133
+ ]
134
+
135
+ [[package]]
136
+ name = "pydantic-core"
137
+ version = "2.33.2"
138
+ source = { registry = "https://pypi.org/simple" }
139
+ dependencies = [
140
+ { name = "typing-extensions" },
141
+ ]
142
+ sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
143
+ wheels = [
144
+ { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" },
145
+ { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" },
146
+ { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" },
147
+ { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" },
148
+ { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" },
149
+ { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" },
150
+ { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" },
151
+ { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" },
152
+ { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" },
153
+ { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" },
154
+ { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" },
155
+ { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" },
156
+ { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" },
157
+ { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" },
158
+ { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" },
159
+ { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" },
160
+ { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" },
161
+ { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" },
162
+ { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" },
163
+ { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" },
164
+ { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" },
165
+ { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" },
166
+ { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" },
167
+ { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" },
168
+ { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" },
169
+ { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" },
170
+ { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" },
171
+ { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
172
+ { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
173
+ { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
174
+ { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
175
+ { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
176
+ { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
177
+ { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
178
+ { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
179
+ { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
180
+ { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
181
+ { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
182
+ { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
183
+ { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
184
+ { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
185
+ { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
186
+ { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
187
+ { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
188
+ { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
189
+ { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
190
+ { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
191
+ { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
192
+ { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
193
+ { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
194
+ { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
195
+ { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
196
+ { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
197
+ { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
198
+ { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
199
+ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
200
+ { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
201
+ { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
202
+ { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" },
203
+ { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" },
204
+ { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" },
205
+ { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" },
206
+ { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" },
207
+ { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" },
208
+ { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" },
209
+ { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" },
210
+ { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" },
211
+ { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" },
212
+ { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" },
213
+ { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" },
214
+ { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" },
215
+ { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" },
216
+ { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" },
217
+ { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" },
218
+ { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" },
219
+ { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" },
220
+ ]
221
+
222
+ [[package]]
223
+ name = "resume-mcp"
224
+ version = "0.1.0"
225
+ source = { virtual = "." }
226
+ dependencies = [
227
+ { name = "jinja2" },
228
+ { name = "pydantic", extra = ["email"] },
229
+ ]
230
+
231
+ [package.metadata]
232
+ requires-dist = [
233
+ { name = "jinja2", specifier = ">=3.1" },
234
+ { name = "pydantic", extras = ["email"], specifier = ">=2.7" },
235
+ ]
236
+
237
+ [package.metadata.requires-dev]
238
+ dev = []
239
+
240
+ [[package]]
241
+ name = "typing-extensions"
242
+ version = "4.15.0"
243
+ source = { registry = "https://pypi.org/simple" }
244
+ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
245
+ wheels = [
246
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
247
+ ]
248
+
249
+ [[package]]
250
+ name = "typing-inspection"
251
+ version = "0.4.1"
252
+ source = { registry = "https://pypi.org/simple" }
253
+ dependencies = [
254
+ { name = "typing-extensions" },
255
+ ]
256
+ sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
257
+ wheels = [
258
+ { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
259
+ ]