fontcustom 1.0.1 → 1.1.0.pre
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/CHANGELOG.md +8 -0
- data/README.md +1 -1
- data/TODO.md +6 -0
- data/lib/fontcustom.rb +1 -1
- data/lib/fontcustom/actions.rb +28 -0
- data/lib/fontcustom/cli.rb +16 -15
- data/lib/fontcustom/generator/font.rb +31 -35
- data/lib/fontcustom/generator/template.rb +49 -34
- data/lib/fontcustom/options.rb +17 -11
- data/lib/fontcustom/scripts/generate.py +1 -1
- data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +4 -3
- data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +9 -14
- data/lib/fontcustom/templates/_fontcustom.scss +8 -14
- data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +3 -2
- data/lib/fontcustom/templates/fontcustom-bootstrap.css +9 -8
- data/lib/fontcustom/templates/fontcustom-preview.html +2 -3
- data/lib/fontcustom/templates/fontcustom.css +7 -7
- data/lib/fontcustom/templates/fontcustom.yml +25 -66
- data/lib/fontcustom/util.rb +108 -31
- data/lib/fontcustom/version.rb +1 -1
- data/lib/fontcustom/watcher.rb +24 -8
- data/spec/fixtures/{mixed-output → generators}/.fontcustom-data +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/another-font.ttf +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/dont-delete-me.bro +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom.css +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.eot +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.svg +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.ttf +0 -0
- data/spec/fixtures/{mixed-output → generators/mixed-output}/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.woff +0 -0
- data/spec/fixtures/{not-a-dir → shared/not-a-dir} +0 -0
- data/spec/fixtures/shared/templates/custom.css +1 -0
- data/spec/fixtures/shared/templates/regular.css +1 -0
- data/spec/fixtures/{empty → shared/vectors-empty}/no_vectors_here.txt +0 -0
- data/spec/fixtures/{vectors → shared/vectors}/C.svg +0 -0
- data/spec/fixtures/{vectors → shared/vectors}/D.svg +0 -0
- data/spec/fixtures/vectors/a_R3ally-eXotic f1Le Name.svg b/data/spec/fixtures/shared/vectors/a_R3ally-eXotic f1Le → Name.svg +0 -0
- data/spec/fixtures/util/config-is-in-dir/fontcustom.yml +1 -0
- data/spec/fixtures/util/fontcustom-malformed.yml +1 -0
- data/spec/fixtures/{fontcustom.yml → util/fontcustom.yml} +0 -0
- data/spec/fixtures/util/rails-like/config/fontcustom.yml +1 -0
- data/spec/fontcustom/actions_spec.rb +22 -0
- data/spec/fontcustom/generator/font_spec.rb +107 -62
- data/spec/fontcustom/generator/template_spec.rb +124 -29
- data/spec/fontcustom/util_spec.rb +299 -53
- data/spec/fontcustom/watcher_spec.rb +56 -10
- data/spec/spec_helper.rb +8 -3
- metadata +46 -34
- data/spec/fixtures/empty-data/.fontcustom-data +0 -0
@@ -1,20 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
else
|
5
|
-
@data[:file_name]
|
6
|
-
end
|
7
|
-
%>/*
|
8
|
-
* Font Custom: bare CSS
|
9
|
-
*/
|
1
|
+
//
|
2
|
+
// Icon Font: <%= @opts[:font_name] %>
|
3
|
+
//
|
10
4
|
|
11
5
|
@font-face {
|
12
6
|
font-family: "<%= @opts[:font_name] %>";
|
13
|
-
src: url("<%=
|
14
|
-
src: url("<%=
|
15
|
-
url("<%=
|
16
|
-
url("<%=
|
17
|
-
url("<%=
|
7
|
+
src: url("<%= @data[:paths][:preprocessor_to_fonts] %>.eot");
|
8
|
+
src: url("<%= @data[:paths][:preprocessor_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
|
9
|
+
url("<%= @data[:paths][:preprocessor_to_fonts] %>.woff") format("woff"),
|
10
|
+
url("<%= @data[:paths][:preprocessor_to_fonts] %>.ttf") format("truetype"),
|
11
|
+
url("<%= @data[:paths][:preprocessor_to_fonts] %>.svg#<%= @opts[:font_name] %>") format("svg");
|
18
12
|
font-weight: normal;
|
19
13
|
font-style: normal;
|
20
14
|
}
|
@@ -1,14 +1,15 @@
|
|
1
|
-
/*
|
2
|
-
|
3
|
-
|
1
|
+
/*
|
2
|
+
Icon Font: <%= @opts[:font_name] %>
|
3
|
+
Bootstrap Override
|
4
|
+
*/
|
4
5
|
|
5
6
|
@font-face {
|
6
7
|
font-family: "<%= @opts[:font_name] %>";
|
7
|
-
src: url("<%= @data[:
|
8
|
-
src: url("<%= @data[:
|
9
|
-
url("<%= @data[:
|
10
|
-
url("<%= @data[:
|
11
|
-
url("<%= @data[:
|
8
|
+
src: url("<%= @data[:paths][:css_to_fonts] %>.eot");
|
9
|
+
src: url("<%= @data[:paths][:css_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
|
10
|
+
url("<%= @data[:paths][:css_to_fonts] %>.woff") format("woff"),
|
11
|
+
url("<%= @data[:paths][:css_to_fonts] %>.ttf") format("truetype"),
|
12
|
+
url("<%= @data[:paths][:css_to_fonts] %>.svg#<%= @opts[:font_name] %>") format("svg");
|
12
13
|
font-weight: normal;
|
13
14
|
font-style: normal;
|
14
15
|
}
|
@@ -1,9 +1,8 @@
|
|
1
|
-
<% scale = %w|12 14 16 18 21 24 36 48 60 72|
|
2
|
-
<!DOCTYPE html>
|
1
|
+
<% scale = %w|12 14 16 18 21 24 36 48 60 72| %><!DOCTYPE html>
|
3
2
|
<html>
|
4
3
|
<head>
|
5
4
|
<title><%= @opts[:font_name] %> glyphs preview</title>
|
6
|
-
<link rel="stylesheet" href="
|
5
|
+
<link rel="stylesheet" href="<%= @data[:paths][:preview_to_css] %>" />
|
7
6
|
<!--[if lte IE 7]><link rel="stylesheet" href="fontcustom-ie7.css" /><![endif]-->
|
8
7
|
|
9
8
|
<style>
|
@@ -1,14 +1,14 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
|
2
|
+
Icon Font: <%= @opts[:font_name] %>
|
3
|
+
*/
|
4
4
|
|
5
5
|
@font-face {
|
6
6
|
font-family: "<%= @opts[:font_name] %>";
|
7
|
-
src: url("<%= @data[:
|
8
|
-
src: url("<%= @data[:
|
9
|
-
url("<%= @data[:
|
10
|
-
url("<%= @data[:
|
11
|
-
url("<%= @data[:
|
7
|
+
src: url("<%= @data[:paths][:css_to_fonts] %>.eot");
|
8
|
+
src: url("<%= @data[:paths][:css_to_fonts] %>.eot?#iefix") format("embedded-opentype"),
|
9
|
+
url("<%= @data[:paths][:css_to_fonts] %>.woff") format("woff"),
|
10
|
+
url("<%= @data[:paths][:css_to_fonts] %>.ttf") format("truetype"),
|
11
|
+
url("<%= @data[:paths][:css_to_fonts] %>.svg#<%= @opts[:font_name] %>") format("svg");
|
12
12
|
font-weight: normal;
|
13
13
|
font-style: normal;
|
14
14
|
}
|
@@ -1,80 +1,39 @@
|
|
1
|
-
##
|
2
|
-
# FONTCUSTOM CONFIG
|
3
|
-
#
|
4
|
-
# This file will automatically be loaded if located inside your vector dir.
|
5
|
-
# Otherwise, pass it to `compile` or `watch` with:
|
6
|
-
#
|
7
|
-
# --config=path/to/config.yml
|
8
|
-
# -c path/to/containing/dir/
|
9
|
-
##
|
10
|
-
|
11
1
|
# ---------------------------------------------------------------------------- #
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# default: INPUT/fontcustom
|
16
|
-
|
17
|
-
#output: path/to/output
|
18
|
-
|
2
|
+
# Project Info
|
3
|
+
# Learn more about these options with `fontcustom help`.
|
19
4
|
# ---------------------------------------------------------------------------- #
|
20
|
-
# Templates
|
21
|
-
# array of templates to generate alongside fonts
|
22
|
-
# accepts shortcuts or paths (absolute, relative to INPUT, or relative to `pwd`)
|
23
|
-
#
|
24
|
-
# shortcuts:
|
25
|
-
# preview
|
26
|
-
# css, scss
|
27
|
-
# bootstrap, bootstrap-scss
|
28
|
-
# bootstrap-ie7, bootstrap-ie7-scss
|
29
|
-
#
|
30
|
-
# default: [ css, preview ]
|
31
5
|
|
32
|
-
#
|
6
|
+
#font_name: My Custom Font
|
7
|
+
#file_hash: false
|
8
|
+
#css_prefix: glyph-
|
9
|
+
#preprocessor_font_path: fonts/fontcustom
|
10
|
+
#debug: true
|
11
|
+
#verbose: false
|
33
12
|
|
34
|
-
# ---------------------------------------------------------------------------- #
|
35
|
-
# Font Name
|
36
|
-
# automatically normalized to lower-spinal-case
|
37
|
-
#
|
38
|
-
# default: fontcustom
|
39
13
|
|
40
|
-
#font_name: my-font
|
41
|
-
|
42
14
|
# ---------------------------------------------------------------------------- #
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
|
48
|
-
#file_hash: false
|
49
|
-
|
15
|
+
# Project Directories
|
16
|
+
# All paths are relative to PROJECT_ROOT (default: working directory).
|
17
|
+
# When assigned a hash, individual components can have their own paths.
|
18
|
+
# When assigned a string, all components share the same path.
|
50
19
|
# ---------------------------------------------------------------------------- #
|
51
|
-
# CSS Class Prefix
|
52
|
-
#
|
53
|
-
# default: icon-
|
54
20
|
|
55
|
-
|
21
|
+
#input:
|
22
|
+
# vectors: app/assets/fontcustom/vectors
|
23
|
+
# templates: app/assets/fontcustom/templates
|
56
24
|
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
# default: none
|
25
|
+
#output:
|
26
|
+
# fonts: app/assets/fonts
|
27
|
+
# css: app/assets/stylesheets
|
28
|
+
# preview: app/views/styleguide
|
63
29
|
|
64
|
-
#font_face_path: assets/fonts/fontcustom
|
65
30
|
|
66
31
|
# ---------------------------------------------------------------------------- #
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
|
72
|
-
#debug: true
|
73
|
-
|
32
|
+
# Templates
|
33
|
+
# Shortcuts:
|
34
|
+
# preview, css, scss, bootstrap, bootstrap-scss, bootstrap-ie7,
|
35
|
+
# bootstrap-ie7-scss
|
36
|
+
# Custom templates should be saved in the INPUT[:templates] directory.
|
74
37
|
# ---------------------------------------------------------------------------- #
|
75
|
-
# Verbose
|
76
|
-
# print out all file operations
|
77
|
-
#
|
78
|
-
# default: true
|
79
38
|
|
80
|
-
#
|
39
|
+
#templates: [ scss, preview, my-custom-template.yml ]
|
data/lib/fontcustom/util.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require "yaml"
|
2
|
+
require "thor/core_ext/hash_with_indifferent_access"
|
2
3
|
|
3
4
|
module Fontcustom
|
4
5
|
class Util
|
5
|
-
class << self
|
6
|
+
class << self
|
6
7
|
def check_fontforge
|
7
8
|
fontforge = `which fontforge`
|
8
9
|
if fontforge == "" || fontforge == "fontforge not found"
|
@@ -14,38 +15,120 @@ module Fontcustom
|
|
14
15
|
# Priority: Passed args > config file > default
|
15
16
|
def collect_options(args = {})
|
16
17
|
options = Fontcustom::DEFAULT_OPTIONS.clone
|
17
|
-
|
18
|
+
options[:project_root] = args[:project_root] if args[:project_root]
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
args.delete
|
20
|
+
# Parse fontcustom.yml if it exists
|
21
|
+
# Deletes :config so that it can't overwrite the output of .get_config_path
|
22
|
+
options[:config] = args.delete(:config) if args[:config]
|
22
23
|
options[:config] = get_config_path options
|
23
24
|
|
24
25
|
if options[:config]
|
25
|
-
|
26
|
-
|
27
|
-
config = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
26
|
+
begin
|
27
|
+
config = YAML.load File.open(options[:config])
|
28
28
|
options.merge! config
|
29
|
+
rescue
|
30
|
+
raise Fontcustom::Error, "I couldn't read your configuration file. Please check #{options[:config]} and try again."
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
34
|
+
# Override with passed arguments
|
35
|
+
args.delete(:input) unless args[:input] # allows nil input from CLI
|
32
36
|
options.merge! args
|
33
|
-
options[:
|
34
|
-
|
35
|
-
options[:
|
37
|
+
options[:font_name] = options[:font_name].strip.gsub(/\W/, '-')
|
38
|
+
|
39
|
+
options[:input] = get_input_paths options
|
40
|
+
options[:output] = get_output_paths options
|
41
|
+
options[:templates] = get_templates options
|
36
42
|
options
|
37
43
|
end
|
38
44
|
|
39
|
-
# passed path > input
|
40
45
|
def get_config_path(options)
|
41
|
-
if options[:config]
|
42
|
-
File.join options[:config]
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
46
|
+
if options[:config]
|
47
|
+
config = File.expand_path File.join(options[:project_root], options[:config])
|
48
|
+
|
49
|
+
# :config is the path to fontcustom.yml
|
50
|
+
if File.exists?(config) && ! File.directory?(config)
|
51
|
+
config
|
52
|
+
|
53
|
+
# :config is a dir containing fontcustom.yml
|
54
|
+
elsif File.exists? File.join(config, "fontcustom.yml")
|
55
|
+
File.join config, "fontcustom.yml"
|
56
|
+
|
57
|
+
else
|
58
|
+
raise Fontcustom::Error, "I couldn't find your configuration file. Check #{config} and try again."
|
59
|
+
end
|
47
60
|
else
|
48
|
-
|
61
|
+
# fontcustom.yml is in the project_root
|
62
|
+
if File.exists? File.join(options[:project_root], "fontcustom.yml")
|
63
|
+
File.join options[:project_root], "fontcustom.yml"
|
64
|
+
|
65
|
+
# config/fontcustom.yml is in the project_root
|
66
|
+
elsif File.exists? File.join(options[:project_root], "config", "fontcustom.yml")
|
67
|
+
File.join options[:project_root], "config", "fontcustom.yml"
|
68
|
+
|
69
|
+
else
|
70
|
+
# TODO helpful warning that no config was found
|
71
|
+
false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_input_paths(options)
|
77
|
+
paths = if options[:input].is_a? Hash
|
78
|
+
input = Thor::CoreExt::HashWithIndifferentAccess.new options[:input]
|
79
|
+
raise Fontcustom::Error, "INPUT should be a string or a hash containing a \"vectors\" key." unless input[:vectors]
|
80
|
+
|
81
|
+
input[:vectors] = File.expand_path File.join(options[:project_root], input[:vectors])
|
82
|
+
raise Fontcustom::Error, "INPUT[\"vectors\"] should be a directory. Check #{input[:vectors]} and try again." unless File.directory? input[:vectors]
|
83
|
+
|
84
|
+
if input[:templates]
|
85
|
+
input[:templates] = File.expand_path File.join(options[:project_root], input[:templates])
|
86
|
+
raise Fontcustom::Error, "INPUT[\"templates\"] should be a directory. Check #{input[:templates]} and try again." unless File.directory? input[:templates]
|
87
|
+
else
|
88
|
+
input[:templates] = input[:vectors]
|
89
|
+
end
|
90
|
+
input
|
91
|
+
elsif options[:input].is_a? String
|
92
|
+
input = File.join options[:project_root], options[:input]
|
93
|
+
raise Fontcustom::Error, "INPUT should be a directory. Check #{input} and try again." unless File.directory? input
|
94
|
+
Thor::CoreExt::HashWithIndifferentAccess.new({
|
95
|
+
:vectors => input,
|
96
|
+
:templates => input
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
if Dir[File.join(paths[:vectors], "*.{svg,eps}")].empty?
|
101
|
+
raise Fontcustom::Error, "#{paths[:vectors]} doesn't contain any vectors (*.svg or *.eps files)."
|
102
|
+
end
|
103
|
+
|
104
|
+
paths
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_output_paths(options)
|
108
|
+
if options[:output].is_a? Hash
|
109
|
+
output = Thor::CoreExt::HashWithIndifferentAccess.new options[:output]
|
110
|
+
raise Fontcustom::Error, "OUTPUT should be a string or a hash containing a \"fonts\" key." unless output[:fonts]
|
111
|
+
|
112
|
+
output.each do |key, val|
|
113
|
+
output[key] = File.expand_path File.join(options[:project_root], val)
|
114
|
+
end
|
115
|
+
|
116
|
+
output[:css] ||= output[:fonts]
|
117
|
+
output[:preview] ||= output[:fonts]
|
118
|
+
output
|
119
|
+
else
|
120
|
+
if options[:output].is_a? String
|
121
|
+
output = File.expand_path File.join(options[:project_root], options[:output])
|
122
|
+
raise Fontcustom::Error, "OUTPUT should be a directory, not a file. Check #{output} and try again." if File.exists?(output) && ! File.directory?(output)
|
123
|
+
else
|
124
|
+
# TODO friendly warning that we're defaulting to pwd/:font_name
|
125
|
+
output = File.join options[:project_root], options[:font_name]
|
126
|
+
end
|
127
|
+
Thor::CoreExt::HashWithIndifferentAccess.new({
|
128
|
+
:fonts => output,
|
129
|
+
:css => output,
|
130
|
+
:preview => output
|
131
|
+
})
|
49
132
|
end
|
50
133
|
end
|
51
134
|
|
@@ -54,8 +137,10 @@ module Fontcustom
|
|
54
137
|
#
|
55
138
|
# Could arguably belong in Generator::Template, however, it's nice to
|
56
139
|
# be able to catch template errors before any generator runs.
|
57
|
-
def
|
140
|
+
def get_templates(options)
|
141
|
+
# ensure that preview has plain stylesheet to reference
|
58
142
|
options[:templates] << "css" if options[:templates].include?("preview") && ! options[:templates].include?("css")
|
143
|
+
|
59
144
|
options[:templates].map do |template|
|
60
145
|
case template
|
61
146
|
when "preview"
|
@@ -73,21 +158,13 @@ module Fontcustom
|
|
73
158
|
when "bootstrap-ie7-scss"
|
74
159
|
File.join gem_lib_path, "templates", "_fontcustom-bootstrap-ie7.scss"
|
75
160
|
else
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
File.join options[:input], template
|
80
|
-
else
|
81
|
-
raise Fontcustom::Error, "We couldn't find your custom template #{template}. Double check and try again?"
|
82
|
-
end
|
161
|
+
path = File.join options[:input][:templates], template
|
162
|
+
raise Fontcustom::Error, "We couldn't find your custom template at #{path}. Double check and try again?" unless File.exists? path
|
163
|
+
path
|
83
164
|
end
|
84
165
|
end
|
85
166
|
end
|
86
167
|
|
87
|
-
def clear_file(file)
|
88
|
-
File.open(file, "w") {}
|
89
|
-
end
|
90
|
-
|
91
168
|
def gem_lib_path
|
92
169
|
File.expand_path(File.join(File.dirname(__FILE__)))
|
93
170
|
end
|
data/lib/fontcustom/version.rb
CHANGED
data/lib/fontcustom/watcher.rb
CHANGED
@@ -5,34 +5,50 @@ module Fontcustom
|
|
5
5
|
class Watcher
|
6
6
|
def initialize(opts)
|
7
7
|
@opts = opts
|
8
|
-
@
|
8
|
+
@vector_listener = Listen.to(@opts[:input][:vectors]).relative_paths(true).filter(/\.(eps|svg)$/).change(&callback)
|
9
|
+
|
10
|
+
templates = @opts[:templates].dup
|
11
|
+
templates.delete_if do |template|
|
12
|
+
template.match Util.gem_lib_path
|
13
|
+
end
|
14
|
+
unless templates.empty?
|
15
|
+
templates = templates.map do |template|
|
16
|
+
File.basename template
|
17
|
+
end
|
18
|
+
@template_listener = Listen.to(@opts[:input][:templates]).relative_paths(true).filter(/(#{templates.join("|")})/).change(&callback)
|
19
|
+
end
|
20
|
+
|
9
21
|
@opts[:blocking] = @opts[:blocking] == false ? false : true
|
10
|
-
|
22
|
+
unless @opts[:blocking]
|
23
|
+
@vector_listener = @vector_listener.polling_fallback_message(false)
|
24
|
+
@template_listener = @template_listener.polling_fallback_message(false) if @template_listener
|
25
|
+
end
|
11
26
|
end
|
12
27
|
|
13
28
|
def watch
|
14
|
-
puts "Font Custom is watching your icons at #{@opts[:input]}. Press Ctrl + C to stop."
|
29
|
+
puts "Font Custom is watching your icons at #{@opts[:input][:vectors]}. Press Ctrl + C to stop."
|
15
30
|
compile unless @opts[:skip_first]
|
16
31
|
|
17
32
|
if @opts[:blocking]
|
18
|
-
@
|
33
|
+
@vector_listener.start!
|
34
|
+
@template_listener.start! if @template_listener
|
19
35
|
else
|
20
|
-
@
|
36
|
+
@vector_listener.start
|
37
|
+
@template_listener.start if @template_listener
|
21
38
|
end
|
22
39
|
|
23
40
|
rescue Fontcustom::Error => e
|
24
41
|
show_error e
|
25
42
|
|
26
43
|
# Catches Ctrl + C
|
27
|
-
# TODO Does the listen gem have a better way of handling this?
|
28
44
|
rescue SignalException
|
29
45
|
stop
|
30
46
|
end
|
31
47
|
|
32
48
|
def stop
|
33
|
-
|
49
|
+
@vector_listener.stop
|
50
|
+
@template_listener.stop if @template_listener
|
34
51
|
puts "\nFont Custom is signing off. Good night and good luck."
|
35
|
-
@listener.stop
|
36
52
|
end
|
37
53
|
|
38
54
|
private
|