trackable_tasks 0.0.3 → 0.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.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.0.4
2
+
3
+ * Added a basic controller to display information about the task runs
4
+
1
5
  == 0.0.3
2
6
 
3
7
  * Moved sqlite and capybara to the development gems
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
@@ -0,0 +1,24 @@
1
+ # Index and show controller for TaskRuns
2
+ # TaskRuns should not be created or edited here because they are generate by rake tasks
3
+ class TrackableTasks::TaskRunsController < ApplicationController
4
+ # Lists all tasks in task run
5
+ def index
6
+ @task_runs = TrackableTasks::TaskRun.all
7
+
8
+ respond_to do |format|
9
+ format.html # index.html.erb
10
+ end
11
+ end
12
+
13
+ # Lists specific task run
14
+ def show
15
+ @task_run = TrackableTasks::TaskRun.find_by_id(params[:id])
16
+
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ end
21
+
22
+ end
23
+ end
24
+
@@ -35,5 +35,30 @@ module TrackableTasks
35
35
  self.error_text = "" if self.error_text.nil?
36
36
  self.error_text += text + "\n"
37
37
  end
38
+
39
+ # Creates run time based on start and end time
40
+ # If there is no end_time, display 'Run has not completed.'
41
+ # @return [String] The run time formatted in hours, minutes and seconds
42
+ # @return [String] Message that run has not completed
43
+ def run_time
44
+ if self.end_time
45
+ return Time.at(self.end_time - self.start_time).gmtime.strftime('%R:%S')
46
+ else
47
+ return "Run has not completed."
48
+ end
49
+ end
50
+
51
+ # Determines error message color based on success and whether or not there is error text
52
+ # Return value corresponds to a css color
53
+ # @return [String] The color of the status/error message
54
+ def status_color
55
+ if self.success && self.error_text.nil?
56
+ return 'green'
57
+ elsif self.success
58
+ return 'yellow'
59
+ else
60
+ return 'red'
61
+ end
62
+ end
38
63
  end
39
64
  end
@@ -0,0 +1,27 @@
1
+ <table>
2
+ <tr>
3
+ <th>Task Type </th>
4
+ <th>Start Time </th>
5
+ <th>Run Time </th>
6
+ <th>Status </th>
7
+ <th> </th>
8
+ </tr>
9
+
10
+
11
+ <% if !@task_runs.empty? %>
12
+ <% @task_runs.each do |task_run| %>
13
+ <tr>
14
+ <td> <%= task_run.task_type %> </td>
15
+ <td> <%= task_run.start_time.strftime('%D') %> </td>
16
+ <td> <%= task_run.run_time %>
17
+ <td> <span style="color: <%= task_run.status_color %>"><%= task_run.success %> </span></td>
18
+ <td> <%= link_to 'Show', task_run %> </td>
19
+ </tr>
20
+ <% end %>
21
+ <% else %>
22
+ <tr>
23
+ <td>There are no records. </td>
24
+ </tr>
25
+ <% end %>
26
+ </table>
27
+
@@ -0,0 +1,8 @@
1
+ <h2> <%= @task_run.task_type %> </h2>
2
+
3
+ <p><strong>Start time: </strong> <%= @task_run.start_time.strftime('%D') %> </p>
4
+ <p><strong>End time: </strong> <%= @task_run.end_time.strftime('%D') %> </p>
5
+ <p><strong>Run time: </strong> <%= @task_run.run_time %> </p>
6
+ <p><strong>Success: </strong> <span style="color: <%= @task_run.status_color %>"> <%= @task_run.success %> </span></p>
7
+ <p><strong>Error text: </strong> <%= @task_run.error_text %> </p>
8
+ <p><strong>Log text: </strong> <%= @task_run.log_text %> </p>
data/config/routes.rb CHANGED
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ namespace :trackable_tasks do
3
+ resources :task_runs
4
+ end
5
+ end
@@ -0,0 +1,64 @@
1
+ Given /^a task_run does not exist$/ do
2
+ TrackableTasks::TaskRun.nil?
3
+ end
4
+
5
+ Then (/^I should see "([^"]*)" $/) do |no_reconds|
6
+ task_run = TrackableTasks::TaskRun.last
7
+ page.should have_content(no_records)
8
+ end
9
+
10
+ Given /^a task_run exists$/ do
11
+ TrackableTasks::TaskRun.create(:start_time => Time.now, :task_type => 'Test Task', :success => true)
12
+ end
13
+
14
+ Given /^a task_run exists with the following values$/ do |table|
15
+ attributes = {}
16
+ table.hashes.each do |key_pair|
17
+ if key_pair["key"] != 'key'
18
+ attributes[key_pair["key"]] = key_pair["value"]
19
+ end
20
+ end
21
+ TrackableTasks::TaskRun.create(attributes)
22
+ TrackableTasks::TaskRun.all.count.should > 0
23
+ end
24
+
25
+ Given /^end_time does not exist$/ do
26
+ task_run = TrackableTasks::TaskRun.last
27
+ task_run.end_time.nil?
28
+ end
29
+
30
+ Then /^I should see the data for that task_run$/ do
31
+ task_run = TrackableTasks::TaskRun.last
32
+ page.should have_content(task_run.start_time.strftime('%D'))
33
+ page.should have_content(task_run.task_type)
34
+ page.should have_content(task_run.success)
35
+ end
36
+
37
+ Then (/^I should see "([^"]*)" in the run_time column$/) do |run_time_message|
38
+ task_run = TrackableTasks::TaskRun.last
39
+ task_run.run_time == run_time_message
40
+ end
41
+
42
+ Given /^success is true$/ do
43
+ task_run = TrackableTasks::TaskRun.last
44
+ task_run.success == true
45
+ end
46
+
47
+ Given /^there is no error_text$/ do
48
+ task_run = TrackableTasks::TaskRun.last
49
+ task_run.error_text.nil?
50
+ end
51
+
52
+ Then /^status_color should be green$/ do
53
+ task_run = TrackableTasks::TaskRun.last
54
+ page.body.should match("color: green") #had to use match here, have_content was not getting the html with css
55
+ end
56
+
57
+ Then /^I should see the show data for that task_run$/ do
58
+ task_run = TrackableTasks::TaskRun.last
59
+ page.should have_content(task_run.start_time.strftime('%D'))
60
+ page.should have_content(task_run.task_type)
61
+ page.should have_content(task_run.success)
62
+ page.should have_content(task_run.log_text)
63
+ page.should have_content(task_run.error_text)
64
+ end
@@ -0,0 +1,214 @@
1
+ # TL;DR: YOU SHOULD DELETE THIS FILE
2
+ #
3
+ # This file was generated by Cucumber-Rails and is only here to get you a head start
4
+ # These step definitions are thin wrappers around the Capybara/Webrat API that lets you
5
+ # visit pages, interact with widgets and make assertions about page content.
6
+ #
7
+ # If you use these step definitions as basis for your features you will quickly end up
8
+ # with features that are:
9
+ #
10
+ # * Hard to maintain
11
+ # * Verbose to read
12
+ #
13
+ # A much better approach is to write your own higher level step definitions, following
14
+ # the advice in the following blog posts:
15
+ #
16
+ # * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
17
+ # * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
18
+ # * http://elabs.se/blog/15-you-re-cuking-it-wrong
19
+ #
20
+
21
+
22
+ require 'uri'
23
+ require 'cgi'
24
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
25
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "selectors"))
26
+
27
+ module WithinHelpers
28
+ def with_scope(locator)
29
+ locator ? within(*selector_for(locator)) { yield } : yield
30
+ end
31
+ end
32
+ World(WithinHelpers)
33
+
34
+ # Single-line step scoper
35
+ When /^(.*) within (.*[^:])$/ do |step, parent|
36
+ with_scope(parent) { When step }
37
+ end
38
+
39
+ # Multi-line step scoper
40
+ When /^(.*) within (.*[^:]):$/ do |step, parent, table_or_string|
41
+ with_scope(parent) { When "#{step}:", table_or_string }
42
+ end
43
+
44
+ Given /^(?:|I )am on (.+)$/ do |page_name|
45
+ visit path_to(page_name)
46
+ end
47
+
48
+ When /^(?:|I )go to (.+)$/ do |page_name|
49
+ visit path_to(page_name)
50
+ end
51
+
52
+ When /^(?:|I )press "([^"]*)"$/ do |button|
53
+ click_button(button)
54
+ end
55
+
56
+ When /^(?:|I )follow "([^"]*)"$/ do |link|
57
+ click_link(link)
58
+ end
59
+
60
+ When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
61
+ fill_in(field, :with => value)
62
+ end
63
+
64
+ When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
65
+ fill_in(field, :with => value)
66
+ end
67
+
68
+ # Use this to fill in an entire form with data from a table. Example:
69
+ #
70
+ # When I fill in the following:
71
+ # | Account Number | 5002 |
72
+ # | Expiry date | 2009-11-01 |
73
+ # | Note | Nice guy |
74
+ # | Wants Email? | |
75
+ #
76
+ # TODO: Add support for checkbox, select og option
77
+ # based on naming conventions.
78
+ #
79
+ When /^(?:|I )fill in the following:$/ do |fields|
80
+ fields.rows_hash.each do |name, value|
81
+ When %{I fill in "#{name}" with "#{value}"}
82
+ end
83
+ end
84
+
85
+ When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
86
+ select(value, :from => field)
87
+ end
88
+
89
+ # moved to maniuplation steps
90
+ When /^(?:|I )check "([^"]*)"$/ do |field|
91
+ check(field)
92
+ end
93
+
94
+ When /^(?:|I )uncheck "([^"]*)"$/ do |field|
95
+ uncheck(field)
96
+ end
97
+
98
+ When /^(?:|I )choose "([^"]*)"$/ do |field|
99
+ choose(field)
100
+ end
101
+
102
+ When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
103
+ attach_file(field, File.expand_path(path))
104
+ end
105
+
106
+ Then /^(?:|I )should see "([^"]*)"$/ do |text|
107
+ if page.respond_to? :should
108
+ page.should have_content(text)
109
+ else
110
+ assert page.has_content?(text)
111
+ end
112
+ end
113
+
114
+ Then /^(?:|I )should see \/([^\/]*)\/$/ do |regexp|
115
+ regexp = Regexp.new(regexp)
116
+
117
+ if page.respond_to? :should
118
+ page.should have_xpath('//*', :text => regexp)
119
+ else
120
+ assert page.has_xpath?('//*', :text => regexp)
121
+ end
122
+ end
123
+
124
+ Then /^(?:|I )should not see "([^"]*)"$/ do |text|
125
+ if page.respond_to? :should
126
+ page.should have_no_content(text)
127
+ else
128
+ assert page.has_no_content?(text)
129
+ end
130
+ end
131
+
132
+ Then /^(?:|I )should not see \/([^\/]*)\/$/ do |regexp|
133
+ regexp = Regexp.new(regexp)
134
+
135
+ if page.respond_to? :should
136
+ page.should have_no_xpath('//*', :text => regexp)
137
+ else
138
+ assert page.has_no_xpath?('//*', :text => regexp)
139
+ end
140
+ end
141
+
142
+ Then /^the "([^"]*)" field(?: within (.*))? should contain "([^"]*)"$/ do |field, parent, value|
143
+ with_scope(parent) do
144
+ field = find_field(field)
145
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
146
+ if field_value.respond_to? :should
147
+ field_value.should =~ /#{value}/
148
+ else
149
+ assert_match(/#{value}/, field_value)
150
+ end
151
+ end
152
+ end
153
+
154
+ Then /^the "([^"]*)" field(?: within (.*))? should not contain "([^"]*)"$/ do |field, parent, value|
155
+ with_scope(parent) do
156
+ field = find_field(field)
157
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
158
+ if field_value.respond_to? :should_not
159
+ field_value.should_not =~ /#{value}/
160
+ else
161
+ assert_no_match(/#{value}/, field_value)
162
+ end
163
+ end
164
+ end
165
+
166
+ # moved to generic steps
167
+ #Then /^the "([^"]*)" checkbox(?: within (.*))? should be checked$/ do |label, parent|
168
+ # with_scope(parent) do
169
+ # field_checked = find_field(label)['checked']
170
+ # if field_checked.respond_to? :should
171
+ # field_checked.should be_true
172
+ # else
173
+ # assert field_checked
174
+ # end
175
+ # end
176
+ #end
177
+
178
+ # moved to generic steps
179
+ #Then /^the "([^"]*)" checkbox(?: within (.*))? should not be checked$/ do |label, parent|
180
+ # with_scope(parent) do
181
+ # field_checked = find_field(label)['checked']
182
+ # if field_checked.respond_to? :should
183
+ # field_checked.should be_false
184
+ # else
185
+ # assert !field_checked
186
+ # end
187
+ # end
188
+ #end
189
+
190
+ Then /^(?:|I )should be on (.+)$/ do |page_name|
191
+ current_path = URI.parse(current_url).path
192
+ if current_path.respond_to? :should
193
+ current_path.should == path_to(page_name)
194
+ else
195
+ assert_equal path_to(page_name), current_path
196
+ end
197
+ end
198
+
199
+ Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
200
+ query = URI.parse(current_url).query
201
+ actual_params = query ? CGI.parse(query) : {}
202
+ expected_params = {}
203
+ expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
204
+
205
+ if actual_params.respond_to? :should
206
+ actual_params.should == expected_params
207
+ else
208
+ assert_equal expected_params, actual_params
209
+ end
210
+ end
211
+
212
+ Then /^show me the page$/ do
213
+ save_and_open_page
214
+ end
@@ -0,0 +1,31 @@
1
+ module NavigationHelpers
2
+ # Maps a name to a path. Used by the
3
+ #
4
+ # When /^I go to (.+)$/ do |page_name|
5
+ #
6
+ # step definition in web_steps.rb
7
+ #
8
+ def path_to(page_name)
9
+ case page_name
10
+
11
+ when /the [h|H]ome\s?page/
12
+ '/'
13
+ when /the task_run index page/
14
+ trackable_tasks_task_runs_path
15
+ when /the task_run show page/
16
+ trackable_tasks_task_run_path(TrackableTasks::TaskRun.last)
17
+
18
+ else
19
+ begin
20
+ page_name =~ /the (.*) page/
21
+ path_components = $1.split(/\s+/)
22
+ self.send(path_components.push('path').join('_').to_sym)
23
+ rescue Object => e
24
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
25
+ "Now, go and add a mapping in #{__FILE__}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ World(NavigationHelpers)
@@ -0,0 +1,39 @@
1
+ module HtmlSelectorsHelpers
2
+ # Maps a name to a selector. Used primarily by the
3
+ #
4
+ # When /^(.+) within (.+)$/ do |step, scope|
5
+ #
6
+ # step definitions in web_steps.rb
7
+ #
8
+ def selector_for(locator)
9
+ case locator
10
+
11
+ when "the page"
12
+ "html > body"
13
+
14
+ # Add more mappings here.
15
+ # Here is an example that pulls values out of the Regexp:
16
+ #
17
+ # when /^the (notice|error|info) flash$/
18
+ # ".flash.#{$1}"
19
+
20
+ # You can also return an array to use a different selector
21
+ # type, like:
22
+ #
23
+ # when /the header/
24
+ # [:xpath, "//header"]
25
+
26
+ # This allows you to provide a quoted selector as the scope
27
+ # for "within" steps as was previously the default for the
28
+ # web steps:
29
+ when /^"(.+)"$/
30
+ $1
31
+
32
+ else
33
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
34
+ "Now, go and add a mapping in #{__FILE__}"
35
+ end
36
+ end
37
+ end
38
+
39
+ World(HtmlSelectorsHelpers)
@@ -0,0 +1,38 @@
1
+ Feature: task_run controller index and show pages
2
+
3
+ Scenario: should show task runs on the index page
4
+ Given a task_run exists
5
+ When I go to the task_run index page
6
+ Then I should see the data for that task_run
7
+
8
+ Scenario: no task runs
9
+ Given a task_run does not exist
10
+ When I go to the task_run index page
11
+ Then I should see "There are no records"
12
+
13
+ Scenario: no end time
14
+ Given a task_run exists
15
+ And end_time does not exist
16
+ When I go to the task_run index page
17
+ Then I should see "Run time not completed" in the run_time column
18
+
19
+ Scenario: success is true
20
+ Given a task_run exists with the following values
21
+ | key | value |
22
+ | start_time | 2011-11-03 16:31:19 -0400 |
23
+ | task_type | Task type 3 |
24
+ | success | true |
25
+ When I go to the task_run index page
26
+ Then status_color should be green
27
+
28
+ Scenario: should show task run on the show page
29
+ Given a task_run exists with the following values
30
+ | key | value |
31
+ | start_time | 2011-11-03 16:31:19 -0400 |
32
+ | end_time | 2011-11-03 17:53:40 -0400 |
33
+ | task_type | Task type 4 |
34
+ | success | true |
35
+ | error_text | This is some error text |
36
+ | log_text | This is some log text |
37
+ When I go to the task_run show page
38
+ Then I should see the show data for that task_run
@@ -14,7 +14,7 @@ describe TaskRun do
14
14
 
15
15
  it "should be valid" do
16
16
  @run.attributes = @valid_attributes
17
- @run.should be_valid
17
+ @run.should be_valid
18
18
  end
19
19
 
20
20
  it "should require task type" do
@@ -97,4 +97,45 @@ describe TaskRun do
97
97
  @run.error_text.should match @text
98
98
  end
99
99
  end
100
+
101
+ describe "status_color method" do
102
+ before(:each) do
103
+ @run = TaskRun.new()
104
+ end
105
+
106
+ it "should return green if success is true and error_text is empty (nil)" do
107
+ @run.success = true
108
+ @run.error_text = nil
109
+ @run.status_color.should == "green"
110
+ end
111
+
112
+ it "should return yellow if success is true but there is error_text" do
113
+ @run.success = true
114
+ @run.error_text = "Error text"
115
+ @run.status_color.should == "yellow"
116
+ end
117
+
118
+ it "should return red if success is false" do
119
+ @run.success = false
120
+ @run.status_color.should == "red"
121
+ end
122
+ end
123
+
124
+ describe "run_time method" do
125
+ before(:each) do
126
+ @run = TaskRun.new()
127
+ end
128
+
129
+ it "should return the time formatted in hours, minutes and seconds if end_time is true" do
130
+ @run.start_time = Time.at(3)
131
+ @run.end_time = Time.at(946702800)
132
+ @run.run_time.should == Time.at(@run.end_time - @run.start_time).gmtime.strftime('%R:%S')
133
+ end
134
+
135
+ it "should return a string 'Run has not completed' if end_time is false" do
136
+ @run.end_time = false
137
+ @run.run_time.should == "Run has not completed."
138
+ end
139
+ end
140
+
100
141
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{trackable_tasks}
8
- s.version = "0.0.3"
8
+ s.version = "0.0.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Jeremiah Hemphill}]
12
- s.date = %q{2011-09-01}
12
+ s.date = %q{2011-11-08}
13
13
  s.description = %q{Adds tracking to rake tasks including error capturing and logging.}
14
14
  s.email = %q{jeremiah@cloudspace.com}
15
15
  s.extra_rdoc_files = [
@@ -26,7 +26,10 @@ Gem::Specification.new do |s|
26
26
  "README.rdoc",
27
27
  "Rakefile",
28
28
  "VERSION",
29
+ "app/controllers/trackable_tasks/task_runs_controller.rb",
29
30
  "app/models/trackable_tasks/task_run.rb",
31
+ "app/views/trackable_tasks/task_runs/index.html.erb",
32
+ "app/views/trackable_tasks/task_runs/show.html.erb",
30
33
  "config/routes.rb",
31
34
  "lib/generators/trackable_tasks/install_generator.rb",
32
35
  "lib/generators/trackable_tasks/templates/migrations/install_migration.rb.erb",
@@ -58,7 +61,11 @@ Gem::Specification.new do |s|
58
61
  "spec/dummy/db/migrate/20110826183240_create_trackable_task_tables.rb",
59
62
  "spec/dummy/db/schema.rb",
60
63
  "spec/dummy/features/step_definitions/trackable_tasks_steps.rb",
64
+ "spec/dummy/features/step_definitions/web_steps.rb",
61
65
  "spec/dummy/features/support/env.rb",
66
+ "spec/dummy/features/support/paths.rb",
67
+ "spec/dummy/features/support/selectors.rb",
68
+ "spec/dummy/features/task_run.feature",
62
69
  "spec/dummy/lib/tasks/trackable_tasks.rake",
63
70
  "spec/dummy/lib/trackable_tasks/my_task.rb",
64
71
  "spec/dummy/public/404.html",
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: trackable_tasks
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.3
5
+ version: 0.0.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jeremiah Hemphill
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-09-01 00:00:00 Z
13
+ date: 2011-11-08 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -196,7 +196,10 @@ files:
196
196
  - README.rdoc
197
197
  - Rakefile
198
198
  - VERSION
199
+ - app/controllers/trackable_tasks/task_runs_controller.rb
199
200
  - app/models/trackable_tasks/task_run.rb
201
+ - app/views/trackable_tasks/task_runs/index.html.erb
202
+ - app/views/trackable_tasks/task_runs/show.html.erb
200
203
  - config/routes.rb
201
204
  - lib/generators/trackable_tasks/install_generator.rb
202
205
  - lib/generators/trackable_tasks/templates/migrations/install_migration.rb.erb
@@ -228,7 +231,11 @@ files:
228
231
  - spec/dummy/db/migrate/20110826183240_create_trackable_task_tables.rb
229
232
  - spec/dummy/db/schema.rb
230
233
  - spec/dummy/features/step_definitions/trackable_tasks_steps.rb
234
+ - spec/dummy/features/step_definitions/web_steps.rb
231
235
  - spec/dummy/features/support/env.rb
236
+ - spec/dummy/features/support/paths.rb
237
+ - spec/dummy/features/support/selectors.rb
238
+ - spec/dummy/features/task_run.feature
232
239
  - spec/dummy/lib/tasks/trackable_tasks.rake
233
240
  - spec/dummy/lib/trackable_tasks/my_task.rb
234
241
  - spec/dummy/public/404.html
@@ -264,7 +271,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
264
271
  requirements:
265
272
  - - ">="
266
273
  - !ruby/object:Gem::Version
267
- hash: -445895761062619372
274
+ hash: 2905551140248170763
268
275
  segments:
269
276
  - 0
270
277
  version: "0"