calibrcv 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cagan Oflazoglu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ <p align="center">
2
+ <img src="assets/logo.png" alt="CalibrCV" width="120" />
3
+ </p>
4
+ <h1 align="center">calibrcv</h1>
5
+ <p align="center">
6
+ Your resume is probably getting rejected by robots. Fix it in your terminal.
7
+ <br /><br />
8
+ <a href="#quick-start">Quick Start</a>
9
+ &middot;
10
+ <a href="#what-happens-when-you-run-it">How It Works</a>
11
+ &middot;
12
+ <a href="#llm-providers">Providers</a>
13
+ &middot;
14
+ <a href="#the-8-calibrcv-laws">The 8 Laws</a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
19
+ <a href="https://nodejs.org/en/"><img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node >= 18"></a>
20
+ <a href="https://ollama.com"><img src="https://img.shields.io/badge/LLM-Ollama%20(local)-black.svg" alt="Ollama"></a>
21
+ <a href="https://www.npmjs.com/package/calibrcv"><img src="https://img.shields.io/npm/v/calibrcv.svg" alt="npm version"></a>
22
+ </p>
23
+
24
+ <p align="center">
25
+ <img src="assets/demo.gif" alt="calibrcv demo" width="700" />
26
+ </p>
27
+
28
+ ---
29
+
30
+ **calibrcv** is an open-source CLI that takes your resume PDF, rewrites it using AI under strict editorial rules, compiles it to LaTeX, and enforces a single-page limit through an agentic trim loop. Runs fully offline with Ollama. No account, no cloud, no data leaves your machine unless you choose a cloud provider.
31
+
32
+ > Most resume tools slap a template on your content and call it optimized. calibrcv runs a 9-stage pipeline with an actual scoring engine. It rewrites every bullet, enforces action verbs, kills filler, compiles to LaTeX, and loops until the result fits on one page. Then it scores the output against 5 ATS categories so you know exactly where you stand.
33
+
34
+ ## Quick Start
35
+
36
+ ```bash
37
+ npm install -g calibrcv
38
+
39
+ # pull a local model (free, runs on your machine)
40
+ ollama pull llama3.1
41
+
42
+ # optimize your resume
43
+ calibrcv build resume.pdf
44
+ ```
45
+
46
+ That's it. Three commands. You get back a PDF, a `.tex` source file, and a terminal score report.
47
+
48
+ ## What Happens When You Run It
49
+
50
+ ```
51
+ resume.pdf
52
+ |
53
+ v
54
+ 1. Parse PDF .............. extract raw text
55
+ |
56
+ v
57
+ 2. Analyze ................ LLM diagnoses weaknesses, generates 3-7 questions
58
+ |
59
+ v
60
+ 3. Enrichment Interview ... you answer in the terminal (skippable)
61
+ |
62
+ v
63
+ 4. Synthesize ............. LLM rewrites every section under the 8 Laws
64
+ |
65
+ v
66
+ 5. Generate LaTeX ......... fills the sb2nov/resume template
67
+ |
68
+ v
69
+ 6. Compile + Trim Loop .... compiles to PDF; if >1 page, AI trims
70
+ | ^ and recompiles (up to 6 rounds)
71
+ | |___________________|
72
+ v
73
+ 7. ATS Score .............. pure algorithmic, 100-point scale
74
+ |
75
+ v
76
+ optimized.pdf + resume.tex + score report
77
+ ```
78
+
79
+ ## Usage
80
+
81
+ ### Build (full pipeline)
82
+
83
+ ```bash
84
+ # basic
85
+ calibrcv build resume.pdf
86
+
87
+ # custom output path
88
+ calibrcv build resume.pdf -o optimized.pdf
89
+
90
+ # target a sector
91
+ calibrcv build resume.pdf --sector banking
92
+
93
+ # tailor for a specific job posting
94
+ calibrcv build resume.pdf --job-url https://linkedin.com/jobs/view/123456
95
+
96
+ # tailor from a local job description file
97
+ calibrcv build resume.pdf --job-desc posting.txt
98
+
99
+ # use a specific cloud provider
100
+ calibrcv build resume.pdf --provider groq
101
+
102
+ # use a different Ollama model
103
+ calibrcv build resume.pdf --model mistral
104
+
105
+ # skip the enrichment Q&A
106
+ calibrcv build resume.pdf --skip-enrich
107
+ ```
108
+
109
+ ### Score (no AI needed)
110
+
111
+ Just want to know where your resume stands? The scoring engine is pure algorithmic. No LLM calls, runs instantly.
112
+
113
+ ```bash
114
+ calibrcv score resume.pdf
115
+ calibrcv score resume.pdf --job-desc posting.txt
116
+ ```
117
+
118
+ ## LLM Providers
119
+
120
+ calibrcv tries providers in order and falls back automatically. Ollama is always first.
121
+
122
+ | Provider | Model | How to enable |
123
+ |----------|-------|---------------|
124
+ | **Ollama** (default) | `llama3.1:8b` | `ollama serve` + `ollama pull llama3.1` |
125
+ | Groq | `llama-3.3-70b` | Set `GROQ_API_KEY` |
126
+ | Google Gemini | `gemini-2.5-flash` | Set `GEMINI_API_KEY` |
127
+ | OpenRouter | `llama-3.1-8b` (free tier) | Set `OPENROUTER_API_KEY` |
128
+
129
+ Put your keys in `.env` in your working directory or at `~/.calibrcv/.env`:
130
+
131
+ ```bash
132
+ GROQ_API_KEY=gsk_...
133
+ GEMINI_API_KEY=AI...
134
+ OPENROUTER_API_KEY=sk-or-...
135
+ OLLAMA_MODEL=llama3.1
136
+ ```
137
+
138
+ Force a specific provider: `calibrcv build resume.pdf --provider groq`
139
+
140
+ ## The 8 CalibrCV Laws
141
+
142
+ Every resume produced by calibrcv follows these rules. No exceptions, no overrides.
143
+
144
+ | # | Law | What it means |
145
+ |---|-----|---------------|
146
+ | 1 | **100-Character Bullets** | Every bullet fits in 100 characters. Period. |
147
+ | 2 | **HBS Action Verbs** | Every bullet opens with an approved verb (Architected, Deployed, Engineered...) |
148
+ | 3 | **Harvard-Style Summary** | 3-4 sentences, zero pronouns (no I/my/me/we), executive voice |
149
+ | 4 | **Realistic Grounding** | No inflated claims. Seniority-appropriate language only. |
150
+ | 5 | **Zero Em Dashes** | Replaced with semicolons, colons, or restructured sentences |
151
+ | 6 | **Two-Line Skills** | Exactly two rows: "Quantitative Stack" and "Analytic Domain" |
152
+ | 7 | **Strict Bullet Counts** | Experience: 2-3 bullets. Projects: exactly 2. |
153
+ | 8 | **Abbreviated Dates** | "Jun. 2023" format throughout |
154
+
155
+ ## ATS Scoring
156
+
157
+ The scoring engine is pure math. No AI calls, no external API. Five categories, 100 points.
158
+
159
+ | Category | Points | What it checks |
160
+ |----------|--------|---------------|
161
+ | Structural Integrity | 0-20 | Required sections present, dates on all entries |
162
+ | Keyword Density | 0-30 | TF-IDF matching against job description (or lexical richness) |
163
+ | Content Quality | 0-25 | HBS verb compliance, quantified metrics, bullet length |
164
+ | Parsability | 0-15 | Box-drawing chars, em dashes, smart quotes, encoding issues |
165
+ | Completeness | 0-10 | Email, phone, LinkedIn, location, skills breadth |
166
+
167
+ ## Prerequisites
168
+
169
+ - **Node.js 18+**
170
+ - **Ollama** for local LLM (or a cloud API key from the table above)
171
+ - **LaTeX compiler** for PDF output: `tectonic`, `pdflatex`, or `xelatex`
172
+ - macOS: `brew install tectonic` or `brew install --cask mactex`
173
+ - Ubuntu/Debian: `sudo apt install texlive-full`
174
+ - Windows: [MiKTeX](https://miktex.org/download)
175
+ - If no compiler is found, calibrcv still outputs the `.tex` source file
176
+
177
+ ## Why This Exists
178
+
179
+ I built CalibrCV as a full SaaS (Vercel + React + Supabase + Stripe). It worked, but it was heavy. Accounts, payments, database, browser automation, email notifications. A lot of infrastructure for a tool that fundamentally takes text in and spits a PDF out.
180
+
181
+ So I ripped the core pipeline out and turned it into something you can install in 10 seconds and run offline. The AI logic, the prompts, the scoring engine, the LaTeX template: all the same. The delivery mechanism changed from "web app with auth" to "three commands in your terminal."
182
+
183
+ ## Contributing
184
+
185
+ PRs welcome. If you want to add a new LLM provider, the interface is simple: look at `src/providers/ollama.js` (55 lines) as a reference.
186
+
187
+ ```bash
188
+ git clone https://github.com/Coflazo/calibrcv-cli.git
189
+ cd calibrcv-cli
190
+ npm install
191
+ node bin/calibrcv.js --help
192
+ ```
193
+
194
+ ## License
195
+
196
+ [MIT](LICENSE)
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { readFileSync, existsSync } from 'fs';
6
+ import { resolve, basename } from 'path';
7
+
8
+ import { loadConfig } from '../src/config.js';
9
+ import { configureProviders } from '../src/lib/ai-router.js';
10
+ import { ResumePipeline } from '../src/pipeline/orchestrator.js';
11
+ import { atsScorer } from '../src/lib/ats-scorer.js';
12
+ import { extractTextFromPDF } from '../src/lib/pdf-extractor.js';
13
+ import { createPipelineUI } from '../src/ui/spinner.js';
14
+ import { runInterview } from '../src/ui/interview.js';
15
+ import { printReport } from '../src/ui/report.js';
16
+ import { scrapeJobUrl } from '../src/lib/job-scraper.js';
17
+
18
+ const program = new Command();
19
+
20
+ program
21
+ .name('calibrcv')
22
+ .description('AI-powered resume optimizer. Runs in your terminal.')
23
+ .version('1.0.0');
24
+
25
+ // ── BUILD command ─────────────────────────────────────────────
26
+
27
+ program
28
+ .command('build')
29
+ .description('Build an optimized resume from a PDF')
30
+ .argument('<resume>', 'Path to your resume PDF')
31
+ .option('-o, --output <path>', 'Output PDF path')
32
+ .option('-s, --sector <sector>', 'Target sector (e.g. banking, consulting, technology)')
33
+ .option('--job-url <url>', 'Job posting URL for tailoring')
34
+ .option('--job-desc <path>', 'Path to job description text file')
35
+ .option('-p, --provider <name>', 'LLM provider (ollama, groq, gemini, openrouter)')
36
+ .option('-m, --model <name>', 'Ollama model name')
37
+ .option('--skip-enrich', 'Skip the enrichment interview')
38
+ .option('-v, --verbose', 'Verbose output')
39
+ .action(async (resumePath, opts) => {
40
+ try {
41
+ const config = loadConfig(opts);
42
+ if (config.model) process.env.OLLAMA_MODEL = config.model;
43
+ configureProviders({ provider: config.provider });
44
+
45
+ // Read the PDF
46
+ const absPath = resolve(resumePath);
47
+ if (!existsSync(absPath)) {
48
+ console.error(chalk.red(`File not found: ${absPath}`));
49
+ process.exit(1);
50
+ }
51
+ const pdfBuffer = readFileSync(absPath);
52
+
53
+ // Output path
54
+ const outputPath = config.output
55
+ ? resolve(config.output)
56
+ : resolve(basename(absPath, '.pdf') + '_calibrcv.pdf');
57
+
58
+ // Job description (optional)
59
+ let jobDescription = null;
60
+ if (config.jobUrl) {
61
+ console.log(chalk.dim(` Fetching job description from ${config.jobUrl}...`));
62
+ try {
63
+ const job = await scrapeJobUrl(config.jobUrl);
64
+ jobDescription = `Title: ${job.title}\nCompany: ${job.company}\n\n${job.description}`;
65
+ console.log(chalk.dim(` Found: ${job.title} at ${job.company}`));
66
+ } catch (err) {
67
+ console.error(chalk.yellow(` Could not scrape job URL: ${err.message}`));
68
+ }
69
+ } else if (config.jobDesc) {
70
+ const jdPath = resolve(config.jobDesc);
71
+ if (existsSync(jdPath)) {
72
+ jobDescription = readFileSync(jdPath, 'utf-8');
73
+ } else {
74
+ console.error(chalk.yellow(` Job description file not found: ${jdPath}`));
75
+ }
76
+ }
77
+
78
+ console.log('');
79
+ console.log(chalk.bold(' CalibrCV'));
80
+ console.log(chalk.dim(` ${basename(absPath)} -> ${basename(outputPath)}`));
81
+ console.log('');
82
+
83
+ const pipeline = new ResumePipeline();
84
+ const ui = createPipelineUI();
85
+
86
+ pipeline.on('progress', (event) => ui.onProgress(event));
87
+
88
+ // Phase 1: Analyze (may pause for enrichment)
89
+ const phase1 = await pipeline.run({
90
+ pdfBuffer,
91
+ targetSector: config.sector,
92
+ jobDescription,
93
+ outputPath,
94
+ });
95
+
96
+ if (phase1.requiresEnrichment) {
97
+ ui.pause();
98
+
99
+ const answers = await runInterview(phase1.questions, config.skipEnrich);
100
+
101
+ ui.resume();
102
+
103
+ // Phase 2: Resume pipeline with answers
104
+ const result = await pipeline.run({
105
+ pdfBuffer,
106
+ targetSector: config.sector,
107
+ enrichmentAnswers: answers,
108
+ resumeText: phase1.resumeText,
109
+ analysis: phase1.analysis,
110
+ jobDescription,
111
+ outputPath,
112
+ });
113
+
114
+ ui.stop();
115
+ printReport(result.atsBreakdown);
116
+
117
+ if (result.pdfBuffer) {
118
+ console.log(chalk.green(` PDF saved to ${outputPath}`));
119
+ console.log(chalk.dim(` LaTeX source saved to ${outputPath.replace(/\.pdf$/i, '.tex')}`));
120
+ } else {
121
+ console.log(chalk.yellow(' No PDF generated (LaTeX compiler not found).'));
122
+ console.log(chalk.dim(` LaTeX source saved to ${outputPath.replace(/\.pdf$/i, '.tex')}`));
123
+ }
124
+ }
125
+
126
+ } catch (err) {
127
+ console.error(chalk.red(`\n Error: ${err.message}`));
128
+ if (err.errors) {
129
+ for (const e of err.errors) {
130
+ console.error(chalk.dim(` ${e.provider}: ${e.error}`));
131
+ }
132
+ }
133
+ process.exit(1);
134
+ }
135
+ });
136
+
137
+ // ── SCORE command ─────────────────────────────────────────────
138
+
139
+ program
140
+ .command('score')
141
+ .description('Run ATS scoring on a resume PDF (no AI needed)')
142
+ .argument('<resume>', 'Path to your resume PDF')
143
+ .option('--job-desc <path>', 'Path to job description text file')
144
+ .option('--job-url <url>', 'Job posting URL for keyword matching')
145
+ .action(async (resumePath, opts) => {
146
+ try {
147
+ const absPath = resolve(resumePath);
148
+ if (!existsSync(absPath)) {
149
+ console.error(chalk.red(`File not found: ${absPath}`));
150
+ process.exit(1);
151
+ }
152
+
153
+ const pdfBuffer = readFileSync(absPath);
154
+ const { text } = await extractTextFromPDF(pdfBuffer);
155
+
156
+ let jobDescription = null;
157
+ if (opts.jobUrl) {
158
+ try {
159
+ const job = await scrapeJobUrl(opts.jobUrl);
160
+ jobDescription = job.description;
161
+ } catch (_) { /* ignore */ }
162
+ } else if (opts.jobDesc) {
163
+ const jdPath = resolve(opts.jobDesc);
164
+ if (existsSync(jdPath)) {
165
+ jobDescription = readFileSync(jdPath, 'utf-8');
166
+ }
167
+ }
168
+
169
+ // Build a minimal resume JSON from raw text for scoring
170
+ const resumeJSON = {
171
+ summary: '',
172
+ experience: [{ title: '', bullets: text.split('\n').filter(l => l.trim().length > 20) }],
173
+ education: [{ institution: '', dates: 'present' }],
174
+ skills: { quantitative_stack: '', analytic_domain: '' },
175
+ projects: [],
176
+ contact: {
177
+ email: text.match(/[\w.-]+@[\w.-]+/)?.[0] || '',
178
+ phone: text.match(/[\+\d\s\-\(\)]{7,}/)?.[0] || '',
179
+ linkedin: text.match(/linkedin\.com\/in\/([\w-]+)/)?.[1] || '',
180
+ location: '',
181
+ },
182
+ };
183
+
184
+ const report = atsScorer.score(text, resumeJSON, jobDescription);
185
+ printReport(report);
186
+
187
+ } catch (err) {
188
+ console.error(chalk.red(`\n Error: ${err.message}`));
189
+ process.exit(1);
190
+ }
191
+ });
192
+
193
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "calibrcv",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered resume optimizer that runs in your terminal.",
5
+ "type": "module",
6
+ "bin": {
7
+ "calibrcv": "./bin/calibrcv.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "keywords": [
13
+ "resume",
14
+ "resume-builder",
15
+ "resume-optimizer",
16
+ "cv",
17
+ "ats",
18
+ "ats-score",
19
+ "ats-friendly",
20
+ "cli",
21
+ "ai",
22
+ "ollama",
23
+ "latex",
24
+ "job-search",
25
+ "career",
26
+ "optimization",
27
+ "open-source"
28
+ ],
29
+ "license": "MIT",
30
+ "author": "Cagan Oflazoglu",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Coflazo/calibrcv-cli"
34
+ },
35
+ "homepage": "https://github.com/Coflazo/calibrcv-cli#readme",
36
+ "bugs": {
37
+ "url": "https://github.com/Coflazo/calibrcv-cli/issues"
38
+ },
39
+ "files": [
40
+ "bin/",
41
+ "src/",
42
+ "LICENSE",
43
+ "README.md"
44
+ ],
45
+ "dependencies": {
46
+ "commander": "^12.0.0",
47
+ "ora": "^8.0.0",
48
+ "chalk": "^5.3.0",
49
+ "@inquirer/prompts": "^7.0.0",
50
+ "dotenv": "^16.4.0",
51
+ "pdf-parse": "^1.1.1",
52
+ "pdf-lib": "^1.17.1",
53
+ "natural": "^8.0.1",
54
+ "cheerio": "^1.0.0",
55
+ "groq-sdk": "^0.7.0",
56
+ "@google/generative-ai": "^0.21.0"
57
+ }
58
+ }
package/src/config.js ADDED
@@ -0,0 +1,31 @@
1
+ import { config as loadDotenv } from 'dotenv';
2
+ import { existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+
6
+ /**
7
+ * Load configuration from .env files and CLI options.
8
+ * Priority: CLI flags > env vars > .env in CWD > ~/.calibrcv/.env > defaults
9
+ *
10
+ * @param {object} cliOptions - Options from commander
11
+ * @returns {object} Merged configuration
12
+ */
13
+ export function loadConfig(cliOptions = {}) {
14
+ // Load .env files (lowest priority first, higher priority overrides)
15
+ const homeEnv = join(homedir(), '.calibrcv', '.env');
16
+ if (existsSync(homeEnv)) {
17
+ loadDotenv({ path: homeEnv, override: false, quiet: true });
18
+ }
19
+ loadDotenv({ override: false, quiet: true }); // CWD .env
20
+
21
+ return {
22
+ provider: cliOptions.provider || null,
23
+ model: cliOptions.model || process.env.OLLAMA_MODEL || 'llama3.1',
24
+ sector: cliOptions.sector || 'General',
25
+ output: cliOptions.output || null,
26
+ jobUrl: cliOptions.jobUrl || null,
27
+ jobDesc: cliOptions.jobDesc || null,
28
+ skipEnrich: cliOptions.skipEnrich || false,
29
+ verbose: cliOptions.verbose || false,
30
+ };
31
+ }
@@ -0,0 +1,15 @@
1
+ export const HBS_VERBS = [
2
+ 'architected', 'engineered', 'synthesized', 'constructed', 'deployed',
3
+ 'formulated', 'orchestrated', 'executed', 'modelled', 'modeled', 'spearheaded',
4
+ 'designed', 'developed', 'delivered', 'automated', 'optimised', 'optimized',
5
+ 'launched', 'scaled', 'diagnosed', 'evaluated', 'mapped', 'built',
6
+ 'implemented', 'piloted', 'led', 'directed', 'managed', 'analysed', 'analyzed',
7
+ 'generated', 'secured', 'reduced', 'increased', 'projected', 'streamlined',
8
+ 'transformed', 'drove', 'established', 'created', 'expanded', 'accelerated',
9
+ 'pioneered', 'championed', 'coordinated', 'supervised', 'trained', 'mentored',
10
+ 'presented', 'negotiated', 'resolved', 'produced', 'maintained', 'integrated',
11
+ 'migrated', 'refactored', 'tested', 'validated', 'documented', 'published',
12
+ 'researched', 'identified', 'improved', 'achieved', 'exceeded', 'won',
13
+ 'contributed', 'supported', 'facilitated', 'consolidated', 'restructured',
14
+ 'configured', 'overhauled', 'devised', 'initiated', 'cultivated',
15
+ ];
@@ -0,0 +1,114 @@
1
+ export const LATEX_TEMPLATE = `%------------------------
2
+ % Resume in Latex
3
+ % Author: CalibrCV.ai
4
+ % Based off: https://github.com/sb2nov/resume
5
+ % License: MIT
6
+ %------------------------
7
+
8
+ \\\\documentclass[letterpaper,11pt]{article}
9
+
10
+ \\\\usepackage{latexsym}
11
+ \\\\usepackage[empty]{fullpage}
12
+ \\\\usepackage{titlesec}
13
+ \\\\usepackage{marvosym}
14
+ \\\\usepackage[usenames,dvipsnames]{color}
15
+ \\\\usepackage{verbatim}
16
+ \\\\usepackage{enumitem}
17
+ \\\\usepackage[hidelinks]{hyperref}
18
+ \\\\usepackage{fancyhdr}
19
+ \\\\usepackage[english]{babel}
20
+ \\\\usepackage{tabularx}
21
+ \\\\usepackage{fontawesome5}
22
+ \\\\input{glyphtounicode}
23
+
24
+ \\\\pagestyle{fancy}
25
+ \\\\fancyhf{}
26
+ \\\\fancyfoot{}
27
+ \\\\renewcommand{\\\\headrulewidth}{0pt}
28
+ \\\\renewcommand{\\\\footrulewidth}{0pt}
29
+
30
+ \\\\addtolength{\\\\oddsidemargin}{-0.5in}
31
+ \\\\addtolength{\\\\evensidemargin}{-0.5in}
32
+ \\\\addtolength{\\\\textwidth}{1in}
33
+ \\\\addtolength{\\\\topmargin}{-0.5in}
34
+ \\\\addtolength{\\\\textheight}{1.0in}
35
+
36
+ \\\\urlstyle{same}
37
+ \\\\raggedbottom
38
+ \\\\raggedright
39
+ \\\\setlength{\\\\tabcolsep}{0in}
40
+
41
+ \\\\titleformat{\\\\section}{
42
+ \\\\vspace{-4pt}\\\\scshape\\\\raggedright\\\\large
43
+ }{}{0em}{}[\\\\color{black}\\\\titlerule \\\\vspace{-5pt}]
44
+
45
+ \\\\pdfgentounicode=1
46
+
47
+ \\\\newcommand{\\\\resumeItem}[1]{
48
+ \\\\item\\\\small{{#1 \\\\vspace{-2pt}}}
49
+ }
50
+
51
+ \\\\newcommand{\\\\resumeSubheading}[4]{
52
+ \\\\vspace{-2pt}\\\\item
53
+ \\\\begin{tabular*}{0.97\\\\textwidth}[t]{l@{\\\\extracolsep{\\\\fill}}r}
54
+ \\\\textbf{#1} & #2 \\\\\\\\
55
+ \\\\textit{\\\\small#3} & \\\\textit{\\\\small #4} \\\\\\\\
56
+ \\\\end{tabular*}\\\\vspace{-7pt}
57
+ }
58
+
59
+ \\\\newcommand{\\\\resumeProjectHeading}[2]{
60
+ \\\\item
61
+ \\\\begin{tabular*}{0.97\\\\textwidth}{l@{\\\\extracolsep{\\\\fill}}r}
62
+ \\\\small#1 & #2 \\\\\\\\
63
+ \\\\end{tabular*}\\\\vspace{-7pt}
64
+ }
65
+
66
+ \\\\newcommand{\\\\resumeSubItem}[1]{\\\\resumeItem{#1}\\\\vspace{-4pt}}
67
+ \\\\renewcommand\\\\labelitemii{$\\\\vcenter{\\\\hbox{\\\\tiny$\\\\bullet$}}$}
68
+ \\\\newcommand{\\\\resumeSubHeadingListStart}{\\\\begin{itemize}[leftmargin=0.15in, label={}]}
69
+ \\\\newcommand{\\\\resumeSubHeadingListEnd}{\\\\end{itemize}}
70
+ \\\\newcommand{\\\\resumeItemListStart}{\\\\begin{itemize}}
71
+ \\\\newcommand{\\\\resumeItemListEnd}{\\\\end{itemize}\\\\vspace{-5pt}}
72
+
73
+ \\\\begin{document}
74
+
75
+ %----------HEADING----------
76
+ \\\\begin{center}
77
+ \\\\textbf{\\\\Huge \\\\scshape {{CONTACT_NAME}}} \\\\\\\\ \\\\vspace{1pt}
78
+ \\\\small {{CONTACT_PHONE}} $|$ \\\\href{mailto:{{CONTACT_EMAIL}}}{\\\\underline{{{CONTACT_EMAIL}}}} $|$
79
+ \\\\faLinkedin \\\\hspace{1pt} \\\\href{https://linkedin.com/in/{{CONTACT_LINKEDIN}}}{\\\\underline{{{CONTACT_LINKEDIN}}}} \\\\\\\\
80
+ \\\\small {{CONTACT_LOCATION}}
81
+ \\\\end{center}
82
+ \\\\vspace{-10pt}
83
+ \\\\begin{center}
84
+ \\\\small \\\\textit{{{SUMMARY}}}
85
+ \\\\end{center}
86
+
87
+ %-----------EDUCATION-----------
88
+ \\\\section{Education}
89
+ \\\\resumeSubHeadingListStart
90
+ {{EDUCATION_ENTRIES}}
91
+ \\\\resumeSubHeadingListEnd
92
+
93
+ %-----------EXPERIENCE-----------
94
+ \\\\section{Experience}
95
+ \\\\resumeSubHeadingListStart
96
+ {{EXPERIENCE_ENTRIES}}
97
+ \\\\resumeSubHeadingListEnd
98
+
99
+ %-----------PROJECTS-----------
100
+ \\\\section{Projects \\\\& Extracurriculars}
101
+ \\\\resumeSubHeadingListStart
102
+ {{PROJECT_ENTRIES}}
103
+ \\\\resumeSubHeadingListEnd
104
+
105
+ %-----------SKILLS-----------
106
+ \\\\section{Technical Skills}
107
+ \\\\begin{itemize}[leftmargin=0.15in, label={}]
108
+ \\\\small{\\\\item{
109
+ \\\\textbf{{{SKILLS_STACK_LABEL}}}{: {{SKILLS_STACK_VALUE}}} \\\\\\\\
110
+ \\\\textbf{{{SKILLS_DOMAIN_LABEL}}}{: {{SKILLS_DOMAIN_VALUE}}}
111
+ }}
112
+ \\\\end{itemize}
113
+
114
+ \\\\end{document}`;