multiformat-cv2 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ea0b2f804d7fb2f5343f838661479add46a24a796fb87bff6ca464233bf9d88a
4
+ data.tar.gz: 469da0d9732299829d39f1837767cbf27eab1af019ea826a62d5d24139297f27
5
+ SHA512:
6
+ metadata.gz: 5ea427348ba5d91c7458e2edbdcb7a0e847cf5d57880ee35706726dee23321fda0d87e783057ab6c5960b11e5d4ced7bcb19dc18affe726ee4c15841f3b9ae8b
7
+ data.tar.gz: 9d4c3f21ca9cd0977eaa23cc88f290523f35aef2b1a6f172e9b996671d0da9960d7342c57d602418ea3c7c1c705f8ac98b66f33b27cb41810ddb831861248716
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2004-2019 David Heinemeier Hansson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # Multiformat CV
2
+
3
+ Multi-format CV generator from YAML files and ERB templates.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ $ gem install multiformat-cv
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Taking this repository's `sample` directory as a starting point, we can
14
+ generate the CV as follows:
15
+
16
+ ```bash
17
+ $ tree
18
+ .
19
+ ├── data
20
+ │   ├── contact.yml
21
+ │   ├── jobs.yml
22
+ │   └── personal.yml
23
+ └── onepager
24
+ ├── cv.css
25
+ └── cv.html.erb
26
+
27
+ 2 directories, 5 files
28
+ $ multiformatcv -d sample/data -s sample/onepager -o sample/onepager/cv.html
29
+ $ open sample/onepager/cv.html
30
+ ```
31
+
32
+ Which, after being printed from the browser, would look something like this:
33
+
34
+ ![Printed CV](sample/onepager/images/cv.png)
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "multiformatcv"
5
+ require "mercenary"
6
+
7
+ Mercenary.program(:multiformatcv) do |p|
8
+ p.version MultiformatCV::VERSION
9
+ p.description "Generate your CV in different formats"
10
+ p.syntax "multiformatcv <format> [-d './data'] [-t <directory>] [-o <file>]"
11
+
12
+ p.option "format", "-f FORMAT", "--format FORMAT", "Output format", String
13
+ p.option "data_dir", "-d DIR", "--data DIR", "YAML data files directory", String
14
+ p.option "templates", "-s DIR", "--templates DIR", "Templates directory, MUST contain cv.<format>.erb file", String
15
+ p.option "output", "-o FILE", "--outpu FILEt", "Output where to write result, defaults to STDOUT", String
16
+
17
+ p.action do |args, options|
18
+ MultiformatCV::generate(options)
19
+ end
20
+ end
@@ -0,0 +1,60 @@
1
+ require 'yaml'
2
+ require 'erubi'
3
+
4
+ module MultiformatCV
5
+
6
+ # YAML files that will be read from the specified directory
7
+ YML_FILES = %w( contact jobs personal )
8
+
9
+ # Parse yaml files located at data directory
10
+ #
11
+ # @param [Hash] opts Options to specify format and templates source
12
+ # @option opts [String] 'data_dir' Directory where the YAML files are located.
13
+ # @option opts [Symbol] 'format' One of [ :html, :tex ]
14
+ # @option opts [Symbol] 'output' Output file
15
+ # @option opts [String] 'templates' Directory where templates are located,
16
+ # expected template files are `cv.#{ format }.erb`
17
+ #
18
+ # @return [MultiformatCV::Resume] Resume with parsed data
19
+ # @see https://www.rubydoc.info/gems/erubi/1.8.0 Erubi documentation
20
+ # @see Erubi::Engine
21
+
22
+ def self.generate(opts = {})
23
+ opts['format'] ||= 'html'
24
+ opts['data_dir'] ||= 'data'
25
+ opts['templates'] ||= default_template_path
26
+ opts['output'] ||= nil
27
+
28
+ template = File.read("#{ opts['templates'] }/cv.#{ opts['format'] }.erb")
29
+ resume = Resume.new
30
+ yml = nil
31
+
32
+ YML_FILES.each do |f|
33
+ yml = YAML.load_file("#{ opts['data_dir'] }/#{ f }.yml")
34
+ if yml then
35
+ resume.send("add_#{ f }", yml[f])
36
+ end
37
+ end
38
+
39
+ resume.rendered = eval Erubi::Engine.new(template).src
40
+
41
+ if opts['output'] then
42
+ File.open(opts['output'], 'w') { |f| f.write(resume.rendered) }
43
+ end
44
+
45
+ resume
46
+ end
47
+
48
+ private
49
+
50
+ def self.default_template_path
51
+ File.expand_path('../../sample/onepager', __FILE__)
52
+ end
53
+ end
54
+
55
+ require 'multiformatcv/contact'
56
+ require 'multiformatcv/job'
57
+ require 'multiformatcv/personal'
58
+ require 'multiformatcv/project'
59
+ require 'multiformatcv/resume'
60
+ require 'multiformatcv/version'
@@ -0,0 +1,32 @@
1
+ class MultiformatCV::Contact
2
+ attr_accessor :name,
3
+ :title,
4
+ :phone,
5
+ :email
6
+
7
+ # Hash of links
8
+ #
9
+ # == Example:
10
+ # links = { github: 'https://www.github.com/john.doe/personal-dashboard' }
11
+ attr_accessor :links
12
+
13
+ # Create Contact instance
14
+ #
15
+ # == Example:
16
+ # contact = MultiformatCV::Contact.new(title: 'Accountant', name: 'John Doe')
17
+ #
18
+ # @param [Hash] h Instance initializer; keys *MUST* be strings
19
+ # @option h [String] 'name'
20
+ # @option h [String] 'title'
21
+ # @option h [String] 'email'
22
+ # @option h [String] 'phone'
23
+ # @option h [Hash<String, String>] 'links'
24
+
25
+ def initialize(h = {})
26
+ @name = h['name']
27
+ @title = h['title']
28
+ @email = h['email']
29
+ @phone = h['phone']
30
+ @links = h['links']
31
+ end
32
+ end
@@ -0,0 +1,42 @@
1
+ class MultiformatCV::Job
2
+ attr_accessor :position,
3
+ :company,
4
+ :start_date,
5
+ :end_date,
6
+ :summary
7
+
8
+ # List of projects that you worked on during this job
9
+ # @return [Array<MultiformatCV::Project>]
10
+ attr_accessor :projects
11
+
12
+ # Create Job instance
13
+ #
14
+ # == Example:
15
+ # job = MultiformatCV::Job.new(position: 'Accountant', company: 'Accountants Inc.')
16
+ #
17
+ # @param [Hash] h Instance initializer; keys *MUST* be strings
18
+ # @option h [String] 'position'
19
+ # @option h [String] 'company'
20
+ # @option h [String] 'start_date'
21
+ # @option h [String] 'end_date'
22
+ # @option h [String] 'summary'
23
+ # @option h [Array<Hash>] 'projects' List of hashes that will be used to
24
+ # initialize new MultiformatCV::Porject entries
25
+ #
26
+ # @see MultiformatCV::Project
27
+
28
+ def initialize(h = {})
29
+ @position = h['position']
30
+ @company = h['company']
31
+ @start_date = h['start_date']
32
+ @end_date = h['end_date']
33
+ @summary = h['summary']
34
+ @projects = []
35
+
36
+ if h['projects']
37
+ h['projects'].each do |p|
38
+ @projects << MultiformatCV::Project.new(p)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ class MultiformatCV::Personal
2
+ attr_accessor :summary
3
+
4
+ # List of personal projects
5
+ # @return [Array<MultiformatCV::Project>]
6
+ attr_accessor :projects
7
+
8
+ # Create Personal information instance
9
+ #
10
+ # == Example:
11
+ # personal = MultiformatCV::Personal.new(summary: 'Volunteer at...', projects: [])
12
+ #
13
+ # @param [Hash] h Instance initializer; keys *MUST* be strings
14
+ # @option h [String] 'summary'
15
+ # @option h [Array<Hash>] 'projects' List of hashes that will be used to
16
+ # initialize new MultiformatCV::Porject entries
17
+ #
18
+ # @see MultiformatCV::Project
19
+
20
+ def initialize(h = {})
21
+ @summary = h['summary']
22
+ @projects = []
23
+
24
+ h['projects'].each { |p| @projects << MultiformatCV::Project.new(p) }
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ class MultiformatCV::Project
2
+ attr_accessor :name,
3
+ :position,
4
+ :summary,
5
+ :tasks,
6
+ :skills
7
+
8
+ # Repository URL for the project
9
+ attr_accessor :repo
10
+
11
+ # Page or site URL for the project
12
+ attr_accessor :url
13
+
14
+ # Create Project instance
15
+ #
16
+ # == Example:
17
+ # project = MultiformatCV::Project.new(name: 'Life Solver (TM)', summary: '...', ...)
18
+ #
19
+ # @param [Hash] h Instance initializer; keys *MUST* be strings
20
+ # @option h [String] 'name'
21
+ # @option h [String] 'position'
22
+ # @option h [String] 'start_date'
23
+ # @option h [String] 'end_date'
24
+ # @option h [String] 'repo' Repository URL
25
+ # @option h [String] 'url' URL for the project
26
+ # @option h [String] 'summary' Project description, goals, etc.
27
+ # @option h [Array<String>] 'tasks' Tasks done for the project
28
+ # @option h [Array<String>] 'skills' skills used in the project
29
+
30
+ def initialize(h = {})
31
+ @name = h['name']
32
+ @position = h['position']
33
+ @start_date = h['start_date']
34
+ @end_date = h['end_date']
35
+ @repo = h['repo']
36
+ @summary = h['summary']
37
+ @url = h['url']
38
+ @tasks = []
39
+ @skills = []
40
+
41
+ h['tasks'].each { |t| @tasks << t } if h['tasks']
42
+ h['skills'].each { |t| @skills << t } if h['skills']
43
+ end
44
+
45
+ # @return [DateTime] Date or nil
46
+ def end_date
47
+ if @end_date and @end_date != ''
48
+ return DateTime.parse(@end_date)
49
+ end
50
+ return nil
51
+ end
52
+
53
+ # @return [DateTime] Date or nil
54
+ def start_date
55
+ if @start_date and @start_date != ''
56
+ return DateTime.parse(@start_date)
57
+ end
58
+ return nil
59
+ end
60
+ end
@@ -0,0 +1,127 @@
1
+ require 'date'
2
+
3
+ class MultiformatCV::Resume
4
+ # Contact information
5
+ # @return [MultiformatCV::Contact]
6
+ attr_accessor :contact
7
+
8
+ # List of jobs
9
+ # @return [Array<MultiformatCV::Job>]
10
+ attr_accessor :jobs
11
+
12
+ # List of skills
13
+ # @key skill name
14
+ # @value time duration in months
15
+ # @return [Hash]
16
+ attr_accessor :skills
17
+
18
+ # Personal accomplishments and projects
19
+ # @return [MultiformatCV::Personal]
20
+ attr_accessor :personal
21
+
22
+ # Rendered templates with CV data
23
+ # @return [String]
24
+ attr_accessor :rendered
25
+
26
+ # Initialize Resume
27
+ #
28
+ # @param [Hash] h Options
29
+ # @option h [Array<MultiformatCV::Contact>] 'contact' Contact information
30
+ # @option h [Array<MultiformatCV::Job>] 'jobs' Jobs list
31
+ # @option h [Array<MultiformatCV::Personal>] 'personal' Personal information
32
+
33
+ def initialize(h = {})
34
+ @contact = MultiformatCV::Contact.new(h['contact'] || []) if h['contact']
35
+ @jobs = []
36
+ @skills = {}
37
+ @personal = MultiformatCV::Personal.new(h['personal'] || []) if h['personal']
38
+
39
+ h['jobs'].each { |j| @jobs << MultiformatCV::Job.new(j) } if h['jobs']
40
+
41
+ estimate_skills_experience_duration! if jobs.length > 0
42
+ end
43
+
44
+ # Set contact information
45
+ # @param [Hash] h Hash used to initialize new MultiformatCV::Contact
46
+ # @see MultiformatCV::Contact
47
+
48
+ def add_contact(h = {})
49
+ @contact = MultiformatCV::Contact.new(h)
50
+ end
51
+
52
+ # Add list of job entries to @jobs list
53
+ #
54
+ # @param [Array<Hash>] arr List of hashes that will be used to initialize new
55
+ # MultiformatCV::Job entries
56
+ #
57
+ # @see MultiformatCV::Job
58
+
59
+ def add_jobs(arr = [])
60
+ arr.each { |j| @jobs << MultiformatCV::Job.new(j) }
61
+ estimate_skills_experience_duration!
62
+ end
63
+
64
+ # Set personal information
65
+ # @param [Hash] h Hash used to initialize new MultiformatCV::Personal
66
+ # @see MultiformatCV::Personal
67
+
68
+ def add_personal(h = {})
69
+ @personal = MultiformatCV::Personal.new(h)
70
+ end
71
+
72
+ private
73
+
74
+ # A skill can be shared among projects, so we need to **NOT** count the
75
+ # same skill more than once if it appears in more than one.
76
+ #
77
+ # We do a naive calculation of _assuming_ if a skill has the same
78
+ # duration in more than one project, then we count it only once.
79
+ #
80
+ # **NOTE**: the way dates are parsed, if they don't specify the day,
81
+ # start of the month assumed; if they don't specify month, start of the
82
+ # year is assumed.
83
+ #
84
+ # For example, this approach will give approximate results when
85
+ # `skill1` was used from January 'til March in `project1` and from
86
+ # June 'til August in `project2`, giving a total of 4 months
87
+ # assuming dates are:
88
+ #
89
+ # * 2020-01-01 -> 2020-03-01: 2 months
90
+ # * 2020-06-01 -> 2020-08-01: 2 months
91
+
92
+ def estimate_skills_experience_duration!
93
+ jobs.each do |job|
94
+ job_skills = {}
95
+ default_start_date = job.start_date
96
+ default_end_date = job.end_date || Time.now # present/current job
97
+
98
+ job.projects.each do |proj|
99
+ start_date = proj.start_date || default_start_date
100
+ end_date = proj.end_date || default_end_date
101
+
102
+ proj.skills.each do |s|
103
+ job_skills[s] ||= []
104
+ job_skills[s] << diff_in_months(start_date.to_time, end_date.to_time)
105
+ end
106
+ end
107
+
108
+ # we assume that if the same skill has the same duration twice for the
109
+ # same job, the projects were developed in parallel so we count the skill
110
+ # only once
111
+ job_skills.each { |s, arr| job_skills[s] = arr.uniq.sum }
112
+ skills.merge!(job_skills) { |k, oldval, newval| oldval + newval }
113
+ end
114
+
115
+ skills
116
+ end
117
+
118
+ # Generic (30-day) month duration in seconds
119
+ ONE_MONTH = 3600 * 24 * 30
120
+
121
+ # @param [Time] t1
122
+ # @param [Time] t2
123
+ # @return [Integer] Difference in months between dates
124
+ def diff_in_months(t1, t2)
125
+ ((t1 - t2) / ONE_MONTH).abs.round
126
+ end
127
+ end
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
5
+ <title><%= "#{ resume.contact.name } - #{ resume.contact.title }" %></title>
6
+ <style>
7
+ html {
8
+ font: normal 16px/20px sans-serif, serif;
9
+ max-width: 90%;
10
+ margin: 2rem auto;
11
+ }
12
+ h1 { font-size: 1.6rem; line-height: 1.8rem; color: #000; }
13
+ h2 { font-size: 1.5rem; line-height: 1.7rem; color: #222; }
14
+ h3 { font-size: 1.4rem; line-height: 1.6rem; color: #444; }
15
+ h4 { font-size: 1.3rem; line-height: 1.5rem; color: #555; }
16
+ h5 { font-size: 1.2rem; line-height: 1.4rem; color: #666; }
17
+ h6 { font-size: 1.1rem; line-height: 1.3rem; color: #777; }
18
+ .text-right { text-align: right; }
19
+
20
+ .job {
21
+ border-bottom: 1px solid #666;
22
+ }
23
+ .project {}
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <header>
28
+ <h1><%= "#{ resume.contact.name } - #{ resume.contact.title }" %></h1>
29
+ <div class="text-right">
30
+ <a href="mailto:<%= resume.contact.email %>" class="email"><%= resume.contact.email %></a><br>
31
+ <a href="tel:<%= resume.contact.phone %>" class="phone"><%= resume.contact.phone %></a>
32
+ </div>
33
+ </header>
34
+
35
+ <section id="jobs">
36
+ <h2>Work Experience</h2>
37
+ <% resume.jobs.each do |job| %>
38
+ <article class="job">
39
+ <header>
40
+ <h3><%= "#{ job.position } &mdash; #{ job.company }" %></h3>
41
+ </header>
42
+ <p><%= job.summary.chomp %></p>
43
+ <% job.projects.each do |project| %>
44
+ <article class="project">
45
+ <h4><%= project.name %></h4>
46
+
47
+ <h5>Skills</h5>
48
+ <ul class="skills">
49
+ <% project.skills.each do |tech| %>
50
+ <li><%= tech %></li>
51
+ <% end %>
52
+ </ul>
53
+
54
+ <h5>Tasks</h5>
55
+ <ul class="tasks">
56
+ <% project.tasks.each do |task| %>
57
+ <li><%= task %></li>
58
+ <% end %>
59
+ </ul>
60
+ </article>
61
+ <% end %>
62
+ </article>
63
+ <% end %>
64
+ </section>
65
+ </body>
66
+ </html>
@@ -0,0 +1,66 @@
1
+ \documentclass{article}
2
+
3
+ \title{<%= resume.contact.name %>}
4
+ \author{<%= resume.contact.name %>}
5
+
6
+ \begin{document}
7
+
8
+ \maketitle
9
+
10
+ \section{\centerline{Proffesional Experience}}
11
+
12
+ \vspace{8pt}
13
+
14
+ <% resume.jobs.each do |job| %>
15
+
16
+ \subsection{<%= job.company %> -- <%= job.position %>}
17
+ \hfill <%= job.start_date %> -- <%= job.end_date or 'present' %>
18
+
19
+ <%- if job.summary %><%= job.summary %><% end -%>
20
+
21
+ <% job.projects.each do |project| %>
22
+ \subsubsection{<%= project.name %>}
23
+
24
+ <%- if project.summary %><%= project.summary %><% end -%>
25
+
26
+
27
+ \noindent Skills
28
+
29
+ \begin{itemize}
30
+ <% project.skills.each do |tech| %>
31
+ \item <%= tech %>
32
+ <% end %>
33
+ \end{itemize}
34
+
35
+ \noindent Tasks
36
+
37
+ \begin{itemize}
38
+ <% project.tasks.each do |task| %>
39
+ \item <%= task %>
40
+ <% end %>
41
+ \end{itemize}
42
+ <% end %>
43
+ <% end %>
44
+
45
+ \section{\centerline{Personal Projects}}
46
+
47
+ \vspace{8pt}
48
+
49
+ <%- if resume.personal and resume.personal.summary %>
50
+ <%= resume.personal.summary %>
51
+ <% end -%>
52
+
53
+ <% resume.personal.projects.each do |project| %>
54
+ \subsubsection{<%= project.name %>}
55
+
56
+ <%- if project.summary %><%= project.summary %><% end -%>
57
+
58
+ \noindent Skills
59
+
60
+ \begin{itemize}
61
+ <% project.skills.each do |tech| %>
62
+ \item <%= tech %>
63
+ <% end %>
64
+ \end{itemize}
65
+ <% end %>
66
+ \end{document}
@@ -0,0 +1,4 @@
1
+ module MultiformatCV
2
+ # Gem version
3
+ VERSION = '0.0.6'
4
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multiformat-cv2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - juankman94
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: erubi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mercenary
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.3
41
+ description: Multi-format CV generator from YAML files
42
+ email: juan.carlos@hey.com
43
+ executables:
44
+ - multiformatcv
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - bin/multiformatcv
51
+ - lib/multiformatcv.rb
52
+ - lib/multiformatcv/contact.rb
53
+ - lib/multiformatcv/job.rb
54
+ - lib/multiformatcv/personal.rb
55
+ - lib/multiformatcv/project.rb
56
+ - lib/multiformatcv/resume.rb
57
+ - lib/multiformatcv/templates/cv.html.erb
58
+ - lib/multiformatcv/templates/cv.tex.erb
59
+ - lib/multiformatcv/version.rb
60
+ homepage: https://www.gitlab.com/juankman94/multiformat-cv
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.1.2
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Generate your CV in different formats
83
+ test_files: []