Compare commits

...

5 commits

Author SHA1 Message Date
502749c838
V2 alpha release 2022-09-13 01:26:15 -07:00
7a20b7f86b
Updates 2022-06-03 00:11:54 -07:00
d91f655177
disabled projects section in latex 2021-09-28 22:01:32 -07:00
4fb22e2194
fixed changes 2021-09-28 22:01:17 -07:00
e06044fc97
update project 2021-09-28 22:01:01 -07:00
6 changed files with 664 additions and 642 deletions

948
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,13 +2,13 @@
name = "panres" name = "panres"
version = "0.1.0" version = "0.1.0"
authors = ["Edward Shen <code@eddie.sh>"] authors = ["Edward Shen <code@eddie.sh>"]
edition = "2018" edition = "2021"
[dependencies] [dependencies]
tera = "1.0.0-beta.13" tera = "1"
clap = "2" clap = { version = "3", features = ["derive", "cargo"] }
serde = "1" serde = "1"
serde_json = "1.0" serde_json = "1"
json5 = "0.2.8" json5 = "0.4"
notify = "5.0.0-pre.3" notify = "5.0.0-pre.15"
crossbeam = "0.7" crossbeam = "0.8"

View file

@ -2,10 +2,10 @@
"author": { "author": {
"name": "Edward Shen", "name": "Edward Shen",
"addresses": { "addresses": {
"home": "8080 Highland Farms Drive, East Amherst, NY 14051", "home": "550 Moreland Way Apt 4410, Santa Clara, CA 95054",
"school": "480 Parker Street, Boston, MA 02115" "school": "480 Parker Street, Boston, MA 02115"
}, },
"email": "code@eddie.sh", "email": "hi@eddie.sh",
"phone": "(716) 491-3343", "phone": "(716) 491-3343",
"website": "eddie.sh", "website": "eddie.sh",
"github": "edward-shen", "github": "edward-shen",
@ -19,22 +19,17 @@
"school": "Northeastern University", "school": "Northeastern University",
"college": "Khoury College of Computer Sciences", "college": "Khoury College of Computer Sciences",
"location": "Boston, MA", "location": "Boston, MA",
"start": "Sept. 2017", "start": "Sep. 2017",
"end": "Present", "end_date": "May 2021",
"end_date": "Present (May 2021)",
"list": [ "list": [
{ {
"name": "degree", "name": "degree",
"desc": "Candidate for a Bachelor of Science in Computer Science" "desc": "Bachelor of Science in Computer Science"
}, },
{ {
"name": "honors", "name": "honors",
"desc": "3.84 / 4.00, Dean's List" "desc": "3.85 / 4.00; summa cum laude; Dean's List"
}, },
{
"name": "courses",
"desc": "Data Collection, Integration, and Analysis; Machine Learning/Data Mining 1; Algorithms and Data; Object-Oriented Design; Networks and Distributed Systems"
}
] ]
}, },
"skills": [ "skills": [
@ -42,63 +37,82 @@
"name": "languages", "name": "languages",
"desc": [ "desc": [
{ {
"level": "proficient", "level": "primary",
"langs": "Rust, Python, TypeScript, HTML5, CSS" "langs": "Rust",
}, },
{ {
"level": "familiar", "level": "secondary",
"langs": "JavaScript, Java, LaTeX, C++, Bash" "langs": "Python, Bash",
}, },
{ {
"level": "explored", "level": "auxiliary",
"langs": "C, Ruby, Racket, Scala" "langs": "C, C++, TypeScript",
} }
] ]
}, },
{ {
"name": "other", "name": "recent technology",
"desc": "Git, (Arch) Linux, VS Code, Raspberry Pi" "desc": "cxx.rs, libc, fbthrift, cgroups v2",
}, },
{ {
"name": "certs", "name": "miscellaneous",
"desc": "CompTIA A+, Dell Certified Technician, Apple Certified Mac Technician" "desc": "Regex, LaTeX"
},
{
"name": "interests",
"desc": "Rhythm games; Self-hosting; Security; Scalability; Free software",
} }
], ],
"experiences": [ "experiences": [
// { {
// "title": "Software Development Engineer Intern", "title": "Production Engineer",
// "company": "Apple", "company": "Meta",
// "location": "Menlo Park, CA", "location": "Menlo Park, CA",
// "start": "Aug. 2020", "start": "Sep. 2021",
// "end": "Dec. 2020", "end": "Present",
// "notes": [ "notes": [
// "sekureetee" "Joined the PE Executable Access Control team to identify, track, and jail untrusted binaries running on internal hosts.",
// ] "Tech lead for Alcatraz, an internal binary that presents common frontend for process-level jailing backends.",
// }, "Advocate for Rust adoption, volunteering for Rust code reviews and presenting Rust talks to teams.",
]
},
{
"title": "SEAR Intern",
"company": "Apple",
"location": "Cupertino, CA",
"remote": true,
"start": "Aug. 2020",
"end": "Dec. 2020",
"notes": [
"Joined the Trusted Execution team, focused on code execution across the Apple ecosystem.",
"Planned, driven, and completed proof-of-concept for iOS 16's Lockdown Mode.",
"Developed kernel and bootloader security policies focused on attack surface reduction.",
]
},
{ {
"title": "Production Engineer Intern", "title": "Production Engineer Intern",
"company": "Facebook", "company": "Facebook",
"location": "Menlo Park, CA", "location": "Menlo Park, CA",
"remote": true,
"start": "May 2020", "start": "May 2020",
"end": "Aug. 2020", "end": "Aug. 2020",
"notes": [ "notes": [
"Rewritten Python config generation in multithreaded asynchronous Rust, reducing overall runtime by 80\\% on large inputs and improving runtime of profiled areas by a factor of 36.6.", "Rewritten Python config generation in multithreaded asynchronous Rust, reducing overall runtime by 80\\% on large inputs and improving runtime of profiled areas by a factor of 36.6.",
"Designed core Rust libraries for foundational services for ubiquitous use across all Rust applications.", "Designed core Rust libraries for foundational services for ubiquitous use across all Rust applications.",
"Detected and resolved soundness issues and misconfigurations in existing python code to preempt Severity 1 site events." "Highlighted as a top intern project for the Production Engineering organization."
]
},
{
"title": "Software Engineer Intern",
"company": "Datto",
"location": "Boston, MA",
"start": "Aug. 2019",
"end": "Dec. 2019",
"notes": [
"Refactored frontend codebase to utilize Typescript, Webpack, and Babel while reducing average JS footprint by 98\\% percent, from 10.4MB to 250KB.",
"Assisted and completed developer environment virtualization project to reduce onboarding time for new developers by 5 days.",
"Integrated into Scrum team that focused on re-implementation of license management systems in a legacy Ruby codebase to Scala and PHP."
] ]
}, },
// {
// "title": "Software Engineer Intern",
// "company": "Datto",
// "location": "Boston, MA",
// "start": "Aug. 2019",
// "end": "Dec. 2019",
// "notes": [
// "Refactored frontend codebase to utilize Typescript, Webpack, and Babel while reducing average JS footprint by 98\\% percent, from 10.4MB to 250KB.",
// "Integrated into Scrum team that focused on re-implementation of license management systems in a legacy Ruby codebase to Scala and PHP."
// ]
// },
{ {
"title": "Production Engineer Intern", "title": "Production Engineer Intern",
"company": "Facebook", "company": "Facebook",
@ -107,8 +121,7 @@
"end": "Aug. 2019", "end": "Aug. 2019",
"notes": [ "notes": [
"Implemented a disaster mitigation for decentralized service discovery when upstream data source is unavailable or in a degraded state.", "Implemented a disaster mitigation for decentralized service discovery when upstream data source is unavailable or in a degraded state.",
"Designed an out-of-band flow to allow resolution of core infrastructure services dependent on service discovery in disaster scenarios to minimize downtime for all Facebook products.", "Designed an out-of-band flow to resolve core infrastructure services dependent on service discovery in disaster scenarios to minimize downtime for all Facebook products.",
"Modernized and restructured core tooling to improve reliability and testing."
] ]
} }
], ],

View file

@ -1,13 +1,14 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use clap::{crate_authors, crate_version, App, AppSettings, Arg}; use clap::{crate_authors, crate_version, Parser};
use crossbeam::crossbeam_channel::unbounded; use crossbeam::channel::unbounded;
use json5::from_str; use json5::from_str;
use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use serde_json::Value; use serde_json::Value;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::fs::{create_dir_all, read_dir, read_to_string, write}; use std::fs::{create_dir_all, read_dir, read_to_string, write};
use std::path::{Path, PathBuf};
use std::process; use std::process;
use tera::{Context, Error as TeraError, Tera}; use tera::{Context, Error as TeraError, Tera};
@ -28,60 +29,51 @@ fn env_or_default(env_name: &str, default: &str) -> String {
env::var(env_name).unwrap_or_else(|_| String::from(default)) env::var(env_name).unwrap_or_else(|_| String::from(default))
} }
/// Universal resume formatter
#[derive(Parser)]
#[clap(version = crate_version!(), author = crate_authors!())]
struct Args {
/// Watch for changes
#[clap(short)]
watch: bool,
/// Specifies which output format you want
#[clap(short, long, multiple_occurrences = true)]
output: Vec<String>,
}
fn run() -> Result<(), Box<dyn Error>> { fn run() -> Result<(), Box<dyn Error>> {
let config: Value = from_str(&read_to_string("config.json5")?)?; let config: Value = from_str(&read_to_string("config.json5")?)?;
let template_dir = env_or_default("PANRES_TEMPLATE_DIR", DEFAULT_TEMPLATE_DIR); let template_dir = env_or_default("PANRES_TEMPLATE_DIR", DEFAULT_TEMPLATE_DIR);
let output_dir = env_or_default("PANRES_OUTPUT_DIR", DEFAULT_OUTPUT_DIR); let output_dir = env_or_default("PANRES_OUTPUT_DIR", DEFAULT_OUTPUT_DIR);
let matches = get_args(); let args = Args::parse();
let tera = Tera::new(&format!("{}/**/*", template_dir))?; let tera = Tera::new(&format!("{template_dir}/**/*"))?;
let mut context = Context::new(); let mut context = Context::new();
context.insert("config", &config); context.insert("config", &config);
let outputs: Vec<String> = matches let template_dir = PathBuf::from(template_dir);
.values_of("output-format")
.unwrap_or_default()
.map(String::from)
.collect();
output(&tera, &context, &output_dir, &outputs, &template_dir)?; output(&tera, &context, &output_dir, &args.output, &template_dir)?;
if matches.is_present("watch") { if args.watch {
watch_mode(tera, context, output_dir, outputs, template_dir)?; watch_mode(tera, context, output_dir, args.output, &template_dir)?;
} }
Ok(()) Ok(())
} }
/// Returns the args passed by the user.
fn get_args() -> clap::ArgMatches<'static> {
App::new("panres")
.version(crate_version!())
.author(crate_authors!())
.about("Universal resume formatter")
.arg(Arg::with_name("watch").short("w").help("Watch for changes"))
.arg(
Arg::with_name("output-format")
.help("Specifies which output format you want")
.required(true)
.multiple(true),
)
.settings(&[AppSettings::ArgRequiredElseHelp])
.get_matches()
}
/// Usually never returns, unless there was an error initializing the watcher. /// Usually never returns, unless there was an error initializing the watcher.
/// Handles watching for file changes, and reloads tera if there's a change. /// Handles watching for file changes, and reloads tera if there's a change.
fn watch_mode<'a>( fn watch_mode(
mut engine: Tera, mut engine: Tera,
context: Context, context: Context,
dir: String, dir: String,
outputs: Vec<String>, outputs: Vec<String>,
template_dir: String, template_dir: &Path,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
let (tx, rx) = unbounded(); let (tx, rx) = unbounded();
let mut watcher: RecommendedWatcher = Watcher::new_immediate(move |res| tx.send(res).unwrap())?; let mut watcher: RecommendedWatcher = Watcher::new(move |res| tx.send(res).unwrap())?;
watcher.watch(&template_dir, RecursiveMode::Recursive)?; watcher.watch(template_dir, RecursiveMode::Recursive)?;
for res in rx { for res in rx {
match res { match res {
@ -89,7 +81,7 @@ fn watch_mode<'a>(
Ok(event) => { Ok(event) => {
println!("got event {:?}", event); println!("got event {:?}", event);
engine.full_reload().expect("Failed to perform full reload"); engine.full_reload().expect("Failed to perform full reload");
output(&engine, &context, &dir, &outputs, &template_dir) output(&engine, &context, &dir, &outputs, template_dir)
.expect("Failed to call output"); .expect("Failed to call output");
} }
} }
@ -100,12 +92,12 @@ fn watch_mode<'a>(
/// Parses the output values and generates a file for each format specified or /// Parses the output values and generates a file for each format specified or
/// found, if told to generate all outputs. /// found, if told to generate all outputs.
fn output<'a>( fn output(
engine: &Tera, engine: &Tera,
context: &Context, context: &Context,
dir: &str, dir: &str,
outputs: &[String], outputs: &[String],
template_dir: &'a str, template_dir: &Path,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
if outputs.contains(&String::from("all")) { if outputs.contains(&String::from("all")) {
for output in read_dir(template_dir)? { for output in read_dir(template_dir)? {

View file

@ -9,6 +9,7 @@
\usepackage{multirow} \usepackage{multirow}
\usepackage{colortbl} % Colored table vlines \usepackage{colortbl} % Colored table vlines
\usepackage{graphicx} % Rotate text \usepackage{graphicx} % Rotate text
\usepackage[hidelinks]{hyperref} % Clickable PDF URLs
% macros which are illegal in .sty (primarily just font awesome stuff) % macros which are illegal in .sty (primarily just font awesome stuff)
@ -22,93 +23,111 @@
\setmainfont{Corbert} \setmainfont{Corbert}
% Set up table styles % Set up table styles
\arrayrulecolor{red} \arrayrulecolor{AccentColor}
\setlength\arrayrulewidth{1.2pt} \setlength\arrayrulewidth{1.2pt}
\begin{tabularx}{\textwidth}{X c l} \begin{tabularx}{\textwidth}{X c l}
\multirow[b]{3}{*}{\name} \multirow[b]{3}{*}{\name}
& \accent{\glyph{"F0AC}} & {{ config.author.website }} \\ & \accent{\glyph{"F0AC}} & \href{
& \accent{\glyph{"F003}} & {{ config.author.email }} \\ https://{{ config.author.website }}
& \accent{\glyph{"F09B}} & {{ config.author.github }} }{
{{ config.author.website }}
}\\
& \accent{\glyph{"F003}} & \href{
mailto:{{ config.author.email }}
}{
{{ config.author.email }}
} \\
& \accent{\glyph{"F09B}} & \href {
https://github.com/{{ config.author.github }}
}{
{{ config.author.github }}
}
\end{tabularx} \end{tabularx}
% Contact info % Contact info
\begin{tabularx}{\textwidth}{ c | r X r } \begin{tabularx}{\textwidth}{c X c}
\sectiontitle{Education} \\[-8pt] {
{% raw -%}
& \widel{ {\large\title{%
{% endraw -%}
{{ config.education.school }}}}\hint{ {{ config.education.location }}}} & {{ config.education.start }}---{{ config.education.end_date }} \\
& \widel{\footnotesize {{ config.education.college }}} \\
{% for row in config.education.list -%}
{% raw -%}
& \hint{%
{% endraw -%}
{{ row.name | title }}:} &
{% raw -%}
\multicolumn{2}{X}{%
{% endraw -%}
{{ row.desc }}} \\
{% endfor -%}
\spacer \begin{tabularx}{300pt}{c | r r r }
\sectiontitle{Experiences\;\;}
{% for experience in config.experiences -%} \\[-8pt]
{% raw -%}
& \widel{\large\title{%
{% endraw -%}
{{ experience.company }}}\hint{ {{experience.title }} }} & {{ experience.start }}---{{ experience.end }} \\
& \widel{\footnotesize {{ experience.location }}
{% if experience.remote -%}
\color[rgb]{.8,.8,.8}{(Remote)}
{% endif -%}
} \\[-8pt]
\\
\sectiontitle{Skills} \\[-8pt] {% for note in experience.notes -%}
{% for row in config.skills -%} & \bullet
& \hint{ {{ row.name | title }}:} & {% raw -%}
{% raw -%} & \widex{%
\multicolumn{2}{X}{% {% endraw -%}
{% endraw -%} {{note}}
{% if row.name == "languages" -%} } \\[-8pt]
\multirow{3}{*}{ \\
\begin{tabularx}{\textwidth}{ r l } {% endfor -%}
{% for group in row.desc -%} \\[-8pt]
{% raw -%} {% endfor -%}
\hint{%
{% endraw -%}
{{ group.level | title }}:} & {{ group.langs }} \\
{% endfor -%}
\end{tabularx}
} \newline \newline % 100% hack pls fix
{% else -%}
{{ row.desc }}
{% endif -%}
}\\
{% endfor -%}
\end{tabularx} \end{tabularx}
}
& &
{
\begin{tabularx}{150pt}{ c | X }
\sectiontitle{Degree\;\;} \\[-8pt]
{% raw -%}
& {\large\title{%
{% endraw -%}
{{ config.education.school }}
}} \\
& \footnotesize{ {{ config.education.location }}} \\
& \hint{Date}\\
& {{ config.education.start }}---{{ config.education.end_date }} \\
{% for row in config.education.list -%}
{% raw -%}
& \hint{%
{% endraw -%}
{{ row.name | title }}} \\
& {{ row.desc }} \\
{% endfor -%}
\\[-8pt]
\\
\begin{tabularx}{\textwidth}{c | r X r } \spacer
\sectiontitle{Experiences} \spacer
{% for experience in config.experiences -%} \\[-8pt] \spacer
{% raw -%} \spacer
& \widel{\large\title{%
{% endraw -%}
{{ experience.company }}}\hint{ {{experience.title }} }} & {{ experience.start }}---{{ experience.end }} \\
& \widel{\footnotesize {{ experience.location }}} \\
{% for note in experience.notes -%}
& \bullet
{% raw -%}
& \widex{%
{% endraw -%}
{{note}}} \\
{% endfor -%}
{% endfor -%}
\end{tabularx}
\begin{tabularx}{\textwidth}{c | r X r } \sectiontitle{Skills and Interests\;\;} \\[-8pt]
\sectiontitle{Projects} {% for row in config.skills -%}
{% for project in config.projects -%} \\[-8pt]
{% raw -%} {% raw -%}
& \widel{\large\title{% & \title{%
{% endraw -%} {% endraw -%}
{{ project.name }}}\hint{ {{ project.lang }} }} \\ {{ row.name | title }}} \\
{% for note in project.notes -%}
& \bullet {% if row.name == "languages" -%}
{% raw -%} {% for group in row.desc -%}
& \widex{% {% raw -%}
{% endraw -%} & \hint{%
{{note}}} \\ {% endraw -%}
{% endfor -%} {{ group.level | title }}} \\
{% endfor -%} & {{ group.langs }} \\
{% endfor -%}
{% else -%}
& \begin{flushleft}
{{ row.desc }} \\
\end{flushleft}
{% endif -%}
\\[-8pt]
\\
{% endfor -%}
\end{tabularx}
}
\end{tabularx} \end{tabularx}
\end{document} \end{document}

View file

@ -8,9 +8,11 @@
] ]
\newfontfamily{\fa}{FontAwesome} \newfontfamily{\fa}{FontAwesome}
\definecolor{AccentColor}{HTML}{238de4}
{% raw %} {% raw %}
% Changes the color of any text inside to the accent color % Changes the color of any text inside to the accent color
\renewcommand{\accent}[1] {{\color{red}{#1}}} \renewcommand{\accent}[1] {{\color{AccentColor}{#1}}}
{% endraw %} {% endraw %}
{% raw %} {% raw %}