cartocss_helper 1.2.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ require 'logger'
2
+
3
+ module Log
4
+ @@_logger_ = Logger.new(STDOUT)
5
+
6
+ def self.logger
7
+ @@_logger_
8
+ end
9
+
10
+ def self.info(message = '')
11
+ logger.info(message)
12
+ end
13
+
14
+ def self.warn(message = '')
15
+ logger.warn(message)
16
+ end
17
+
18
+ @@_logger_.formatter = proc do |_severity, _datetime, _progname, msg|
19
+ fileLine = ''
20
+ caller.each do |clr|
21
+ unless /\/logger.rb:/ =~ clr
22
+ fileLine = clr
23
+ break
24
+ end
25
+ end
26
+ fileLine = fileLine.split(':in `', 2)[0]
27
+ fileLine.sub!(/:(\d)/, '(\1')
28
+ "#{fileLine}) : #{msg}\n"
29
+ end
30
+ end
@@ -0,0 +1,53 @@
1
+ require 'rest-client'
2
+ require_relative 'generic_downloader.rb'
3
+
4
+ class RestClientWrapper
5
+ def initialize
6
+ @last_url_fetched = nil
7
+ end
8
+
9
+ def fetch_data_from_url(url, request_timeout)
10
+ wait if url == @last_url_fetched
11
+ @last_url_fetched = url
12
+ return execute_fetch_data_from_url(url, request_timeout)
13
+ # http://www.rubydoc.info/gems/rest-client/1.8.0/RestClient/Exception
14
+ rescue RestClient::RequestTimeout => e
15
+ raise RequestTimeout, e.to_s
16
+ rescue RestClient::ExceptionWithResponse => e
17
+ raise_exception_about_returned_response(e)
18
+ rescue RestClient::MaxRedirectsReached, RestClient::SSLCertificateNotVerified, RestClient::ServerBrokeConnection, SocketError, URI::InvalidURIError
19
+ raise ExceptionWithoutResponse.new(e), e.to_s
20
+ rescue ArgumentError => e
21
+ raise_issue_359_exception(e)
22
+ rescue => e
23
+ puts 'unhandled exception! It is a clear bug!'
24
+ puts "<#{e.class} error happened>"
25
+ raise e, e.to_s
26
+ end
27
+
28
+ def execute_fetch_data_from_url(url, request_timeout)
29
+ data = RestClient::Request.execute(method: :get, url: url, timeout: request_timeout)
30
+ # see https://github.com/rest-client/rest-client/issues/370, will be fixed in 2.0
31
+ # published versions listed on https://rubygems.org/gems/rest-client/versions/
32
+ return String.new(data)
33
+ end
34
+
35
+ def raise_issue_359_exception(e)
36
+ raise BuggyRestClient, "ArgumentError from rest-client, most likely caused by https://github.com/rest-client/rest-client/issues/359 (requesting GBs of data) [#{e}]"
37
+ end
38
+
39
+ def raise_exception_about_returned_response(e)
40
+ failure = ExceptionWithResponse.new(e)
41
+ failure.http_code = e.http_code
42
+ failure.response = e.response
43
+ raise failure, e.to_s
44
+ end
45
+
46
+ def wait
47
+ progressbar = ProgressBar.create
48
+ 100.times do
49
+ sleep 4
50
+ progressbar.increment
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,55 @@
1
+ class FailedCommandException < StandardError
2
+ end
3
+
4
+ module SystemHelper
5
+ def check_error_code(command, stderr, status, allowed_return_codes)
6
+ returned = status.exitstatus
7
+ return if status.success?
8
+ return if allowed_return_codes.include?(returned)
9
+ explanation = "failed command #{command} due to error code #{returned}. stderr was #{stderr}"
10
+ raise FailedCommandException.new(explanation)
11
+ end
12
+
13
+ def check_stderr(command, stderr, status, ignore_stderr_presence)
14
+ return if ignore_stderr_presence
15
+ return if stderr == ''
16
+ returned = status.exitstatus
17
+ explanation = "failed command #{command} due to < #{stderr}> on stderr. return code was #{returned}"
18
+ raise FailedCommandException.new(explanation)
19
+ end
20
+
21
+ def execute_command(command, debug = false, allowed_return_codes: [], ignore_stderr_presence: false)
22
+ puts command if debug
23
+ stdout, stderr, status = Open3.capture3(command)
24
+
25
+ check_error_code(command, stderr, status, allowed_return_codes)
26
+ check_stderr(command, stderr, status, ignore_stderr_presence)
27
+
28
+ return stderr + stdout
29
+ end
30
+
31
+ def self.not_enough_free_space
32
+ minimum_gb = 2
33
+ available_gb = get_available_space_for_cache_in_gb
34
+ if available_gb < minimum_gb
35
+ puts "get_available_space_for_cache_in_gb: #{available_gb}, minimum_gb: #{minimum_gb}"
36
+ return true
37
+ else
38
+ return false
39
+ end
40
+ end
41
+
42
+ def get_available_space_for_cache_in_gb
43
+ stat = Sys::Filesystem.stat(CartoCSSHelper::Configuration.get_path_to_folder_for_cache)
44
+ return stat.block_size * stat.blocks_available / 1024 / 1024 / 1024
45
+ end
46
+
47
+ def delete_file(filename, reason)
48
+ open(CartoCSSHelper::Configuration.get_path_to_folder_for_output + 'deleting_files_log.txt', 'a') do |file|
49
+ message = "deleting #{filename}, #{File.size(filename) / 1024 / 1024}MB - #{reason}"
50
+ puts message
51
+ file.puts(message)
52
+ File.delete(filename)
53
+ end
54
+ end
55
+ end
@@ -10,15 +10,32 @@ include CartoCSSHelper::Configuration
10
10
  module CartoCSSHelper
11
11
  module Validator
12
12
  def run_tests(git_branch)
13
- run_expected_rendering_test(git_branch)
14
13
  run_dy_test(git_branch)
14
+ run_missing_name_test(git_branch)
15
+ run_expected_rendering_test(git_branch, true)
15
16
  run_closed_way_test(git_branch)
17
+ run_expected_rendering_test(git_branch)
18
+ run_unwanted_name_test(git_branch)
16
19
  end
17
20
 
18
- def run_expected_rendering_test(git_branch)
21
+ def run_expected_rendering_test(git_branch, quick_and_more_prone_to_errors = false)
19
22
  Git.checkout git_branch
20
23
  puts 'unexpectedly rendered/unrendered keys:'
21
- compare_expected_with_real_rendering
24
+ compare_expected_with_real_rendering(quick_and_more_prone_to_errors)
25
+ puts
26
+ end
27
+
28
+ def run_missing_name_test(git_branch)
29
+ Git.checkout git_branch
30
+ puts 'Check whatever names are displayed:'
31
+ run_global_check(:check_missing_names)
32
+ puts
33
+ end
34
+
35
+ def run_unwanted_name_test(git_branch)
36
+ Git.checkout git_branch
37
+ puts 'Check whatever names are displayed:'
38
+ run_global_check(:check_unwanted_names)
22
39
  puts
23
40
  end
24
41
 
@@ -36,137 +53,181 @@ module CartoCSSHelper
36
53
  puts
37
54
  end
38
55
 
39
- def compare_expected_with_real_rendering
56
+ def compare_expected_with_real_rendering(quick_and_more_prone_to_errors = false)
40
57
  list_of_documented = CartoCSSHelper::Configuration.get_style_specific_data.list_of_documented_tags
41
58
  info = Info.new
42
- list_of_rendered = info.get_render_state_of_tags
59
+ list_of_rendered = info.get_render_state_of_tags(quick_and_more_prone_to_errors)
43
60
 
61
+ puts 'ensure_that_tags_documented_and_rendered_have_the_same_state'
44
62
  ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
63
+
64
+ puts 'ensure_that_all_rendered_tags_are_documented'
45
65
  ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
66
+
67
+ puts 'ensure_that_all_documented_are_really_rendered'
46
68
  ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
47
69
  end
48
70
 
49
71
  def ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
50
- list_of_rendered.each { |tag_info|
72
+ list_of_rendered.each do |tag_info|
51
73
  compare_expected_with_tag_data list_of_documented, tag_info
52
- }
74
+ end
53
75
  end
54
76
 
55
77
  def ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
56
- list_of_rendered.each { |tag_info|
57
- if tag_info.state != :ignored
58
- if !is_tag_documented(list_of_documented, tag_info.key, tag_info.value)
59
- puts 'documented'
60
- puts "\tmissing"
61
- puts 'real'
62
- print "\t"
63
- tag_info.print
64
- puts
65
- end
66
- end
67
- }
78
+ list_of_rendered.each do |tag_info|
79
+ next if is_tag_documented(list_of_documented, tag_info.key, tag_info.value)
80
+ puts 'documented'
81
+ puts "\tmissing"
82
+ puts 'real'
83
+ print "\t"
84
+ tag_info.print
85
+ puts
86
+ end
68
87
  end
69
88
 
70
89
  def ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
71
- list_of_documented.each { |documented|
72
- if !is_tag_documented(list_of_rendered, documented.key, documented.value)
73
- puts 'documented'
74
- print "\t"
75
- documented.print
76
- puts 'real'
77
- puts "\tmissing"
78
- puts
90
+ list_of_documented.each do |documented|
91
+ if Info.get_expected_state(documented.key, documented.value) == :ignored
92
+ next
79
93
  end
80
- }
94
+ next if is_tag_documented(list_of_rendered, documented.key, documented.value)
95
+ puts 'documented'
96
+ print "\t"
97
+ documented.print
98
+ puts 'real'
99
+ puts "\tmissing"
100
+ puts
101
+ end
81
102
  end
82
103
 
83
104
  def is_tag_documented(list, key, value)
84
- list.each { |tag_info|
85
- if key == tag_info.key
86
- if value == tag_info.value
87
- return true
88
- end
89
- end
90
- }
105
+ list.each do |tag_info|
106
+ next unless key == tag_info.key
107
+ return true if value == tag_info.value
108
+ end
91
109
  return false
92
110
  end
93
111
 
94
112
  def compare_expected_with_tag_data(list_of_expected, tag_info)
95
- list_of_expected.each { |expected|
96
- if expected.key == tag_info.key
97
- if expected.value == tag_info.value
98
- if expected.equal? tag_info
99
- puts 'expected'
100
- print "\t"
101
- expected.print
102
- puts 'real'
103
- print "\t"
104
- tag_info.print
105
- puts
106
- end
107
- return
108
- end
113
+ list_of_expected.each do |expected|
114
+ next unless expected.key == tag_info.key
115
+ next unless expected.value == tag_info.value
116
+ if expected.equal? tag_info
117
+ puts 'expected'
118
+ print "\t"
119
+ expected.print
120
+ puts 'real'
121
+ print "\t"
122
+ tag_info.print
123
+ puts
109
124
  end
110
- }
125
+ return
126
+ end
111
127
  end
112
128
 
113
129
  def run_global_check(function)
114
- Heuristic.get_tags.each { |element|
115
- (Configuration.get_max_z..Configuration.get_max_z).each { |zlevel| #get_min_z should be used - but as renderer is extremely slow this hack was used TODO
116
- send(function, element[0], element[1], zlevel)
117
- }
118
- }
119
- end
120
-
121
- #TODO - what about composite tags?
122
- def check_problems_with_closed_line(key, value, zlevel, on_water = false)
123
- way = Scene.new({key => value}, zlevel, on_water, 'way')
124
- closed_way = Scene.new({key => value}, zlevel, on_water, 'closed_way')
125
- empty = Scene.new({}, zlevel, on_water, 'node')
130
+ Heuristic.get_tags.each do |element|
131
+ key = element[0]
132
+ value = element[1]
133
+ state = Info.get_expected_state(key, value)
134
+ tags = { key => value }
135
+ next if state == :ignore
136
+ if state == :composite
137
+ tags.merge!(Info.get_expected_composite(key, value))
138
+ end
139
+ (Configuration.get_max_z..Configuration.get_max_z).each do |zlevel| # get_min_z should be used - but as renderer is extremely slow this hack was used TODO
140
+ send(function, tags, zlevel)
141
+ end
142
+ end
143
+ end
144
+
145
+ def check_problems_with_closed_line(tags, zlevel, on_water = false)
146
+ way = Scene.new(tags, zlevel, on_water, 'way', true)
147
+ closed_way = Scene.new(tags, zlevel, on_water, 'closed_way', true)
148
+ empty = Scene.new({}, zlevel, on_water, 'node', true)
126
149
  if way.is_output_different(empty)
127
- if !closed_way.is_output_different(empty)
128
- puts key+'='+value
150
+ puts tags unless closed_way.is_output_different(empty)
151
+ end
152
+ end
153
+
154
+ def check_missing_names(tags, zlevel, interactive = false, on_water = false)
155
+ not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
156
+ return if not_required.include?(tags)
157
+ ['node', 'closed_way', 'way'].each do |type|
158
+ next if not_required.include?(tags.merge({ type: type }))
159
+ unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
160
+ # puts key+"="+value+" - not displayed as node on z#{zlevel}"
161
+ next
162
+ end
163
+ tags.delete('name') if tags['name'] != nil
164
+ unless is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
165
+ puts "#{tags} - label is missing on z#{zlevel} #{type}"
166
+ next
129
167
  end
130
168
  end
131
169
  end
132
170
 
133
- def check_dy(key, value, zlevel, interactive=false, on_water=false)
134
- if !is_object_displaying_anything key, value, zlevel, on_water
135
- #puts key+"="+value+" - not displayed as node on z#{zlevel}"
171
+ def check_unwanted_names(tags, zlevel, interactive = false, on_water = false)
172
+ ['node', 'closed_way', 'way'].each do |type|
173
+ not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
174
+ next unless not_required.include?(tags) || not_required.include?(tags.merge({ type: type }))
175
+ unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
176
+ # puts key+"="+value+" - not displayed as node on z#{zlevel}"
177
+ next
178
+ end
179
+ tags.delete('name') if tags['name'] != nil
180
+ if is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
181
+ puts "#{tags} - label is unxpectedly displayed on z#{zlevel} #{type}"
182
+ end
183
+ end
184
+ end
185
+
186
+ def check_dy(tags, zlevel, interactive = false, on_water = false)
187
+ unless is_object_displaying_anything_as_node tags, zlevel, on_water
188
+ # puts key+"="+value+" - not displayed as node on z#{zlevel}"
136
189
  return
137
190
  end
138
- if !is_object_displaying_name key, value, 'a', zlevel, on_water
139
- #puts key+"="+value+" - label is missing on z#{zlevel} nodes"
191
+ unless is_object_displaying_name_as_node tags, 'a', zlevel, on_water
192
+ # puts key+"="+value+" - label is missing on z#{zlevel} nodes"
140
193
  return
141
194
  end
142
195
  test_name = 'ÉÉÉÉÉÉ ÉÉÉÉÉÉ ÉÉÉÉÉÉ'
143
- while !is_object_displaying_name key, value, test_name, zlevel, on_water
144
- puts key+'='+value+" - name is missing for name '#{test_name}' on z#{zlevel}"
196
+ until is_object_displaying_name_as_node tags, test_name, zlevel, on_water
197
+ puts "#{tags} - name is missing for name '#{test_name}' on z#{zlevel}"
145
198
  if interactive
146
199
  puts 'press enter'
147
200
  gets
148
201
  else
149
202
  return
150
203
  end
151
- with_name = Scene.new({key => value, 'name' => test_name}, zlevel, on_water, 'node')
204
+ with_name = Scene.new({ key => value, 'name' => test_name }, zlevel, on_water, 'node', true)
152
205
  with_name.flush_cache
153
206
  puts 'calculating'
154
207
  end
155
- #puts key+"="+value+" - name is OK for name '#{name}'"
208
+ # puts key+"="+value+" - name is OK for name '#{name}'"
156
209
  end
157
210
 
158
- def is_object_displaying_name(key, value, name, zlevel, on_water)
159
- name_tags = {key => value, 'name' => name}
160
- with_name = Scene.new(name_tags, zlevel, on_water, 'node')
161
- nameless_tags = {key => value}
162
- nameless = Scene.new(nameless_tags, zlevel, on_water, 'node')
211
+ def is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, type)
212
+ name_tags = tags.merge({ 'name' => name })
213
+ with_name = Scene.new(name_tags, zlevel, on_water, type, true)
214
+ nameless_tags = tags
215
+ nameless = Scene.new(nameless_tags, zlevel, on_water, type, true)
163
216
  return with_name.is_output_different(nameless)
164
217
  end
165
218
 
166
- def is_object_displaying_anything(key, value, zlevel, on_water)
167
- object = Scene.new({key => value}, zlevel, on_water, 'node')
168
- empty = Scene.new({}, zlevel, on_water, 'node')
219
+ def is_object_displaying_name_as_node(tags, name, zlevel, on_water)
220
+ is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, 'node')
221
+ end
222
+
223
+ def is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, type)
224
+ object = Scene.new(tags, zlevel, on_water, type, true)
225
+ empty = Scene.new({}, zlevel, on_water, type, true)
169
226
  return object.is_output_different(empty)
170
227
  end
228
+
229
+ def is_object_displaying_anything_as_node(tags, zlevel, on_water)
230
+ return is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, 'node')
231
+ end
171
232
  end
172
233
  end
@@ -7,9 +7,10 @@ module CartoCSSHelper
7
7
  @file_location = file_location
8
8
  @description = description
9
9
  end
10
+
10
11
  def identical(another_image)
11
- #Returns true if the contents of a file A and a file B are identical.
12
- return FileUtils.compare_file(self.file_location, another_image.file_location)
12
+ # Returns true if the contents of a file A and a file B are identical.
13
+ return FileUtils.compare_file(file_location, another_image.file_location)
13
14
  end
14
15
  end
15
16
 
@@ -22,6 +23,7 @@ module CartoCSSHelper
22
23
  @right_file_location = right_image.file_location
23
24
  @description = left_image.description
24
25
  end
26
+
25
27
  def merge_description_from_next_image(image)
26
28
  @description << ', ' << image.description
27
29
  end
@@ -36,7 +38,7 @@ module CartoCSSHelper
36
38
  @image_size = image_size
37
39
  @margin = 10
38
40
  @standard_pointsize = 10
39
- @header_space = @standard_pointsize*1.5
41
+ @header_space = @standard_pointsize * 1.5
40
42
  @diff_note_space = @standard_pointsize
41
43
 
42
44
  render
@@ -44,13 +46,13 @@ module CartoCSSHelper
44
46
 
45
47
  def compress(before, after)
46
48
  returned = [PairOfComparedImages.new(before[0], after[0])]
47
- (1...before.length).each { |i|
48
- if before[i].identical(before[i-1]) && after[i].identical(after[i-1])
49
+ (1...before.length).each do |i|
50
+ if before[i].identical(before[i - 1]) && after[i].identical(after[i - 1])
49
51
  returned[-1].merge_description_from_next_image(before[i])
50
52
  else
51
53
  returned.push(PairOfComparedImages.new(before[i], after[i]))
52
54
  end
53
- }
55
+ end
54
56
  return returned
55
57
  end
56
58
 
@@ -58,17 +60,16 @@ module CartoCSSHelper
58
60
  create_canvas
59
61
  offset = 0
60
62
  render_header
61
- offset += @header_space + @margin*1.5
62
- render_diff_note offset
63
- offset += @diff_note_space + @margin*0.5
63
+ offset += @header_space + @margin * 1.5
64
+ offset += @diff_note_space + @margin * 0.5
64
65
  render_images_with_labels offset
65
- offset += (@compared.length)*(@margin + @image_size)
66
+ offset += @compared.length * (@margin + @image_size)
66
67
  render_footer offset
67
68
  end
68
69
 
69
70
  def create_canvas
70
71
  y = get_needed_y
71
- x = @image_size*2+3*@margin
72
+ x = @image_size * 2 + 3 * @margin
72
73
 
73
74
  @canvas = Magick::Image.new(x, y)
74
75
  end
@@ -76,48 +77,49 @@ module CartoCSSHelper
76
77
  def get_needed_y
77
78
  y = 0
78
79
  y += @header_space
79
- y += @margin*1.5
80
+ y += @margin * 1.5
80
81
  y += @diff_note_space
81
- y += @margin*0.5
82
- y += (@compared.length) * (@image_size + @margin)
82
+ y += @margin * 0.5
83
+ y += @compared.length * (@image_size + @margin)
83
84
  y += @diff_note_space
84
85
  return y
85
86
  end
86
87
 
87
88
  def render_header
88
89
  header_drawer = Magick::Draw.new
89
- header_drawer.pointsize(@header_space*3/5)
90
+ header_drawer.pointsize(@header_space * 3 / 5)
90
91
  header_drawer.text(@margin, @header_space, @header)
91
92
  header_drawer.draw(@canvas)
92
93
  end
93
94
 
94
- def render_diff_note(y_offset)
95
- drawer = Magick::Draw.new
96
- drawer.pointsize(@diff_note_space)
97
- #drawer.text(@margin, y_offset, 'before')
98
- drawer.draw(@canvas)
99
- #drawer.text(@margin*2 + @image_size, y_offset, 'after')
100
- drawer.draw(@canvas)
101
- end
102
-
103
95
  def render_images_with_labels(y_offset)
104
- (0...@compared.length).each { |i|
96
+ (0...@compared.length).each do |i|
105
97
  render_row_of_labelled_images(@compared[i], y_offset + i * (@margin + @image_size))
106
- }
98
+ end
99
+ end
100
+
101
+ def read_image_from_disk(filename)
102
+ return Magick::Image.read(filename)[0]
103
+ rescue Magick::ImageMagickError => e
104
+ # for example on loading corrupted empty file (for example CartoCSSHelper was interuppted during writing to disk...)
105
+ puts "reading image <#{filename}> from disk failed"
106
+ puts e.class
107
+ puts e
108
+ raise e
107
109
  end
108
110
 
109
111
  def render_row_of_labelled_images(processed, y_offset)
110
- left_image = Magick::Image.read(processed.left_file_location)[0]
111
- right_image = Magick::Image.read(processed.right_file_location)[0]
112
+ left_image = read_image_from_disk(processed.left_file_location)
113
+ right_image = read_image_from_disk(processed.right_file_location)
112
114
  drawer = Magick::Draw.new
113
- drawer.pointsize(@diff_note_space*4/5)
115
+ drawer.pointsize(@diff_note_space * 4 / 5)
114
116
  if left_image == right_image
115
- drawer.text(@margin + @image_size/2, y_offset, "#{processed.description} - unchanged")
117
+ drawer.text(@margin + @image_size / 2, y_offset, "#{processed.description} - unchanged")
116
118
  drawer.draw(@canvas)
117
119
  else
118
120
  drawer.text(@margin, y_offset, "#{processed.description} - before")
119
121
  drawer.draw(@canvas)
120
- drawer.text(@margin*2 + @image_size, y_offset, "#{processed.description} - after")
122
+ drawer.text(@margin * 2 + @image_size, y_offset, "#{processed.description} - after")
121
123
  drawer.draw(@canvas)
122
124
  end
123
125
  render_row_of_images(y_offset, left_image, right_image)
@@ -133,17 +135,17 @@ module CartoCSSHelper
133
135
  # noinspection RubyResolve
134
136
  def render_row_of_images(y_offset, left_image, right_image)
135
137
  if left_image == right_image
136
- @canvas.composite!(left_image, @margin*1.5 + @image_size/2, y_offset, Magick::OverCompositeOp)
138
+ @canvas.composite!(left_image, @margin * 1.5 + @image_size / 2, y_offset, Magick::OverCompositeOp)
137
139
  else
138
140
  @canvas.composite!(left_image, @margin, y_offset, Magick::OverCompositeOp)
139
- @canvas.composite!(right_image, @margin*2+@image_size, y_offset, Magick::OverCompositeOp)
141
+ @canvas.composite!(right_image, @margin * 2 + @image_size, y_offset, Magick::OverCompositeOp)
140
142
  end
141
143
  end
142
144
 
143
145
  def render_footer(y_offset)
144
146
  label_drawer = Magick::Draw.new
145
147
  label_drawer.pointsize(@standard_pointsize)
146
- label_drawer.text(@margin, y_offset, 'generated using https://github.com/mkoniecz/CartoCSSHelper')
148
+ label_drawer.text(@margin, y_offset, 'generated using https://github.com/matkoniecz/CartoCSSHelper')
147
149
  label_drawer.draw(@canvas)
148
150
  end
149
151