marathon-api 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.simplecov +2 -2
- data/.travis.yml +1 -1
- data/README.md +40 -14
- data/bin/marathon +242 -0
- data/fixtures/marathon_docker_sample_2.json +2 -1
- data/fixtures/vcr/Marathon_App/_restart/restarts_an_app.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_changes/changes_the_group.yml +61 -0
- data/fixtures/vcr/Marathon_Group/_delete/deletes_the_group.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_delete/fails_deleting_not_existing_app.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_get/fails_getting_not_existing_app.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_get/gets_the_group.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_list/lists_apps.yml +33 -0
- data/fixtures/vcr/Marathon_Group/_start/fails_getting_not_existing_group.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_start/starts_the_group.yml +35 -0
- data/lib/marathon.rb +33 -5
- data/lib/marathon/app.rb +72 -22
- data/lib/marathon/base.rb +32 -0
- data/lib/marathon/connection.rb +32 -22
- data/lib/marathon/constraint.rb +39 -0
- data/lib/marathon/container.rb +41 -0
- data/lib/marathon/container_docker.rb +33 -0
- data/lib/marathon/container_docker_port_mapping.rb +32 -0
- data/lib/marathon/container_volume.rb +31 -0
- data/lib/marathon/deployment.rb +5 -15
- data/lib/marathon/deployment_info.rb +20 -0
- data/lib/marathon/error.rb +8 -2
- data/lib/marathon/group.rb +166 -0
- data/lib/marathon/health_check.rb +35 -0
- data/lib/marathon/queue.rb +4 -13
- data/lib/marathon/task.rb +15 -12
- data/lib/marathon/util.rb +47 -3
- data/lib/marathon/version.rb +1 -1
- data/marathon-api.gemspec +4 -3
- data/spec/marathon/app_spec.rb +108 -50
- data/spec/marathon/base_spec.rb +53 -0
- data/spec/marathon/connection_spec.rb +1 -1
- data/spec/marathon/constraint_spec.rb +27 -0
- data/spec/marathon/container_docker_port_mapping_spec.rb +55 -0
- data/spec/marathon/container_docker_spec.rb +42 -0
- data/spec/marathon/container_spec.rb +40 -0
- data/spec/marathon/container_volume_spec.rb +50 -0
- data/spec/marathon/deployment_info_spec.rb +43 -0
- data/spec/marathon/deployment_spec.rb +15 -16
- data/spec/marathon/error_spec.rb +17 -0
- data/spec/marathon/group_spec.rb +172 -0
- data/spec/marathon/health_check_spec.rb +50 -0
- data/spec/marathon/marathon_spec.rb +31 -0
- data/spec/marathon/queue_spec.rb +2 -2
- data/spec/marathon/task_spec.rb +24 -11
- data/spec/marathon/util_spec.rb +21 -1
- metadata +58 -6
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: delete
|
5
|
+
uri: http://localhost:8080/v2/groups//test-group?force=true
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- ub0r/Marathon-API 0.9.0
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json
|
23
|
+
Transfer-Encoding:
|
24
|
+
- chunked
|
25
|
+
Server:
|
26
|
+
- Jetty(8.y.z-SNAPSHOT)
|
27
|
+
body:
|
28
|
+
encoding: UTF-8
|
29
|
+
string: '{"version":"2015-03-09T10:33:40.335Z","deploymentId":"c5ad3775-a422-48f0-99ee-e7e7f098a832"}'
|
30
|
+
http_version:
|
31
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
32
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: delete
|
5
|
+
uri: http://localhost:8080/v2/groups/fooo%20group
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- ub0r/Marathon-API 0.9.0
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 404
|
19
|
+
message: Not Found
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json
|
23
|
+
Transfer-Encoding:
|
24
|
+
- chunked
|
25
|
+
Server:
|
26
|
+
- Jetty(8.y.z-SNAPSHOT)
|
27
|
+
body:
|
28
|
+
encoding: UTF-8
|
29
|
+
string: '{"message":"Group ''/fooo group'' does not exist"}'
|
30
|
+
http_version:
|
31
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
32
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:8080/v2/groups/fooo%20group
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- ub0r/Marathon-API 0.9.0
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 404
|
19
|
+
message: Not Found
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json
|
23
|
+
Transfer-Encoding:
|
24
|
+
- chunked
|
25
|
+
Server:
|
26
|
+
- Jetty(8.y.z-SNAPSHOT)
|
27
|
+
body:
|
28
|
+
encoding: UTF-8
|
29
|
+
string: '{"message":"Group ''/fooo group'' does not exist"}'
|
30
|
+
http_version:
|
31
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
32
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:8080/v2/groups//test-group
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- ub0r/Marathon-API 0.9.0
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json
|
23
|
+
Transfer-Encoding:
|
24
|
+
- chunked
|
25
|
+
Server:
|
26
|
+
- Jetty(8.y.z-SNAPSHOT)
|
27
|
+
body:
|
28
|
+
encoding: UTF-8
|
29
|
+
string: '{"id":"/test-group","apps":[{"id":"/test-group/app","cmd":"sleep 30","args":null,"user":null,"env":{},"instances":1,"cpus":1.0,"mem":128.0,"disk":0.0,"executor":"","constraints":[],"uris":[],"storeUrls":[],"ports":[10000],"requirePorts":false,"backoffSeconds":1,"backoffFactor":1.15,"maxLaunchDelaySeconds":3600,"container":null,"healthChecks":[],"dependencies":[],"upgradeStrategy":{"minimumHealthCapacity":1.0,"maximumOverCapacity":0.0},"labels":{},"version":"2015-03-09T10:33:39.889Z"}],"groups":[],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"}'
|
30
|
+
http_version:
|
31
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
32
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:8080/v2/groups
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- ub0r/Marathon-API 0.9.0
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json
|
23
|
+
Transfer-Encoding:
|
24
|
+
- chunked
|
25
|
+
Server:
|
26
|
+
- Jetty(8.y.z-SNAPSHOT)
|
27
|
+
body:
|
28
|
+
encoding: UTF-8
|
29
|
+
string: '{"id":"/","apps":[],"groups":[{"id":"/ubuntu2","apps":[],"groups":[],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"},{"id":"/test-group","apps":[{"id":"/test-group/app","cmd":"sleep
|
30
|
+
30","args":null,"user":null,"env":{},"instances":1,"cpus":1.0,"mem":128.0,"disk":0.0,"executor":"","constraints":[],"uris":[],"storeUrls":[],"ports":[10000],"requirePorts":false,"backoffSeconds":1,"backoffFactor":1.15,"maxLaunchDelaySeconds":3600,"container":null,"healthChecks":[],"dependencies":[],"upgradeStrategy":{"minimumHealthCapacity":1.0,"maximumOverCapacity":0.0},"labels":{},"version":"2015-03-09T10:33:39.889Z"}],"groups":[],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"}],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"}'
|
31
|
+
http_version:
|
32
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
33
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:8080/v2/groups/fooo%20group
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- ub0r/Marathon-API 0.9.0
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 404
|
19
|
+
message: Not Found
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json
|
23
|
+
Transfer-Encoding:
|
24
|
+
- chunked
|
25
|
+
Server:
|
26
|
+
- Jetty(8.y.z-SNAPSHOT)
|
27
|
+
body:
|
28
|
+
encoding: UTF-8
|
29
|
+
string: '{"message":"Group ''/fooo group'' does not exist"}'
|
30
|
+
http_version:
|
31
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
32
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: http://localhost:8080/v2/groups
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"id":"/test-group","apps":[{"backoffFactor":1.15,"backoffSeconds":1,"maxLaunchDelaySeconds":3600,"cmd":"sleep
|
9
|
+
30","constraints":[],"cpus":1.0,"dependencies":[],"disk":0.0,"env":{},"executor":"","id":"app","instances":1,"mem":128.0,"ports":[10000],"requirePorts":false,"storeUrls":[],"upgradeStrategy":{"minimumHealthCapacity":1.0},"tasks":[]}],"dependencies":[],"groups":[]}'
|
10
|
+
headers:
|
11
|
+
Content-Type:
|
12
|
+
- application/json
|
13
|
+
Accept:
|
14
|
+
- application/json
|
15
|
+
User-Agent:
|
16
|
+
- ub0r/Marathon-API 0.9.0
|
17
|
+
response:
|
18
|
+
status:
|
19
|
+
code: 201
|
20
|
+
message: Created
|
21
|
+
headers:
|
22
|
+
Location:
|
23
|
+
- http://localhost:8080/v2/groups/test-group
|
24
|
+
Content-Type:
|
25
|
+
- application/json
|
26
|
+
Transfer-Encoding:
|
27
|
+
- chunked
|
28
|
+
Server:
|
29
|
+
- Jetty(8.y.z-SNAPSHOT)
|
30
|
+
body:
|
31
|
+
encoding: UTF-8
|
32
|
+
string: '{"version":"2015-03-09T10:33:39.889Z","deploymentId":"ad618509-e8ee-4949-8267-ef35a619426f"}'
|
33
|
+
http_version:
|
34
|
+
recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
|
35
|
+
recorded_with: VCR 2.9.3
|
data/lib/marathon.rb
CHANGED
@@ -9,16 +9,25 @@ module Marathon
|
|
9
9
|
|
10
10
|
attr_accessor :logger
|
11
11
|
|
12
|
+
require 'marathon/version'
|
12
13
|
require 'marathon/util'
|
13
14
|
require 'marathon/error'
|
14
15
|
require 'marathon/connection'
|
16
|
+
require 'marathon/base'
|
17
|
+
require 'marathon/constraint'
|
18
|
+
require 'marathon/container_docker_port_mapping'
|
19
|
+
require 'marathon/container_docker'
|
20
|
+
require 'marathon/container_volume'
|
21
|
+
require 'marathon/container'
|
22
|
+
require 'marathon/health_check'
|
23
|
+
require 'marathon/deployment_info'
|
24
|
+
require 'marathon/group'
|
15
25
|
require 'marathon/app'
|
16
26
|
require 'marathon/deployment'
|
17
27
|
require 'marathon/event_subscriptions'
|
18
28
|
require 'marathon/leader'
|
19
29
|
require 'marathon/queue'
|
20
30
|
require 'marathon/task'
|
21
|
-
require 'marathon/version'
|
22
31
|
|
23
32
|
DEFAULT_URL = 'http://localhost:8080'
|
24
33
|
|
@@ -27,21 +36,40 @@ module Marathon
|
|
27
36
|
ENV['MARATHON_URL']
|
28
37
|
end
|
29
38
|
|
30
|
-
# Get
|
39
|
+
# Get marathon options from environment
|
40
|
+
def env_options
|
41
|
+
opts = {}
|
42
|
+
opts[:username] = ENV['MARATHON_USER'] if ENV['MARATHON_USER']
|
43
|
+
opts[:password] = ENV['MARATHON_PASSWORD'] if ENV['MARATHON_PASSWORD']
|
44
|
+
opts
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get the marathon API URL
|
31
48
|
def url
|
32
49
|
@url ||= env_url || DEFAULT_URL
|
33
50
|
@url
|
34
51
|
end
|
35
52
|
|
53
|
+
# Get options for connecting to marathon API
|
54
|
+
def options
|
55
|
+
@options ||= env_options
|
56
|
+
end
|
57
|
+
|
36
58
|
# Set a new url
|
37
59
|
def url=(new_url)
|
38
60
|
@url = new_url
|
39
61
|
reset_connection!
|
40
62
|
end
|
41
63
|
|
64
|
+
# Set new options
|
65
|
+
def options=(new_options)
|
66
|
+
@options = env_options.merge(new_options || {})
|
67
|
+
reset_connection!
|
68
|
+
end
|
69
|
+
|
42
70
|
# Set a new connection
|
43
71
|
def connection
|
44
|
-
@connection ||= Connection.new(url)
|
72
|
+
@connection ||= Connection.new(url, options)
|
45
73
|
end
|
46
74
|
|
47
75
|
# Reset the connection
|
@@ -59,7 +87,7 @@ module Marathon
|
|
59
87
|
connection.get('/ping')
|
60
88
|
end
|
61
89
|
|
62
|
-
module_function :connection, :env_url, :info, :logger, :logger=,
|
63
|
-
:
|
90
|
+
module_function :connection, :env_options, :env_url, :info, :logger, :logger=, :ping,
|
91
|
+
:options, :options=, :url, :url= ,:reset_connection!
|
64
92
|
|
65
93
|
end
|
data/lib/marathon/app.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
# This class represents a Marathon App.
|
2
2
|
# See https://mesosphere.github.io/marathon/docs/rest-api.html#apps for full list of API's methods.
|
3
|
-
class Marathon::App
|
3
|
+
class Marathon::App < Marathon::Base
|
4
4
|
|
5
|
-
|
5
|
+
ACCESSORS = %w[ id args cmd cpus disk env executor instances mem ports requirePorts
|
6
|
+
storeUris tasksRunning tasksStaged uris user version ]
|
7
|
+
|
8
|
+
DEFAULTS = {
|
9
|
+
:constraints => [],
|
10
|
+
:env => {},
|
11
|
+
:ports => [],
|
12
|
+
:uris => []
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_reader :read_only
|
6
16
|
|
7
17
|
# Create a new application object.
|
8
18
|
# ++hash++: Hash including all attributes.
|
9
19
|
# See https://mesosphere.github.io/marathon/docs/rest-api.html#post-/v2/apps for full details.
|
10
20
|
# ++read_only++: prevent actions on this application
|
11
|
-
def initialize(hash
|
12
|
-
|
21
|
+
def initialize(hash, read_only = false)
|
22
|
+
super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
|
23
|
+
raise ArgumentError, 'App must have an id' unless id
|
13
24
|
@read_only = read_only
|
14
25
|
end
|
15
26
|
|
16
|
-
# Shortcuts for reaching attributes
|
17
|
-
%w[ id args cmd cpus disk env executor instances mem ports requirePorts
|
18
|
-
storeUris tasksRunning tasksStaged uris user version ].each do |method|
|
19
|
-
define_method(method) { |*args, &block| info[method] }
|
20
|
-
end
|
21
|
-
|
22
27
|
# Prevent actions on read only instances.
|
23
28
|
# Raises an ArgumentError when triying to change read_only instances.
|
24
29
|
def check_read_only
|
@@ -27,17 +32,38 @@ class Marathon::App
|
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
35
|
+
# Get container info.
|
36
|
+
# This is read only!
|
37
|
+
def container
|
38
|
+
if @info[:container]
|
39
|
+
Marathon::Container.new(@info[:container])
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get constrains.
|
46
|
+
# This is read only!
|
47
|
+
def constraints
|
48
|
+
@info[:constraints].map { |e| Marathon::Constraint.new(e) }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get health checks.
|
52
|
+
# This is read only!
|
53
|
+
def healthChecks
|
54
|
+
@info[:healthChecks].map { |e| Marathon::HealthCheck.new(e) }
|
55
|
+
end
|
56
|
+
|
30
57
|
# List all running tasks for the application.
|
31
|
-
#
|
58
|
+
# This is read only!
|
32
59
|
def tasks
|
33
60
|
check_read_only
|
34
|
-
unless @info[
|
61
|
+
unless @info[:tasks]
|
35
62
|
refresh
|
36
63
|
end
|
37
64
|
|
38
|
-
raise
|
39
|
-
|
40
|
-
@info['tasks'].map { |e| Marathon::Task.new(e) }
|
65
|
+
raise UnexpectedResponseError, "Expected to find tasks element in app's info" unless @info[:tasks]
|
66
|
+
@info[:tasks].map { |e| Marathon::Task.new(e) }
|
41
67
|
end
|
42
68
|
|
43
69
|
# List the versions of the application.
|
@@ -111,12 +137,36 @@ class Marathon::App
|
|
111
137
|
end
|
112
138
|
|
113
139
|
def to_s
|
114
|
-
"Marathon::App { :id => #{
|
140
|
+
"Marathon::App { :id => #{id} }"
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns a string for listing the application.
|
144
|
+
def to_pretty_s
|
145
|
+
%Q[
|
146
|
+
App ID: #{id}
|
147
|
+
Instances: #{tasks.size}/#{instances}
|
148
|
+
Command: #{cmd}
|
149
|
+
CPUs: #{cpus}
|
150
|
+
Memory: #{mem} MB
|
151
|
+
#{pretty_uris()}
|
152
|
+
#{pretty_env()}
|
153
|
+
#{pretty_constraints()}
|
154
|
+
Version: #{version}
|
155
|
+
].gsub(/\n\n+/, "\n").strip
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def pretty_env
|
161
|
+
env.map { |k,v| "ENV: #{k}=#{v}" }.join("\n")
|
162
|
+
end
|
163
|
+
|
164
|
+
def pretty_uris
|
165
|
+
uris.map { |e| "URI: #{e}" }.join("\n")
|
115
166
|
end
|
116
167
|
|
117
|
-
|
118
|
-
|
119
|
-
info.to_json
|
168
|
+
def pretty_constraints
|
169
|
+
constraints.map { |e| "Constraint: #{e.to_pretty_s}" }.join("\n")
|
120
170
|
end
|
121
171
|
|
122
172
|
class << self
|
@@ -166,7 +216,7 @@ class Marathon::App
|
|
166
216
|
query = {}
|
167
217
|
query[:force] = true if force
|
168
218
|
json = Marathon.connection.post("/v2/apps/#{id}/restart", query)
|
169
|
-
|
219
|
+
Marathon::DeploymentInfo.new(json)
|
170
220
|
end
|
171
221
|
|
172
222
|
# Change parameters of a running application. The new application parameters apply only to subsequently
|
@@ -179,7 +229,7 @@ class Marathon::App
|
|
179
229
|
query = {}
|
180
230
|
query[:force] = true if force
|
181
231
|
json = Marathon.connection.put("/v2/apps/#{id}", query, :body => hash)
|
182
|
-
|
232
|
+
Marathon::DeploymentInfo.new(json)
|
183
233
|
end
|
184
234
|
|
185
235
|
# List the versions of the application with id.
|
@@ -197,4 +247,4 @@ class Marathon::App
|
|
197
247
|
new(json, true)
|
198
248
|
end
|
199
249
|
end
|
200
|
-
end
|
250
|
+
end
|