cloudfactory 0.4.4 → 0.4.5

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.
@@ -61,7 +61,7 @@ module Cf
61
61
  # Checking Worker
62
62
  worker = station['station']['worker']
63
63
  if worker.class != Hash
64
- errors << "Worker is missing in Block station #{i+1}!"
64
+ errors << "Worker is missing in Block station #{i+1}!"
65
65
  return errors
66
66
  elsif worker.class == Hash
67
67
  # Checking Worker type
@@ -72,14 +72,14 @@ module Cf
72
72
  if worker_type.nil?
73
73
  errors << "Worker Type is missing!"
74
74
  else
75
- if worker_type != "human"
75
+ if worker_type != "human"
76
76
  errors << "Worker type is invalid in Block station #{i+1}!" if worker_type.split("_").last != "robot"
77
77
  if worker_type.split("_").last == "robot"
78
78
  settings = worker['settings']
79
79
  errors << "Settings for the robot worker is missing in Block station #{i+1}!" if settings.nil?
80
80
  errors << "Settings for the robot worker is invalid in Block station #{i+1}!" if settings.class != Hash
81
81
  end
82
- elsif worker_type == "human"
82
+ elsif worker_type == "human"
83
83
  # Checking number of workers if worker_type == "human"
84
84
  num_workers = worker['num_workers']
85
85
  if num_workers.nil?
@@ -91,7 +91,7 @@ module Cf
91
91
  # Checking reward of workers if worker_type == "human"
92
92
  reward = worker['reward']
93
93
  if reward.nil?
94
- errors << "Reward of workers not specified in Block station #{i+1}!"
94
+ errors << "Reward of workers not specified in Block station #{i+1}!"
95
95
  else
96
96
  errors << "Reward of workers must be greater than 0 in Block station #{i+1}!" if reward < 1
97
97
  end
@@ -106,29 +106,6 @@ module Cf
106
106
  errors << "Stat badge setting is invalid in Block station #{i+1}!" if stat_badge.class != Hash
107
107
  end
108
108
 
109
- # Checking skill_badge
110
- skill_badges = station['station']['worker']['skill_badges']
111
- if !skill_badges.nil?
112
- errors << "Skill badge settings is invalid in Block station #{i+1}!" if skill_badges.class != Array
113
- skill_badges.each_with_index do |badge, badge_index|
114
- badge_title = badge['title']
115
- badge_description = badge['description']
116
- max_badges = badge['max_badges']
117
- badge_test = badge['test']
118
- test_input = badge_test['input'] if badge_test.class == Hash
119
- expected_output = badge_test['expected_output'] if badge_test.class == Hash
120
- errors << "Skill badge title is Missing in Block #{badge_index+1}!" if badge_title.nil?
121
- errors << "Skill badge Description is Missing in Block #{badge_index+1}!" if badge_description.nil?
122
- errors << "Skill badge max_badges must be greater than 100 in Block #{badge_index+1}!" if max_badges < 100 && !max_badges.nil?
123
- errors << "Skill badge Test is Missing in Block #{badge_index+1}!" if badge_test.nil?
124
- errors << "Skill badge Test is Invalid (must be Hash) in Block #{badge_index+1}!" if badge_test.class != Hash && !badge_test.nil?
125
- errors << "Skill badge Test input is Missing in Block #{badge_index+1}!" if test_input.nil? && !badge_test.nil?
126
- errors << "Skill badge Test input is Invalid (must be Hash) in Block #{badge_index+1}!" if test_input.class != Hash && !test_input.nil? && !badge_test.nil?
127
- errors << "Skill badge Test expected_output is Missing in Block #{badge_index+1}!" if expected_output.nil? && !badge_test.nil?
128
- errors << "Skill badge Test expected_output is Invalid (must be an array) in Block #{badge_index+1}!" if expected_output.class != Array && !expected_output.nil? && !badge_test.nil?
129
- end
130
- end
131
-
132
109
  # Checking TaskForm
133
110
  if worker_type == "human"
134
111
  task_form = station['station']['task_form']
@@ -142,9 +119,9 @@ module Cf
142
119
 
143
120
  instruction = custom_task_form['instruction']
144
121
  errors << "Form Instruction is missing in Block station #{i+1}!" if instruction.nil?
145
-
122
+
146
123
  errors << "station#{i+1}.html is missing in folder #{Dir.pwd} !" if !File.exist?("station#{i+1}.html")
147
- #
124
+ #
148
125
  # if File.exist?("#{Dir.pwd}")
149
126
  # station_source = "#{Dir.pwd}/station_#{i+1}"
150
127
  # errors << "station#{i+1} is missing in folder #{Dir.pwd}/station_#{i+1} !" if !File.exist?("station#{i+1}.html")
@@ -176,7 +153,7 @@ module Cf
176
153
  errors << "Option values is required for field_type => #{field_type} in block #{index+1} of Form Field within Station #{i+1} !"
177
154
  elsif !option_values.nil?
178
155
  if option_values.class != Array
179
- errors << "Option values must be an array for field_type => #{field_type} in block #{index+1} of Form Field within Station #{i+1}!"
156
+ errors << "Option values must be an array for field_type => #{field_type} in block #{index+1} of Form Field within Station #{i+1}!"
180
157
  end
181
158
  end
182
159
  end
@@ -10,11 +10,65 @@ module Cf # :nodoc: all
10
10
  end
11
11
  end
12
12
 
13
- desc "production start <run-title>", "creates a production run with input data file at input/<run-title>.csv"
13
+ desc "production start_test <run-title> -g<number-of-goldstandrds-to-be-added>", "creates a production run with given line goldstandards as units"
14
+ method_option :gold_standards_inputs, :type => :string, :aliases => "-g", :desc => "number of goldstandard as input for the run"
15
+ method_option :live, :type => :boolean, :default => false, :desc => "specifies sandbox or live mode"
16
+ method_option :line, :type => :string, :aliases => "-l", :desc => "public line to use to do the production run. the format should be <account_name>/<line-title> e.g. millisami/brandiator"
17
+ def start_test(title=nil)
18
+ line_destination = Dir.pwd
19
+ yaml_source = "#{line_destination}/line.yml"
20
+
21
+ set_target_uri(options[:live])
22
+ set_api_key
23
+ CF.account_name = CF::Account.info['name']
24
+
25
+ if options[:line].present?
26
+ line = CF::Line.find(options[:line])
27
+ if line.nil?
28
+ say("Line named #{options[:line]} does not exist !!!", :red) and exit(1)
29
+ else
30
+ line = Hashie::Mash.new(line)
31
+ line_title = options[:line]
32
+ end
33
+ elsif File.exist?("#{yaml_source}")
34
+ line_yaml_dump = YAML::load(File.read(yaml_source).strip)
35
+ line_title = line_yaml_dump['title'].parameterize
36
+ line = CF::Line.find(line_title)
37
+ if line.nil?
38
+ say("Line named #{options[:line]} does not exist !!!", :red) and exit(1)
39
+ else
40
+ line = Hashie::Mash.new(line)
41
+ end
42
+ else
43
+ say("Looks like you're not in the Line directory or did not provide the line title to use the line", :red) and return
44
+ end
45
+
46
+ if title.nil?
47
+ if line_title =~ /\w\/\w/
48
+ run_title = "#{line_title.split("/").last}-#{Time.new.strftime('%Y%b%d-%H%M%S')}".downcase
49
+ else
50
+ run_title = "#{line_title}-#{Time.new.strftime('%Y%b%d-%H%M%S')}".downcase
51
+ end
52
+ else
53
+ run_title = "#{title.parameterize}-#{Time.new.strftime('%Y%b%d-%H%M%S')}".downcase
54
+ end
55
+
56
+ gold_standard_inputs = options[:gold_standards_inputs]
57
+ say "Creating a test production run with title #{run_title}", :green
58
+ run = CF::TestRun.new(line_title, run_title, gold_standard_inputs)
59
+ if run.errors.blank?
60
+ display_success_run(run)
61
+ else
62
+ say("Error: #{run.errors}", :red)
63
+ end
64
+
65
+ end
66
+
67
+ desc "production start <run-title>", "creates a production run with input data file at input/<run-title>.csv for more option 'cf production help start'"
14
68
  method_option :input_data, :type => :string, :aliases => "-i", :desc => "the name of the input data file"
15
69
  method_option :live, :type => :boolean, :default => false, :desc => "specifies sandbox or live mode"
16
70
  method_option :line, :type => :string, :aliases => "-l", :desc => "public line to use to do the production run. the format should be <account_name>/<line-title> e.g. millisami/brandiator"
17
- def start(title=nil)
71
+ def start(title=nil)
18
72
  line_destination = Dir.pwd
19
73
  yaml_source = "#{line_destination}/line.yml"
20
74
 
@@ -32,7 +86,7 @@ module Cf # :nodoc: all
32
86
  end
33
87
  elsif File.exist?("#{yaml_source}")
34
88
  line_yaml_dump = YAML::load(File.read(yaml_source).strip)
35
- line_title = line_yaml_dump['title'].parameterize
89
+ line_title = line_yaml_dump['title'].parameterize
36
90
  line = CF::Line.find(line_title)
37
91
  if line.nil?
38
92
  say("Line named #{options[:line]} does not exist !!!", :red) and exit(1)
@@ -162,7 +216,7 @@ module Cf # :nodoc: all
162
216
  if resp_runs.has_key?("total_runs") && resp_runs['total_runs']==0
163
217
  say("\nRun list is empty.\n", :yellow) and return
164
218
  end
165
-
219
+
166
220
  if resp_runs['total_pages']
167
221
  say("\nShowing page #{current_page} of #{resp_runs['total_pages']} (Total runs: #{resp_runs['total_runs']})")
168
222
  end
@@ -198,7 +252,7 @@ module Cf # :nodoc: all
198
252
  # if result.status == "resumed"
199
253
  say("Run with title \"#{result['title']}\" is resumed!", :green)
200
254
  # end
201
- end
255
+ end
202
256
 
203
257
  desc "production add_units", "add units to already existing production run"
204
258
  method_option :run_title, :type => :string, :required => true, :aliases => "-t", :desc => "the title of the run to resume"
@@ -223,12 +277,12 @@ module Cf # :nodoc: all
223
277
  if units.nil?
224
278
  say("Error: Invalid File!", :red) and exit(1)
225
279
  else
226
- if units['error'].present?
280
+ if units['error'].present?
227
281
  say("Error: #{units['error']['message']}", :red) and exit(1)
228
282
  end
229
283
  say("\"#{units['successfull']}\"!", :green)
230
284
  end
231
- end
285
+ end
232
286
 
233
287
  desc "production delete", "Deletes created Production Run"
234
288
  method_option :run_title, :type => :string, :required => true, :aliases => "-t", :desc => "the title of the run to resume"
@@ -237,12 +291,12 @@ module Cf # :nodoc: all
237
291
  set_api_key
238
292
  CF.account_name = CF::Account.info['name']
239
293
  run_title = options[:run_title].parameterize
240
-
294
+
241
295
  deleted_run = CF::Run.destroy(run_title)
242
296
  if deleted_run['error'].present?
243
297
  say("Error: #{deleted_run['error']['message']}", :red) and exit(1)
244
298
  end
245
299
  say("Run Deleted Successfully entitled: \"#{deleted_run['title']}\"!", :green)
246
- end
300
+ end
247
301
  end
248
302
  end
@@ -0,0 +1,74 @@
1
+ module CF
2
+ class GoldStandard
3
+ require 'httparty'
4
+ include Client
5
+
6
+ # goldstandard settings
7
+ attr_accessor :settings
8
+
9
+ #GoldStandard name
10
+ attr_accessor :name
11
+
12
+ # the input provided to the goldstandard
13
+ attr_accessor :input
14
+
15
+ # ExpectedOutput of the gold-standard with which the actual output is matched
16
+ attr_accessor :expected_output
17
+
18
+ # assignment_duration is the time period that is allocated for the badge test
19
+ attr_accessor :assignment_duration
20
+
21
+ # Contains error message
22
+ attr_accessor :errors
23
+
24
+
25
+ # ==Initializes a new gold standard
26
+ # ===Usage Example:
27
+ # CF::GoldStandard.new({ :line => line,:name => "easy",:input => [{'image_url' =>"http://onwired.com/images/portfolio/linda-stanley-business-card.jpg"}],:expected_output => [{"first_name" => {"value" => "John"}, "last_name" => {"value" => "Lennon"}, "company" => {"value" => "Sprout"}}]})
28
+ # line.gold_standards gold_standard
29
+
30
+ def initialize(options={})
31
+ @settings = options
32
+ @station = options[:station] if options[:station].present?
33
+ @line = options[:line] if options[:line].nil? ? nil : options[:line]
34
+ if !@line.nil? || @station
35
+ options.delete(:station) if @settings[:station].present?
36
+ options.delete(:line)
37
+ if options[:file] || options["file"]
38
+ options.symbolize_keys!
39
+ file_upload = File.new(options[:file], 'rb')
40
+ if @station
41
+ resp = self.class.post("/lines/#{CF.account_name}/#{@line.title.downcase}/stations/#{@station.index}/gold_standards.json", {:file => file_upload})
42
+ @station.gold_standards = self
43
+ else
44
+ resp = self.class.post("/lines/#{CF.account_name}/#{@line.title.downcase}/gold_standards.json", {:file => file_upload})
45
+ @line.gold_standards = self
46
+ end
47
+ else
48
+ request =
49
+ {
50
+ :body =>
51
+ {
52
+ :api_key => CF.api_key,
53
+ :gold_standard => options
54
+ }
55
+ }
56
+
57
+ if @station
58
+ resp = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{@line.title.downcase}/stations/#{@station.index}/gold_standards.json",request)
59
+ @station.gold_standards = self
60
+ else
61
+ resp = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{@line.title.downcase}/gold_standards.json",request)
62
+ @line.gold_standards = self
63
+ end
64
+ self.errors = resp.parsed_response['error']['message'] if resp.code != 200
65
+ end
66
+ end
67
+ end
68
+
69
+ def self.create(*args)
70
+ GoldStandard.new(args.first)
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,67 @@
1
+ Tasks:
2
+
3
+ Help:
4
+ Usage:
5
+ cf [command] help
6
+ Description:
7
+ Shows all help commands
8
+
9
+ Version
10
+ Usage:
11
+ cf version
12
+ Description:
13
+ Shows the current version of cloudfactory gem
14
+
15
+ UserInfo:
16
+ Usage:
17
+ cf whoami
18
+ Description:
19
+ to know what credential you are using
20
+
21
+ Login
22
+ Usage:
23
+ cf login
24
+ Description:
25
+ Setup the cloudfactory credentials
26
+
27
+ Form:
28
+ Usage:
29
+ cf form generate --fields=key:value --labels=LABELS --station=N # generates a custom task form at <line-title>/<form-title>.html and its associated css and js files
30
+ cf form preview -s, --station=N # generates a html file to preview the custom task form
31
+ Description:
32
+ Commands to generate custom task forms. For more info, cf form help
33
+ More:
34
+ cf form help [sub-command] #list all help related to form subcommands
35
+
36
+ Line:
37
+ Usage:
38
+ cf line create # takes the line.yml and creates a new line at http://cloudfactory.com
39
+ cf line delete # delete the current line at http://cloudfactory.com
40
+ cf line details # list the details of the line
41
+ cf line generate LINE-TITLE # generates a line template at <line-title>/line.yml
42
+ cf line list # List your lines
43
+ Description:
44
+ Commands to manage the Lines. For more info, cf line help
45
+ More:
46
+ cf line help [sub-command] #list all help related to line subcommands
47
+
48
+ Production:
49
+ Usage:
50
+ cf production add_units -i, --input-data=INPUT_DATA -t, --run-title=RUN_TITLE # add units to already existing production run
51
+ cf production delete -t, --run-title=RUN_TITLE # Deletes created Production Run
52
+ cf production list # list the production runs
53
+ cf production resume -r, --run-title=RUN_TITLE # resume a paused production run
54
+ cf production start <run-title> # creates a production run with input data file at input/<run-title>.csv
55
+ cf production start_test <run-title> -g<number-of-goldstandrds-to-be-added> # creates a production run with given line goldstandards as units
56
+ Description:
57
+ Commands to create production runs. For more info, cf production help
58
+ More:
59
+ cf production help [sub-command] #list all help related to production subcommands
60
+
61
+ Output:
62
+ Usage:
63
+ cf output <run-title> -t, --run-title=RUN_TITLE
64
+ Description:
65
+ Get the output of run. For more info, cf output help
66
+ More:
67
+ cf output help [sub-command] #list all help related to output subcommands
@@ -3,33 +3,33 @@ module CF
3
3
  include Client
4
4
  require 'httparty'
5
5
  extend ActiveSupport::Concern
6
-
6
+
7
7
  # ID of "Worker" object
8
8
  attr_accessor :id
9
-
9
+
10
10
  # Number of worker, e.g. :number => 3
11
11
  attr_accessor :number
12
-
12
+
13
13
  # Reward for worker, e.g. :reward => 10 (reward unit is in cents)
14
14
  attr_accessor :reward
15
-
15
+
16
16
  # Station attribute for "worker" object
17
17
  attr_accessor :station
18
-
18
+
19
19
  # Stat Badge for "worker" object, e.g. worker = CF::HumanWorker.new({:number => 2, :reward => 20, :stat_badge => {:approval_rating => 40, :assignment_duration => 1800, :abandonment_rate => 30}})
20
20
  attr_accessor :stat_badge
21
-
21
+
22
22
  # Skill Badge for "worker" object
23
23
  # example:
24
- # badge_settings =
24
+ # badge_settings =
25
25
  # {
26
- # :title => 'Football Fanatic',
27
- # :description => "This qualification allows you to perform work at stations which have this badge.",
28
- # :max_badges => 3,
29
- # :test =>
26
+ # :title => 'Football Fanatic',
27
+ # :description => "This qualification allows you to perform work at stations which have this badge.",
28
+ # :max_badges => 3,
29
+ # :test =>
30
30
  # {
31
31
  # :input => {:name => "Lionel Andres Messi", :country => "Argentina"},
32
- # :expected_output =>
32
+ # :expected_output =>
33
33
  # [
34
34
  # {:birthplace => "Rosario, Santa Fe, Argentina",:match_options => {:tolerance => 10, :ignore_case => true }},
35
35
  # {:position => "CF",:match_options => {:tolerance => 1 }},
@@ -39,72 +39,68 @@ module CF
39
39
  # }
40
40
  #
41
41
  # worker = CF::HumanWorker.new({:number => 2, :reward => 20, :skill_badge => badge_settings})
42
- attr_accessor :skill_badges
43
-
42
+ # attr_accessor :skill_badges
43
+
44
44
  # Contains Error messages if any for "worker" object
45
45
  attr_accessor :errors
46
-
46
+
47
47
  # Badge setting for "worker" object
48
48
  attr_accessor :badge
49
-
50
- # ==Initializes a new "worker" object
49
+
50
+ # ==Initializes a new "worker" object
51
51
  # ==Usage of HumanWorker.new(hash):
52
52
  #
53
- # ==In Block DSL way
54
- # line = CF::Line.create("human_worker", "Survey") do |l|
53
+ # ==In Block DSL way
54
+ # line = CF::Line.create("human_worker", "Survey") do |l|
55
55
  # CF::Station.create({:line => l, :type => "work"}) do |s|
56
56
  # CF::HumanWorker.new({:station => s, :number => 1, :reward => 10})
57
57
  # end
58
58
  # end
59
59
  #
60
- # ==In Plain Ruby way
60
+ # ==In Plain Ruby way
61
61
  # line = CF::Line.new("human_worker", "Digitization")
62
62
  # input_format = CF::InputFormat.new({:name => "image_url", :required => true, :valid_type => "url"})
63
63
  # line.input_formats input_format
64
- #
64
+ #
65
65
  # station = CF::Station.new({:type => "work"})
66
66
  # line.stations station
67
- #
67
+ #
68
68
  # worker = CF::HumanWorker.new({:number => 2, :reward => 20})
69
69
  # line.stations.first.worker = worker
70
-
70
+
71
71
  def initialize(options={})
72
- @skill_badges = []
73
72
  @station = options[:station]
74
73
  @number = options[:number].nil? ? 1 : options[:number]
75
74
  @reward = options[:reward]
76
- @badge = options[:skill_badge].nil? ? nil : options[:skill_badge]
77
75
  @stat_badge = options[:stat_badge].nil? ? nil : options[:stat_badge]
78
76
  if @station
79
- if options[:skill_badge].nil? && options[:stat_badge].nil?
80
- request =
77
+ if options[:stat_badge].nil?
78
+ request =
81
79
  {
82
- :body =>
80
+ :body =>
83
81
  {
84
82
  :api_key => CF.api_key,
85
83
  :worker => {:number => @number, :reward => @reward, :type => "HumanWorker"}
86
84
  }
87
85
  }
88
86
  else
89
- request =
87
+ request =
90
88
  {
91
- :body =>
89
+ :body =>
92
90
  {
93
91
  :api_key => CF.api_key,
94
92
  :worker => {:number => @number, :reward => @reward, :type => "HumanWorker"},
95
- :skill_badge => @badge,
96
93
  :stat_badge => options[:stat_badge]
97
94
  }
98
95
  }
99
96
  end
100
97
  resp = HTTParty.post("#{CF.api_url}#{CF.api_version}/lines/#{CF.account_name}/#{@station.line['title'].downcase}/stations/#{@station.index}/workers.json",request)
101
-
98
+
102
99
  self.id = resp.parsed_response['id']
103
100
  self.number = resp.parsed_response['number']
104
101
  self.reward = resp.parsed_response['reward']
105
- self.stat_badge = resp.parsed_response['stat_badge']
106
- @skill_badges << resp.parsed_response['skill_badges']
107
-
102
+ self.stat_badge = resp.parsed_response['stat_badge']
103
+
108
104
  if resp.code != 200
109
105
  self.errors = resp.parsed_response['error']['message']
110
106
  end
@@ -112,19 +108,19 @@ module CF
112
108
  self.station.worker = self
113
109
  end
114
110
  end
115
-
111
+
116
112
  # ==Creation a new "worker" object with Badge
117
113
  # ==Usage Example:
118
- # ==In Plain Ruby way
119
- # badge_settings =
114
+ # ==In Plain Ruby way
115
+ # badge_settings =
120
116
  # {
121
- # :title => 'Football Fanatic',
122
- # :description => "This qualification allows you to perform work at stations which have this badge.",
123
- # :max_badges => 3,
124
- # :test =>
117
+ # :title => 'Football Fanatic',
118
+ # :description => "This qualification allows you to perform work at stations which have this badge.",
119
+ # :max_badges => 3,
120
+ # :test =>
125
121
  # {
126
122
  # :input => {:name => "Lionel Andres Messi", :country => "Argentina"},
127
- # :expected_output =>
123
+ # :expected_output =>
128
124
  # [
129
125
  # {:birthplace => "Rosario, Santa Fe, Argentina",:match_options => {:tolerance => 10, :ignore_case => true }},
130
126
  # {:position => "CF",:match_options => {:tolerance => 1 }},
@@ -135,18 +131,18 @@ module CF
135
131
  # line = CF::Line.new("human_worker", "Digitization")
136
132
  # input_format = CF::InputFormat.new({:name => "image_url", :required => true, :valid_type => "url"})
137
133
  # line.input_formats input_format
138
- #
134
+ #
139
135
  # station = CF::Station.new({:type => "work"})
140
136
  # line.stations station
141
- #
137
+ #
142
138
  # worker = CF::HumanWorker.new({:number => 2, :reward => 20, :skill_badge => skill_badge})
143
139
  # line.stations.first.worker = worker
144
140
  #
145
141
  # line.stations.first.worker.badge = badge_settings
146
142
  def badge=(badge)
147
- request =
143
+ request =
148
144
  {
149
- :body =>
145
+ :body =>
150
146
  {
151
147
  :api_key => CF.api_key,
152
148
  :skill_badge => badge
@@ -156,9 +152,9 @@ module CF
156
152
  self.errors = resp['error']['message'] if resp.code != 200
157
153
  self.skill_badges << resp.parsed_response['skill_badges']
158
154
  end
159
-
155
+
160
156
  def to_s # :nodoc:
161
- "{:id => => #{self.id}, :number => #{self.number}, :reward => #{self.reward}, :stat_badge => #{self.stat_badge}, :skill_badges => #{self.skill_badges}, :errors => #{self.errors}}"
157
+ "{:id => => #{self.id}, :number => #{self.number}, :reward => #{self.reward}, :stat_badge => #{self.stat_badge}, :errors => #{self.errors}}"
162
158
  end
163
159
  end
164
160
  end