json_resume 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +87 -0
- data/README.md +6 -1
- data/Rakefile +1 -1
- data/bin/json_resume +110 -82
- data/json_resume.gemspec +19 -20
- data/lib/json_resume.rb +2 -2
- data/lib/json_resume/formatter.rb +122 -125
- data/lib/json_resume/formatter_html.rb +9 -10
- data/lib/json_resume/formatter_latex.rb +13 -14
- data/lib/json_resume/formatter_md.rb +6 -7
- data/lib/json_resume/json_resume.rb +13 -13
- data/lib/json_resume/reader.rb +21 -19
- data/lib/json_resume/version.rb +1 -1
- data/locale/pt.yml +3 -3
- data/locale/zh_cn.yml +45 -0
- data/spec/json_resume/formatter_html_spec.rb +20 -20
- data/spec/json_resume/formatter_latex_spec.rb +7 -7
- data/spec/json_resume/formatter_spec.rb +19 -19
- data/spec/json_resume/reader_spec.rb +11 -11
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c2a37ce811da368c2df5af7af1e7e4088b34072
|
4
|
+
data.tar.gz: 39690709061e65e1183a938971689231a7662dc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f567a271f08691c337ae6141e4856107c84f30fbe98d2aecaebc9b05e0ddd0df21b5e4246179df9b0c7c67633e4e779b19b3d502c557430d8785566edb0708f
|
7
|
+
data.tar.gz: 262094ab199cc9c47d347e6dddef3e857b94719aa236cfc5ff11901602ed1e186067983957c5013d6f0ac1a485112f6c4fa5ca911b9c0ae49ac3f87b47f72492
|
data/.rubocop.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
+
# on 2014-12-29 14:04:27 +0530 using RuboCop version 0.28.0.
|
3
|
+
# The point is for the user to remove these configuration records
|
4
|
+
# one by one as the offenses are removed from the code base.
|
5
|
+
# Note that changes in the inspected code, or installation of new
|
6
|
+
# versions of RuboCop, may require this file to be generated again.
|
7
|
+
|
8
|
+
# Offense count: 8
|
9
|
+
Metrics/AbcSize:
|
10
|
+
Max: 22
|
11
|
+
|
12
|
+
# Offense count: 1
|
13
|
+
# Configuration parameters: CountComments.
|
14
|
+
Metrics/ClassLength:
|
15
|
+
Max: 253
|
16
|
+
|
17
|
+
# Offense count: 36
|
18
|
+
# Configuration parameters: AllowURI, URISchemes.
|
19
|
+
Metrics/LineLength:
|
20
|
+
Max: 213
|
21
|
+
|
22
|
+
# Offense count: 4
|
23
|
+
# Configuration parameters: CountComments.
|
24
|
+
Metrics/MethodLength:
|
25
|
+
Max: 30
|
26
|
+
|
27
|
+
# Offense count: 1
|
28
|
+
Style/AccessorMethodName:
|
29
|
+
Enabled: true
|
30
|
+
|
31
|
+
# Offense count: 1
|
32
|
+
# Cop supports --auto-correct.
|
33
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
34
|
+
Style/AndOr:
|
35
|
+
Enabled: true
|
36
|
+
|
37
|
+
# Offense count: 1
|
38
|
+
Style/ClassVars:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
# Offense count: 1
|
42
|
+
# Configuration parameters: Keywords.
|
43
|
+
Style/CommentAnnotation:
|
44
|
+
Enabled: true
|
45
|
+
|
46
|
+
# Offense count: 11
|
47
|
+
Style/Documentation:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
# Offense count: 1
|
51
|
+
Style/EachWithObject:
|
52
|
+
Enabled: true
|
53
|
+
|
54
|
+
# Offense count: 1
|
55
|
+
Style/EvenOdd:
|
56
|
+
Enabled: true
|
57
|
+
|
58
|
+
# Offense count: 1
|
59
|
+
# Configuration parameters: MinBodyLength.
|
60
|
+
Style/GuardClause:
|
61
|
+
Enabled: true
|
62
|
+
|
63
|
+
# Offense count: 1
|
64
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
65
|
+
Style/MethodName:
|
66
|
+
Enabled: true
|
67
|
+
|
68
|
+
# Offense count: 1
|
69
|
+
# Configuration parameters: NamePrefix, NamePrefixBlacklist.
|
70
|
+
Style/PredicateName:
|
71
|
+
Enabled: true
|
72
|
+
|
73
|
+
# Offense count: 1
|
74
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
75
|
+
Style/RaiseArgs:
|
76
|
+
Enabled: true
|
77
|
+
|
78
|
+
# Offense count: 2
|
79
|
+
# Configuration parameters: MaxSlashes.
|
80
|
+
Style/RegexpLiteral:
|
81
|
+
Enabled: true
|
82
|
+
|
83
|
+
# Offense count: 2
|
84
|
+
# Cop supports --auto-correct.
|
85
|
+
# Configuration parameters: AllowAsExpressionSeparator.
|
86
|
+
Style/Semicolon:
|
87
|
+
Enabled: true
|
data/README.md
CHANGED
@@ -16,6 +16,8 @@ A [sample](https://github.com/prat0318/json_resume/blob/master/examples/prateek_
|
|
16
16
|
|
17
17
|
Modify it as per the needs, and remove or keep rest of the fields empty.
|
18
18
|
|
19
|
+
Note: YAML files are also supported. Try `$ json_resume sample --in=yaml`.
|
20
|
+
|
19
21
|
### Conversion
|
20
22
|
|
21
23
|
* Syntax
|
@@ -23,12 +25,15 @@ Modify it as per the needs, and remove or keep rest of the fields empty.
|
|
23
25
|
```
|
24
26
|
json_resume convert [--template=/path/to/custom/template]
|
25
27
|
[--out=html|html_pdf|tex|tex_pdf|md]
|
26
|
-
[--locale=es|en|pt]
|
28
|
+
[--locale=es|en|pt|zh_cn]
|
29
|
+
[--dest_dir=/path/to/put/output/files]
|
27
30
|
[--theme=default|classic] <json_input>
|
28
31
|
|
29
32
|
<json_input> can be /path/to/json OR "{'json':'string'}" OR http://raw.json
|
30
33
|
```
|
31
34
|
|
35
|
+
NEW: YAML files are also supported. Pass path/to/yaml file (must have .yaml or .yml).
|
36
|
+
|
32
37
|
* Default (HTML) version
|
33
38
|
|
34
39
|
```
|
data/Rakefile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/json_resume
CHANGED
@@ -7,40 +7,52 @@ require_relative '../lib/json_resume'
|
|
7
7
|
require 'zlib'
|
8
8
|
require 'pdfkit'
|
9
9
|
require 'rest-client'
|
10
|
+
require 'json'
|
11
|
+
require 'yaml'
|
10
12
|
|
11
|
-
WL_URL =
|
13
|
+
WL_URL = 'https://www.overleaf.com/docs'
|
12
14
|
|
13
15
|
class String
|
14
|
-
|
15
|
-
|
16
|
+
def red
|
17
|
+
"\033[31m#{self}\033[0m"
|
18
|
+
end
|
19
|
+
|
20
|
+
def green
|
21
|
+
"\033[32m#{self}\033[0m"
|
22
|
+
end
|
16
23
|
end
|
17
24
|
|
18
25
|
class JsonResumeCLI < Thor
|
19
|
-
|
20
|
-
|
21
|
-
option :
|
22
|
-
option :
|
23
|
-
option :
|
24
|
-
option :
|
25
|
-
option :dest_dir, :default=>"current", :banner=>"dest_dir", :desc=>"location of dest. dir (optional)"
|
26
|
+
desc 'convert /path/to/json/file', 'converts the json to pretty resume format'
|
27
|
+
option :out, default: 'html', banner: 'output_type', desc: 'html|html_pdf|tex|tex_pdf|md'
|
28
|
+
option :template, banner: 'template_path', desc: 'path to customized template (optional)'
|
29
|
+
option :locale, default: 'en', banner: 'locale', desc: 'en|es|pt|zh_cn'
|
30
|
+
option :theme, default: 'default', banner: 'theme', desc: 'default|classic'
|
31
|
+
option :dest_dir, default: 'current', banner: 'dest_dir', desc: 'location of dest. dir (optional)'
|
26
32
|
def convert(json_input)
|
27
|
-
|
33
|
+
assign_i18n(options[:locale])
|
28
34
|
puts "Generating the #{options[:out]} type..."
|
29
|
-
dest = options[:dest_dir] == 'current'? Dir.pwd : options[:dest_dir]
|
35
|
+
dest = options[:dest_dir] == 'current' ? Dir.pwd : options[:dest_dir]
|
30
36
|
begin
|
31
|
-
puts send('convert_to_'+options[:out], json_input, get_template(options), dest)
|
37
|
+
puts send('convert_to_' + options[:out], json_input, get_template(options), dest)
|
32
38
|
rescue Encoding::InvalidByteSequenceError
|
33
39
|
puts "ERROR: You need to 'export LC_CTYPE=en_US.UTF-8' ...".green
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
37
|
-
desc
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
desc 'sample', 'Generates a sample json file in cwd'
|
44
|
+
option :in, default: 'json', banner: 'input_type', desc: 'json|yaml'
|
45
|
+
def sample
|
46
|
+
cwd = Dir.pwd
|
47
|
+
file_names = []
|
48
|
+
if options[:in] == 'yaml'
|
49
|
+
file_names = convert_sample_to_yaml
|
50
|
+
else
|
51
|
+
json_file_paths = Dir["#{@@orig_locn}/../examples/*.json"]
|
52
|
+
file_names = json_file_paths.map { |x| File.basename(x) }
|
53
|
+
FileUtils.cp json_file_paths, cwd
|
54
|
+
end
|
55
|
+
msg = "Generated #{file_names.join(' ')} in #{cwd}/".green
|
44
56
|
msg += "\nYou can now modify it and call: json_resume convert <file.json>"
|
45
57
|
puts msg
|
46
58
|
end
|
@@ -48,42 +60,54 @@ class JsonResumeCLI < Thor
|
|
48
60
|
no_commands do
|
49
61
|
@@orig_locn = File.expand_path(File.dirname(__FILE__))
|
50
62
|
|
63
|
+
def convert_sample_to_yaml
|
64
|
+
cwd = Dir.pwd
|
65
|
+
json_file_paths = Dir["#{@@orig_locn}/../examples/*.json"]
|
66
|
+
json_file_paths.map do |json_file_path|
|
67
|
+
dest = File.basename(json_file_path).gsub(/json$/, 'yaml')
|
68
|
+
yaml_string = (JSON.parse(File.read(json_file_path))).to_yaml
|
69
|
+
File.open("#{cwd}/#{dest}", 'w') { |f| f.write(yaml_string) }
|
70
|
+
dest
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
51
74
|
def get_template(options)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
75
|
+
return options[:template] if options[:template]
|
76
|
+
out_type = options[:out].split('_').first # html for both html, html_pdf
|
77
|
+
out_type = 'html' if out_type == 'pdf'
|
78
|
+
theme = options[:theme]
|
79
|
+
template_path = "#{@@orig_locn}/../templates/#{theme}_#{out_type}.mustache"
|
80
|
+
if !(File.exist? template_path) && theme != 'default'
|
81
|
+
puts "Theme #{theme} doesn't exist for #{options[:out]} type yet! Using default...".red
|
82
|
+
template_path = "#{@@orig_locn}/../templates/default_#{out_type}.mustache"
|
83
|
+
end
|
84
|
+
template_path
|
62
85
|
end
|
63
86
|
|
64
|
-
def convert_to_html(json_input, template, dest=Dir.pwd, dir_name='resume')
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
87
|
+
def convert_to_html(json_input, template, dest = Dir.pwd, dir_name = 'resume')
|
88
|
+
dest_dir = "#{dest}/#{dir_name}"
|
89
|
+
FileUtils.mkdir_p dest_dir
|
90
|
+
FileUtils.cp_r(Dir["#{@@orig_locn}/../extras/resume_html/*"], dest_dir)
|
91
|
+
msg = generate_file(json_input, template, 'html', "#{dest_dir}/page.html")
|
92
|
+
msg += "\nPlace #{dest_dir}/ in /var/www/ to host."
|
93
|
+
msg
|
70
94
|
end
|
71
95
|
|
72
|
-
def convert_to_pdf(json_input, template, dest=Dir.pwd)
|
96
|
+
def convert_to_pdf(json_input, template, dest = Dir.pwd)
|
73
97
|
puts "Defaulting to 'html_pdf'..."
|
74
98
|
convert_to_html_pdf(json_input, template, dest)
|
75
99
|
end
|
76
100
|
|
77
|
-
def convert_to_html_pdf(json_input, template, dest=Dir.pwd)
|
78
|
-
tmp_dir =
|
101
|
+
def convert_to_html_pdf(json_input, template, dest = Dir.pwd)
|
102
|
+
tmp_dir = '.tmp_resume'
|
79
103
|
convert_to_html(json_input, template, dest, tmp_dir)
|
80
104
|
PDFKit.configure do |config|
|
81
105
|
wkhtmltopdf_path = `which wkhtmltopdf`.to_s.strip
|
82
106
|
config.wkhtmltopdf = wkhtmltopdf_path unless wkhtmltopdf_path.empty?
|
83
107
|
config.default_options = {
|
84
|
-
:
|
85
|
-
:
|
86
|
-
:
|
108
|
+
footer_right: "Page [page] of [toPage] .\n",
|
109
|
+
footer_font_size: 10,
|
110
|
+
footer_font_name: 'Georgia'
|
87
111
|
}
|
88
112
|
end
|
89
113
|
html_file = File.new("#{dest}/#{tmp_dir}/core-page.html")
|
@@ -91,88 +115,92 @@ class JsonResumeCLI < Thor
|
|
91
115
|
File.open("#{dest}/#{tmp_dir}/public/css/mobile.css", 'w') {}
|
92
116
|
|
93
117
|
pdf_options = {
|
94
|
-
:
|
95
|
-
:
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
118
|
+
margin_top: 2.0,
|
119
|
+
margin_left: 0.0,
|
120
|
+
margin_right: 0.0,
|
121
|
+
margin_bottom: 4.0,
|
122
|
+
page_size: 'Letter'
|
99
123
|
}
|
100
124
|
kit = PDFKit.new(html_file, pdf_options)
|
101
125
|
|
102
126
|
begin
|
103
|
-
kit.to_file(dest+
|
127
|
+
kit.to_file(dest + '/resume.pdf')
|
104
128
|
rescue Errno::ENOENT => e
|
105
129
|
puts "\nTry: sudo apt-get update; sudo apt-get install libxtst6 libfontconfig1".green
|
106
130
|
raise e
|
107
131
|
end
|
108
132
|
FileUtils.rm_rf "#{dest}/#{tmp_dir}"
|
109
133
|
msg = "\nGenerated resume.pdf at #{dest}.".green
|
134
|
+
msg
|
110
135
|
end
|
111
136
|
|
112
|
-
def convert_to_tex(json_input, template, dest=Dir.pwd, filename=
|
113
|
-
generate_file(json_input, template,
|
137
|
+
def convert_to_tex(json_input, template, dest = Dir.pwd, filename = 'resume.tex')
|
138
|
+
generate_file(json_input, template, 'latex', "#{dest}/#{filename}")
|
114
139
|
end
|
115
140
|
|
116
|
-
def convert_to_tex_pdf(json_input, template, dest=Dir.pwd)
|
117
|
-
file1 =
|
141
|
+
def convert_to_tex_pdf(json_input, template, dest = Dir.pwd)
|
142
|
+
file1 = 'resume'
|
143
|
+
filename = "#{file1}.tex"
|
118
144
|
convert_to_tex(json_input, template, dest, filename)
|
119
|
-
if `which pdflatex` ==
|
120
|
-
puts
|
121
|
-
puts
|
122
|
-
puts
|
145
|
+
if `which pdflatex` == ''
|
146
|
+
puts 'It looks like pdflatex is not installed...'.red
|
147
|
+
puts 'Either install it with instructions at...'
|
148
|
+
puts 'http://dods.ipsl.jussieu.fr/fast/pdflatex_install.html'
|
123
149
|
return use_write_latex(dest, filename)
|
124
150
|
end
|
125
|
-
if `kpsewhich moderncv.cls` ==
|
126
|
-
puts
|
127
|
-
puts
|
151
|
+
if `kpsewhich moderncv.cls` == ''
|
152
|
+
puts 'It looks liks moderncv package for tex is not installed'.red
|
153
|
+
puts 'Read about it here: http://ctan.org/pkg/moderncv'
|
128
154
|
return use_write_latex(dest, filename)
|
129
155
|
end
|
130
156
|
system("pdflatex -shell-escape -interaction=nonstopmode #{dest}/#{filename}")
|
131
|
-
[
|
157
|
+
['.tex', '.out', '.aux', '.log'].each do |ext|
|
132
158
|
FileUtils.rm "#{dest}/#{file1}#{ext}"
|
133
159
|
end
|
134
160
|
msg = "\nPDF is ready at #{dest}/#{file1}.pdf"
|
161
|
+
msg
|
135
162
|
end
|
136
163
|
|
137
164
|
def use_write_latex(dest, filename)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
165
|
+
reply = ask 'Create PDF online using writeLatex/overleaf ([y]n)?'
|
166
|
+
if reply == '' || reply == 'y'
|
167
|
+
return convert_using_write_latex(dest, filename)
|
168
|
+
end
|
169
|
+
msg = "Latex file created at #{dest}/#{filename}".green
|
170
|
+
msg
|
143
171
|
end
|
144
172
|
|
145
|
-
def
|
173
|
+
def convert_using_write_latex(dest, filename)
|
146
174
|
tex_file = File.read("#{dest}/#{filename}")
|
147
|
-
|
175
|
+
msg = ''
|
176
|
+
RestClient.post(WL_URL, snip: tex_file, splash: 'none') do |response, _, _, &_|
|
148
177
|
FileUtils.rm "#{dest}/#{filename}"
|
149
178
|
msg = "\nPDF is ready at #{response.headers[:location]}".green
|
150
179
|
end
|
180
|
+
msg
|
151
181
|
end
|
152
182
|
|
153
|
-
def convert_to_md(json_input, template, dest=Dir.pwd)
|
154
|
-
generate_file(json_input, template,
|
183
|
+
def convert_to_md(json_input, template, dest = Dir.pwd)
|
184
|
+
generate_file(json_input, template, 'markdown', "#{dest}/resume.md")
|
155
185
|
end
|
156
186
|
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
end
|
187
|
+
def assign_i18n(locale)
|
188
|
+
I18n.load_path = Dir["#{@@orig_locn}/../locale/*.yml"]
|
189
|
+
I18n.enforce_available_locales = true
|
190
|
+
I18n.locale = locale.to_sym
|
191
|
+
end
|
162
192
|
|
163
|
-
def i18n(text)
|
164
|
-
|
165
|
-
end
|
193
|
+
def i18n(text)
|
194
|
+
text.gsub(/##(\w*?)##/) { I18n.t! Regexp.last_match[1], scope: 'headings' }
|
195
|
+
end
|
166
196
|
|
167
197
|
def generate_file(json_input, template, output_type, dest)
|
168
|
-
resume_obj = JsonResume.new(json_input,
|
198
|
+
resume_obj = JsonResume.new(json_input, 'output_type' => output_type)
|
169
199
|
mustache_obj = Mustache.render(i18n(File.read(template)), resume_obj.reader.hash)
|
170
|
-
File.open(dest,'w') {|f| f.write(mustache_obj) }
|
171
|
-
|
200
|
+
File.open(dest, 'w') { |f| f.write(mustache_obj) }
|
201
|
+
"\nGenerated files present at #{dest}".green
|
172
202
|
end
|
173
|
-
|
174
203
|
end
|
175
|
-
|
176
204
|
end
|
177
205
|
|
178
206
|
JsonResumeCLI.start(ARGV)
|
data/json_resume.gemspec
CHANGED
@@ -4,28 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'json_resume/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'json_resume'
|
8
8
|
spec.version = JsonResume::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
9
|
+
spec.authors = ['Prateek Agarwal']
|
10
|
+
spec.email = ['prat0318@gmail.com']
|
11
|
+
spec.description = 'json_resume creates pretty resume formats from a .json input file. Currently, it can convert to html, tex, markdown and pdf. Customizing the templates to your own needs is also super easy.'
|
12
|
+
spec.summary = 'Generates pretty resume formats out of json input file'
|
13
|
+
spec.homepage = 'http://github.com/prat0318/json_resume'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files`.split(
|
17
|
-
spec.executables = [
|
18
|
-
spec.test_files = spec.files.grep(
|
19
|
-
spec.require_paths = [
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
|
+
spec.executables = ['json_resume']
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)/)
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
23
|
-
|
24
|
-
spec.add_dependency "i18n"
|
25
|
-
spec.add_dependency "mustache"
|
26
|
-
spec.add_dependency "pdfkit"
|
27
|
-
spec.add_dependency "rest-client"
|
28
|
-
spec.add_dependency "thor"
|
29
|
-
spec.add_dependency "wkhtmltopdf-binary"
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
30
23
|
|
24
|
+
spec.add_dependency 'i18n'
|
25
|
+
spec.add_dependency 'mustache'
|
26
|
+
spec.add_dependency 'pdfkit'
|
27
|
+
spec.add_dependency 'rest-client'
|
28
|
+
spec.add_dependency 'thor'
|
29
|
+
spec.add_dependency 'wkhtmltopdf-binary'
|
31
30
|
end
|