fontana 0.0.1.placeholder → 0.0.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.irbrc +1 -0
- data/Guardfile +19 -0
- data/README +18 -0
- data/README.textile +9 -0
- data/fontana.gemspec +6 -2
- data/lib/fontana.rb +4 -2
- data/lib/fontana/converter.rb +16 -0
- data/lib/fontana/dragonfly.rb +7 -0
- data/lib/fontana/dragonfly/encoder.rb +15 -0
- data/lib/fontana/font.rb +85 -0
- data/lib/fontana/fontforge.rb +58 -0
- data/lib/fontana/fontforge/2otf.pe +2 -0
- data/lib/fontana/fontforge/2svg.pe +2 -0
- data/lib/fontana/fontforge/2ttf.pe +2 -0
- data/lib/fontana/fontforge/2woff.pe +2 -0
- data/lib/fontana/fontforge/info.pe +25 -0
- data/lib/fontana/fontforge/scripting.txt +8 -0
- data/lib/fontana/rails.rb +45 -0
- data/lib/fontana/ttf2eot.rb +34 -0
- data/lib/fontana/version.rb +1 -1
- data/spec/dragonfly/encoder_spec.rb +16 -0
- data/spec/fontana_spec.rb +96 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.eot +0 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.otf +0 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.pdf +0 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.sfd +230942 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.svg +4923 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.ttf +0 -0
- data/spec/support/fonts/Consola Mono/ConsolaMono.woff +0 -0
- data/spec/support/fonts/Consola Mono/FONTLOG.txt +107 -0
- data/spec/support/fonts/Consola Mono/SIL - Open Font License.txt +105 -0
- data/vendor/ttf2eot-0.0.2-2.patched.tar.gz +0 -0
- metadata +70 -7
data/.irbrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
puts "Loading the irb rc file from the current directory"
|
data/Guardfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
# Capybara request specs
|
17
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
18
|
+
end
|
19
|
+
|
data/README
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
Fontana is a wrapper around several command line utilities for converting fonts to different formats.
|
2
|
+
|
3
|
+
Install the required command line utilites if they do not alreay exist on your system.
|
4
|
+
|
5
|
+
brew install ttf2eot
|
6
|
+
brew install fontforge
|
7
|
+
|
8
|
+
On Ubuntu the install is not so bad.
|
9
|
+
|
10
|
+
sudo apt-get install fontforge
|
11
|
+
|
12
|
+
wget https://raw.github.com/mdeering/fontana/master/vendor/ttf2eot-0.0.2-2.patched.tar.gz
|
13
|
+
tar xvfz ttf2eot-0.0.2-2.patched.tar.gz
|
14
|
+
cd ttf2eot-0.0.2-2
|
15
|
+
make
|
16
|
+
sudo cp ttf2eot /usr/bin/.
|
17
|
+
|
18
|
+
Much of the wrapper is based on the scripts found here https://github.com/zoltan-dulac/css3FontConverter
|
data/README.textile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Fontana is a wrapper around several command line utilities for converting fonts to different formats.
|
2
|
+
|
3
|
+
Install the required command line utilites if they do not alreay exist on your system.
|
4
|
+
|
5
|
+
brew update
|
6
|
+
brew install ttf2eot
|
7
|
+
brew install fontforge
|
8
|
+
|
9
|
+
Much of the wrapper is based on the scripts found here https://github.com/zoltan-dulac/css3FontConverter
|
data/fontana.gemspec
CHANGED
@@ -14,10 +14,14 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.rubyforge_project = "fontana"
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files -- {
|
17
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
+
s.add_development_dependency 'guard'
|
22
|
+
s.add_development_dependency 'guard-rspec'
|
21
23
|
s.add_development_dependency 'rspec'
|
22
|
-
s.
|
24
|
+
s.add_development_dependency 'yard'
|
25
|
+
s.add_development_dependency 'dragonfly'
|
26
|
+
|
23
27
|
end
|
data/lib/fontana.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Fontana
|
2
|
+
|
3
|
+
module Converter
|
4
|
+
|
5
|
+
# Converts the font file into the new desired format
|
6
|
+
#
|
7
|
+
# @param [Tempfile] file a font file of one of the acceptd font formats
|
8
|
+
# @param [Symbol] format a symbol respresenting the expected font format you would like returned
|
9
|
+
# @return [Tempfile] a temperary file handle to a font in the format that was requested
|
10
|
+
def convert(file, format)
|
11
|
+
file
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/lib/fontana/font.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
module Fontana
|
2
|
+
|
3
|
+
class Font
|
4
|
+
|
5
|
+
def initialize(original_font_path)
|
6
|
+
raise Errno::ENOENT.new("No such file #{original_font_path}") unless File.file?(original_font_path)
|
7
|
+
|
8
|
+
@original_font_path = original_font_path
|
9
|
+
@original_font_type = File.extname(@original_font_path)
|
10
|
+
File.open(@original_font_path) { |file| @original_font_file_contents = file.read }
|
11
|
+
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_eot
|
16
|
+
return @eot_string unless @eot_string.nil?
|
17
|
+
|
18
|
+
case @original_font_type
|
19
|
+
when '.eot'
|
20
|
+
@eot_string = @original_font_file_contents
|
21
|
+
when '.ttf'
|
22
|
+
@eot_string = TTF2EOT.convert(@original_font_file_contents)
|
23
|
+
else
|
24
|
+
@eot_string = TTF2EOT.convert(to_ttf)
|
25
|
+
end
|
26
|
+
|
27
|
+
@eot_string
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_otf
|
31
|
+
return @otf_string unless @otf_string.nil?
|
32
|
+
|
33
|
+
case @original_font_type
|
34
|
+
when '.otf'
|
35
|
+
@otf_string = @original_font_file_contents
|
36
|
+
else
|
37
|
+
@otf_string = Fontforge.convert(@original_font_type, @original_font_file_contents, '.otf')
|
38
|
+
end
|
39
|
+
|
40
|
+
@otf_string
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_svg
|
44
|
+
return @svg_string unless @svg_string.nil?
|
45
|
+
|
46
|
+
case @original_font_type
|
47
|
+
when '.svg'
|
48
|
+
@svg_string = @original_font_file_contents
|
49
|
+
else
|
50
|
+
@svg_string = Fontforge.convert(@original_font_type, @original_font_file_contents, '.svg')
|
51
|
+
end
|
52
|
+
|
53
|
+
@svg_string
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def to_ttf
|
58
|
+
return @ttf_string unless @ttf_string.nil?
|
59
|
+
|
60
|
+
case @original_font_type
|
61
|
+
when '.ttf'
|
62
|
+
@ttf_string = @original_font_file_contents
|
63
|
+
else
|
64
|
+
@ttf_string = Fontforge.convert(@original_font_type, @original_font_file_contents, '.ttf')
|
65
|
+
end
|
66
|
+
|
67
|
+
@ttf_string
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_woff
|
71
|
+
return @woff_string unless @woff_string.nil?
|
72
|
+
|
73
|
+
case @original_font_type
|
74
|
+
when '.woff'
|
75
|
+
@woff_string = @original_font_file_contents
|
76
|
+
else
|
77
|
+
@woff_string = Fontforge.convert(@original_font_type, @original_font_file_contents, '.woff')
|
78
|
+
end
|
79
|
+
|
80
|
+
@woff_string
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Fontana
|
4
|
+
|
5
|
+
class Fontforge
|
6
|
+
|
7
|
+
def self.convert(input_ext, input_string, output_ext)
|
8
|
+
input_file = create_input_file(input_ext, input_string)
|
9
|
+
output_file = setup_output_file output_ext
|
10
|
+
run_conversion_command(input_file, output_file, output_ext.split('.').last)
|
11
|
+
return_string = readback_output_file(output_file)
|
12
|
+
cleanup(input_file)
|
13
|
+
cleanup(output_file)
|
14
|
+
return_string
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.information(font_path)
|
18
|
+
run_information_command(font_path).strip
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def self.cleanup(tempfile)
|
25
|
+
tempfile.unlink
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.create_input_file(ext, content, filename = 'fontana-fontforge-input')
|
29
|
+
tempfile = Tempfile.new([filename, ext])
|
30
|
+
tempfile.binmode
|
31
|
+
tempfile.write content
|
32
|
+
tempfile.close
|
33
|
+
tempfile
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.setup_output_file(extension, filename = 'fontana-fontforge-output')
|
37
|
+
tempfile = Tempfile.new([filename, extension])
|
38
|
+
tempfile.close
|
39
|
+
tempfile
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.readback_output_file(output_file)
|
43
|
+
output = nil
|
44
|
+
File.open(output_file.path, 'rb') { |file| output = file.read }
|
45
|
+
output
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.run_conversion_command(input_file, output_file, ext)
|
49
|
+
puts "fontforge -script #{File.join(File.dirname(__FILE__), 'fontforge', "2#{ext}.pe")} #{input_file.path} #{output_file.path}"
|
50
|
+
puts `fontforge -script #{File.join(File.dirname(__FILE__), 'fontforge', "2#{ext}.pe")} #{input_file.path} #{output_file.path}`
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.run_information_command(input_file_path)
|
54
|
+
puts "fontforge -script #{File.join(File.dirname(__FILE__), 'fontforge', "info.pe")} '#{input_file_path}'"
|
55
|
+
`fontforge -script #{File.join(File.dirname(__FILE__), 'fontforge', "info.pe")} '#{input_file_path}'`
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Open($1)
|
2
|
+
Print($fullname, ' ', $weight)
|
3
|
+
#Print('firstfont')
|
4
|
+
#Print($firstfont)
|
5
|
+
#Print('curfont')
|
6
|
+
#Print($curfont)
|
7
|
+
#Print('fontname')
|
8
|
+
#Print($fontname)
|
9
|
+
#Print('familyname')
|
10
|
+
#Print($familyname)
|
11
|
+
#Print('fullname')
|
12
|
+
#Print($fullname)
|
13
|
+
#Print('weight')
|
14
|
+
#Print($weight)
|
15
|
+
#Print('copyright')
|
16
|
+
#Print($copyright)
|
17
|
+
#Print('filename')
|
18
|
+
#Print($filename)
|
19
|
+
#Print('fontversion')
|
20
|
+
#Print($fontversion)
|
21
|
+
#Print('iscid')
|
22
|
+
#Print($iscid)
|
23
|
+
#Print('mmcount')
|
24
|
+
#Print($mmcount)
|
25
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
http://fontforge.sourceforge.net/scripting-tutorial.html
|
2
|
+
|
3
|
+
STDIN
|
4
|
+
If you wish FontForge to read a script from stdin then you can use "-" as a "filename" for stdin. (If you build FontForge without X11 then fontforge will attempt to read a script file from stdin if none is given on the command line.)
|
5
|
+
|
6
|
+
STDOUT
|
7
|
+
FONTFORGE_VERBOSE
|
8
|
+
If you set the environment variable FONTFORGE_VERBOSE (it doesn't need a value, just needs to be set) then FontForge will print scripts to stdout as it executes them.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'dragonfly'
|
3
|
+
require 'fontana/dragonfly'
|
4
|
+
begin
|
5
|
+
require 'rack/cache'
|
6
|
+
rescue LoadError => e
|
7
|
+
puts "Couldn't find rack-cache - make sure you have it in your Gemfile:"
|
8
|
+
puts " gem 'rack-cache', :require => 'rack/cache'"
|
9
|
+
puts " or configure dragonfly manually instead of using 'fontana/rails/fonts'"
|
10
|
+
raise e
|
11
|
+
end
|
12
|
+
|
13
|
+
### The dragonfly app ###
|
14
|
+
app = Dragonfly[:fonts]
|
15
|
+
|
16
|
+
app.configure do |c|
|
17
|
+
c.encoder.register(Fontana::Dragonfly::Encoder)
|
18
|
+
c.register_mime_type(:eot, 'application/vnd.ms-fontobject')
|
19
|
+
c.register_mime_type(:otf, 'font/opentype')
|
20
|
+
c.register_mime_type(:svg, 'image/svg+xml')
|
21
|
+
c.register_mime_type(:ttf, 'font/ttf')
|
22
|
+
c.register_mime_type(:woff, 'application/x-font-woff')
|
23
|
+
c.url_format = '/media-fonts/:job/:basename.:format'
|
24
|
+
c.log = ::Rails.logger
|
25
|
+
c.datastore.root_path = ::Rails.root.join('public/system/dragonfly', ::Rails.env).to_s
|
26
|
+
c.datastore.server_root = ::Rails.root.join('public').to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
# app.configure_with(:rails)
|
30
|
+
|
31
|
+
### Extend active record ###
|
32
|
+
if defined?(ActiveRecord::Base)
|
33
|
+
app.define_macro(ActiveRecord::Base, :font_accessor)
|
34
|
+
end
|
35
|
+
|
36
|
+
### Insert the middleware ###
|
37
|
+
rack_cache_already_inserted = Rails.application.config.action_controller.perform_caching && Rails.application.config.action_dispatch.rack_cache
|
38
|
+
|
39
|
+
Rails.application.middleware.insert 0, Rack::Cache, {
|
40
|
+
:verbose => true,
|
41
|
+
:metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), # URI encoded in case of spaces
|
42
|
+
:entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
|
43
|
+
} unless rack_cache_already_inserted
|
44
|
+
|
45
|
+
Rails.application.middleware.insert_after Rack::Cache, Dragonfly::Middleware, :fonts
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Fontana
|
4
|
+
|
5
|
+
class TTF2EOT
|
6
|
+
|
7
|
+
def self.convert(input_string)
|
8
|
+
input_file = create_input_file(input_string)
|
9
|
+
return_string = run_command(input_file)
|
10
|
+
cleanup(input_file)
|
11
|
+
return_string
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def self.cleanup(tempfile)
|
18
|
+
tempfile.unlink
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.create_input_file(content, filename = 'fontana-ttf2eot-input')
|
22
|
+
tempfile = Tempfile.new([filename, '.ttf'])
|
23
|
+
tempfile.write content
|
24
|
+
tempfile.close
|
25
|
+
tempfile
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run_command(input_file)
|
29
|
+
puts "ttf2eot #{input_file.path}"
|
30
|
+
`ttf2eot #{input_file.path}`
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
data/lib/fontana/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fontana::Dragonfly::Encoder do
|
4
|
+
|
5
|
+
describe '#encode' do
|
6
|
+
|
7
|
+
it 'should do nothing if the font is already in the correct format' do
|
8
|
+
sample_ttf = font_assets('/Consola Mono/ConsolaMono.ttf')
|
9
|
+
temp_ttf = Dragonfly::TempObject.new(File.new(sample_ttf))
|
10
|
+
returned_ttf = Fontana::Dragonfly::Encoder.new.encode(temp_ttf, :ttf)
|
11
|
+
Digest::MD5.hexdigest(returned_ttf) == Digest::MD5.file( font_assets('/Consola Mono/ConsolaMono.ttf'))
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fontana::Font do
|
4
|
+
|
5
|
+
def eot_md5
|
6
|
+
@eot_md5 ||= Digest::MD5.file(font_assets('Consola Mono/ConsolaMono.eot'))
|
7
|
+
end
|
8
|
+
|
9
|
+
def otf_md5
|
10
|
+
@otf_md5 ||= Digest::MD5.file(font_assets('Consola Mono/ConsolaMono.otf'))
|
11
|
+
end
|
12
|
+
|
13
|
+
def svg_md5
|
14
|
+
@svg_md5 ||= Digest::MD5.file(font_assets('Consola Mono/ConsolaMono.svg'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def ttf_md5
|
18
|
+
@ttf_md5 ||= Digest::MD5.file(font_assets('Consola Mono/ConsolaMono.ttf'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def woff_md5
|
22
|
+
@woff_md5 ||= Digest::MD5.file(font_assets('Consola Mono/ConsolaMono.woff'))
|
23
|
+
end
|
24
|
+
|
25
|
+
context '#initialize' do
|
26
|
+
|
27
|
+
it 'should require the path to font file' do
|
28
|
+
lambda { Fontana::Font.new() }.should raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'will assume a string is a path to file and attempt to open it' do
|
32
|
+
lambda { Fontana::Font.new('/bad/file/path') }.should raise_error(Errno::ENOENT)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
pending 'font conversions' do
|
38
|
+
|
39
|
+
[ :eot, :otf, :svg, :ttf, :woff ].each do |file_extension|
|
40
|
+
|
41
|
+
context "with a #{file_extension} as an original font #to_eot" do
|
42
|
+
|
43
|
+
it 'will return a string representing the embedded open type font' do
|
44
|
+
font = Fontana::Font.new(font_assets("Consola Mono/ConsolaMono.#{file_extension}"))
|
45
|
+
Digest::MD5.hexdigest(font.to_eot).should == eot_md5.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with a #{file_extension} as an original font #to_otf" do
|
51
|
+
|
52
|
+
it 'will return a string representing the open type font' do
|
53
|
+
pending 'No utility found to convert from eot => otf' if file_extension == :eot
|
54
|
+
font = Fontana::Font.new(font_assets("Consola Mono/ConsolaMono.#{file_extension}"))
|
55
|
+
Digest::MD5.hexdigest(font.to_otf).should == otf_md5.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
context "with a #{file_extension} as an original font #to_svg" do
|
62
|
+
|
63
|
+
it 'will return a string representing the scalable vector graphic font' do
|
64
|
+
pending 'No utility found to convert from eot => svg' if file_extension == :eot
|
65
|
+
font = Fontana::Font.new(font_assets("Consola Mono/ConsolaMono.#{file_extension}"))
|
66
|
+
Digest::MD5.hexdigest(font.to_svg).should == svg_md5.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
context "with a #{file_extension} as an original font #to_ttf" do
|
73
|
+
|
74
|
+
it 'will return a string representing the true type font' do
|
75
|
+
pending 'No utility found to convert from eot => ttf' if file_extension == :eot
|
76
|
+
font = Fontana::Font.new(font_assets("Consola Mono/ConsolaMono.#{file_extension}"))
|
77
|
+
Digest::MD5.hexdigest(font.to_ttf).should == ttf_md5.to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
context "with a #{file_extension} as an original font #to_woff" do
|
83
|
+
|
84
|
+
it 'will return a string representing the web open font format font' do
|
85
|
+
pending 'No utility found to convert from eot => woff' if file_extension == :eot
|
86
|
+
font = Fontana::Font.new(font_assets("Consola Mono/ConsolaMono.#{file_extension}"))
|
87
|
+
Digest::MD5.hexdigest(font.to_woff).should == woff_md5.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|