cartocss_helper 1.2.1 → 4.0.0

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.
@@ -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