riot 0.12.1 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.gitignore +10 -0
  2. data/.yardopts +6 -0
  3. data/CHANGELOG +58 -46
  4. data/Gemfile +4 -0
  5. data/README.markdown +322 -85
  6. data/Rakefile +3 -38
  7. data/lib/riot.rb +74 -11
  8. data/lib/riot/assertion.rb +32 -1
  9. data/lib/riot/assertion_macro.rb +57 -10
  10. data/lib/riot/assertion_macros/any.rb +4 -2
  11. data/lib/riot/assertion_macros/assigns.rb +18 -4
  12. data/lib/riot/assertion_macros/empty.rb +2 -0
  13. data/lib/riot/assertion_macros/equals.rb +4 -0
  14. data/lib/riot/assertion_macros/equivalent_to.rb +5 -1
  15. data/lib/riot/assertion_macros/exists.rb +4 -2
  16. data/lib/riot/assertion_macros/includes.rb +5 -1
  17. data/lib/riot/assertion_macros/kind_of.rb +5 -1
  18. data/lib/riot/assertion_macros/matches.rb +5 -1
  19. data/lib/riot/assertion_macros/nil.rb +3 -1
  20. data/lib/riot/assertion_macros/not_borat.rb +6 -0
  21. data/lib/riot/assertion_macros/raises.rb +13 -7
  22. data/lib/riot/assertion_macros/respond_to.rb +5 -1
  23. data/lib/riot/assertion_macros/same_elements.rb +6 -2
  24. data/lib/riot/assertion_macros/size.rb +5 -1
  25. data/lib/riot/context.rb +58 -10
  26. data/lib/riot/context_helpers.rb +20 -4
  27. data/lib/riot/context_options.rb +14 -4
  28. data/lib/riot/message.rb +87 -6
  29. data/lib/riot/middleware.rb +69 -4
  30. data/lib/riot/reporter.rb +71 -110
  31. data/lib/riot/reporter/dot_matrix.rb +49 -0
  32. data/lib/riot/reporter/io.rb +85 -0
  33. data/lib/riot/reporter/pretty_dot_matrix.rb +38 -0
  34. data/lib/riot/reporter/silent.rb +18 -0
  35. data/lib/riot/reporter/story.rb +52 -0
  36. data/lib/riot/rr.rb +28 -4
  37. data/lib/riot/runnable.rb +53 -0
  38. data/lib/riot/situation.rb +45 -0
  39. data/lib/riot/version.rb +4 -0
  40. data/riot.gemspec +14 -155
  41. data/test/core/assertion_macros/any_test.rb +10 -10
  42. data/test/core/assertion_macros/assigns_test.rb +7 -7
  43. data/test/core/assertion_macros/equivalent_to_test.rb +3 -3
  44. data/test/core/assertion_macros/exists_test.rb +4 -4
  45. data/test/core/assertion_macros/includes_test.rb +2 -2
  46. data/test/core/assertion_macros/kind_of_test.rb +3 -3
  47. data/test/core/assertion_macros/matches_test.rb +2 -2
  48. data/test/core/assertion_macros/nil_test.rb +2 -2
  49. data/test/core/assertion_macros/raises_test.rb +10 -10
  50. data/test/core/assertion_macros/respond_to_test.rb +2 -2
  51. data/test/core/assertion_macros/same_elements_test.rb +4 -4
  52. data/test/core/assertion_macros/size_test.rb +6 -6
  53. data/test/core/context/asserts_with_arguments_test.rb +12 -0
  54. data/test/core/context/using_describe_in_a_test.rb +1 -1
  55. data/test/core/report_test.rb +9 -5
  56. data/test/core/runnable/message_test.rb +10 -6
  57. data/test/teststrap.rb +0 -6
  58. metadata +20 -33
  59. data/TODO.markdown +0 -14
  60. data/VERSION +0 -1
  61. data/test.watchr +0 -70
  62. data/test/benchmark/colorize.rb +0 -39
@@ -16,12 +16,14 @@ module Riot
16
16
  class ExistsMacro < AssertionMacro
17
17
  register :exists
18
18
 
19
+ # (see Riot::AssertionMacro#evaluate)
19
20
  def evaluate(actual)
20
- actual.nil? ? fail("expected a non-nil value") : pass("is not nil")
21
+ actual.nil? ? fail("expected a non-nil value") : pass("does exist")
21
22
  end
22
23
 
24
+ # (see Riot::AssertionMacro#devaluate)
23
25
  def devaluate(actual)
24
- actual.nil? ? pass("is nil") : fail("expected a nil value")
26
+ actual.nil? ? pass("does exist") : fail("expected a nil value")
25
27
  end
26
28
  end
27
29
  end
@@ -13,6 +13,8 @@ module Riot
13
13
  class IncludesMacro < AssertionMacro
14
14
  register :includes
15
15
 
16
+ # (see Riot::AssertionMacro#evaluate)
17
+ # @param [Object] expected the object that is expected to be included
16
18
  def evaluate(actual, expected)
17
19
  if actual.include?(expected)
18
20
  pass new_message.includes(expected)
@@ -21,11 +23,13 @@ module Riot
21
23
  end
22
24
  end
23
25
 
26
+ # (see Riot::AssertionMacro#devaluate)
27
+ # @param [Object] expected the object that is not expected to be included
24
28
  def devaluate(actual, expected)
25
29
  if actual.include?(expected)
26
30
  fail expected_message(actual).to_not_include(expected)
27
31
  else
28
- pass new_message.does_not_include(expected)
32
+ pass new_message.includes(expected)
29
33
  end
30
34
  end
31
35
 
@@ -10,6 +10,8 @@ module Riot
10
10
  class KindOfMacro < AssertionMacro
11
11
  register :kind_of
12
12
 
13
+ # (see Riot::AssertionMacro#evaluate)
14
+ # @param [Class] expected the expected class of actual
13
15
  def evaluate(actual, expected)
14
16
  if actual.kind_of?(expected)
15
17
  pass new_message.is_a_kind_of(expected)
@@ -18,11 +20,13 @@ module Riot
18
20
  end
19
21
  end
20
22
 
23
+ # (see Riot::AssertionMacro#devaluate)
24
+ # @param [Class] expected the unexpected class of actual
21
25
  def devaluate(actual, expected)
22
26
  if actual.kind_of?(expected)
23
27
  fail expected_message.not_kind_of(expected).not(actual.class)
24
28
  else
25
- pass new_message.is_not_a_kind_of(expected)
29
+ pass new_message.is_a_kind_of(expected)
26
30
  end
27
31
  end
28
32
  end
@@ -10,6 +10,8 @@ module Riot
10
10
  class MatchesMacro < AssertionMacro
11
11
  register :matches
12
12
 
13
+ # (see Riot::AssertionMacro#evaluate)
14
+ # @param [Regex, String] expected the string or regex to be used in comparison
13
15
  def evaluate(actual, expected)
14
16
  expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
15
17
  if actual.to_s =~ expected
@@ -19,12 +21,14 @@ module Riot
19
21
  end
20
22
  end
21
23
 
24
+ # (see Riot::AssertionMacro#devaluate)
25
+ # @param [Regex, String] expected the string or regex to be used in comparison
22
26
  def devaluate(actual, expected)
23
27
  expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
24
28
  if actual.to_s =~ expected
25
29
  fail(expected_message(expected).not_to_match(actual))
26
30
  else
27
- pass(new_message.does_not_match(expected))
31
+ pass(new_message.matches(expected))
28
32
  end
29
33
  end
30
34
  end
@@ -11,12 +11,14 @@ module Riot
11
11
  class NilMacro < AssertionMacro
12
12
  register :nil
13
13
 
14
+ # (see Riot::AssertionMacro#evaluate)
14
15
  def evaluate(actual)
15
16
  actual.nil? ? pass("is nil") : fail(expected_message.nil.not(actual))
16
17
  end
17
18
 
19
+ # (see Riot::AssertionMacro#devaluate)
18
20
  def devaluate(actual)
19
- actual.nil? ? fail(expected_message.is_nil.not('non-nil')) : pass("is not nil")
21
+ actual.nil? ? fail(expected_message.is_nil.not('non-nil')) : pass("is nil")
20
22
  end
21
23
  end
22
24
  end
@@ -12,14 +12,20 @@ module Riot
12
12
  # It would be kind of like a double negative:
13
13
  #
14
14
  # denies("you are funny") { true }.not!
15
+ #
16
+ # @deprecated Please use the denies assertion instead
15
17
  class NotMacro < AssertionMacro
16
18
  register :not!
17
19
 
20
+ # (see Riot::AssertionMacro#evaluate)
18
21
  def evaluate(actual)
22
+ warn "not! is deprecated; please use the denies assertion instead"
19
23
  actual ? fail("expected to exist ... not!") : pass("does exist ... not!")
20
24
  end
21
25
 
26
+ # (see Riot::AssertionMacro#devaluate)
22
27
  def devaluate(actual)
28
+ warn "not! is deprecated; please use the denies assertion instead"
23
29
  actual ? pass("does not exist ... not!") : fail("expected to not exist ... not!")
24
30
  end
25
31
  end
@@ -18,12 +18,15 @@ module Riot
18
18
  register :raises
19
19
  expects_exception!
20
20
 
21
+ # (see Riot::AssertionMacro#evaluate)
22
+ # @param [Class] expected_class the expected Exception class
23
+ # @param [String, nil] expected_message an optional exception message or message partial
21
24
  def evaluate(actual_exception, expected_class, expected_message=nil)
22
25
  actual_message = actual_exception && actual_exception.message
23
26
  if actual_exception.nil?
24
- fail should_have_message.raised(expected_class).but.raised_nothing
27
+ fail new_message.expected_to_raise(expected_class).but.raised_nothing
25
28
  elsif expected_class != actual_exception.class
26
- fail should_have_message.raised(expected_class).not(actual_exception.class)
29
+ fail new_message.expected_to_raise(expected_class).not(actual_exception.class)
27
30
  elsif expected_message && !(actual_message.to_s =~ %r[#{expected_message}])
28
31
  fail expected_message(expected_message).for_message.not(actual_message)
29
32
  else
@@ -32,23 +35,26 @@ module Riot
32
35
  end
33
36
  end # evaluate
34
37
 
38
+ # (see Riot::AssertionMacro#devaluate)
39
+ # @param [Class] expected_class the unexpected Exception class
40
+ # @param [String, nil] expected_message an optional exception message or message partial
35
41
  def devaluate(actual_exception, expected_class, expected_message=nil)
36
42
  actual_message = actual_exception && actual_exception.message
37
43
  if actual_exception.nil?
38
- pass new_message.raised_nothing
44
+ pass new_message.raises(expected_class)
39
45
  elsif expected_class != actual_exception.class
40
46
  if expected_message && !(actual_message.to_s =~ %r[#{expected_message}])
41
- pass new_message.not_raised(expected_class).with_message(expected_message)
47
+ pass new_message.raises(expected_class).with_message(expected_message)
42
48
  else
43
- pass new_message.not_raised(expected_class)
49
+ pass new_message.raises(expected_class)
44
50
  end
45
51
  else
46
- message = should_have_message.not_raised(expected_class)
52
+ message = new_message.expected_to_not_raise(expected_class)
47
53
  if expected_message
48
54
  fail message.with_message(expected_message).but.raised(actual_exception.class).
49
55
  with_message(actual_exception.message)
50
56
  else
51
- fail message.but.raised(actual_exception.class)
57
+ fail message
52
58
  end
53
59
  end
54
60
  end # devaluate
@@ -11,6 +11,8 @@ module Riot
11
11
  register :respond_to
12
12
  register :responds_to
13
13
 
14
+ # (see Riot::AssertionMacro#evaluate)
15
+ # @param [Symbol, String] expected the method name that actual should respond to
14
16
  def evaluate(actual, expected)
15
17
  if actual.respond_to?(expected)
16
18
  pass(new_message.responds_to(expected))
@@ -19,11 +21,13 @@ module Riot
19
21
  end
20
22
  end
21
23
 
24
+ # (see Riot::AssertionMacro#devaluate)
25
+ # @param [Symbol, String] expected the method name that actual should not respond to
22
26
  def devaluate(actual, expected)
23
27
  if actual.respond_to?(expected)
24
28
  fail(expected_message.method(expected).is_defined)
25
29
  else
26
- pass new_message.does_not_respond_to(expected)
30
+ pass new_message.responds_to(expected)
27
31
  end
28
32
  end
29
33
 
@@ -11,14 +11,18 @@ module Riot
11
11
  register :same_elements
12
12
  require 'set'
13
13
 
14
+ # (see Riot::AssertionMacro#evaluate)
15
+ # @param [Object] expected the collection of elements that actual should be equivalent to
14
16
  def evaluate(actual, expected)
15
17
  same = (Set.new(expected) == Set.new(actual))
16
- same ? pass : fail(expected_message.elements(expected).to_match(actual))
18
+ same ? pass(new_message.has_same_elements_as(expected)) : fail(expected_message.elements(expected).to_match(actual))
17
19
  end
18
20
 
21
+ # (see Riot::AssertionMacro#devaluate)
22
+ # @param [Object] expected the collection of elements that actual should not be equivalent to
19
23
  def devaluate(actual, expected)
20
24
  same = (Set.new(expected) == Set.new(actual))
21
- same ? fail(expected_message.elements(expected).not_to_match(actual)) : pass
25
+ same ? fail(expected_message.elements(expected).not_to_match(actual)) : pass(new_message.has_same_elements_as(expected))
22
26
  end
23
27
 
24
28
  end
@@ -14,14 +14,18 @@ module Riot
14
14
  class SizeMacro < AssertionMacro
15
15
  register :size
16
16
 
17
+ # (see Riot::AssertionMacro#evaluate)
18
+ # @param [Number] expected the expected size of actual
17
19
  def evaluate(actual, expected)
18
20
  failure_message = expected_message.size_of(actual).to_be(expected).not(actual.size)
19
21
  expected === actual.size ? pass(new_message.is_of_size(expected)) : fail(failure_message)
20
22
  end
21
23
 
24
+ # (see Riot::AssertionMacro#devaluate)
25
+ # @param [Number] expected the unexpected size of actual
22
26
  def devaluate(actual, expected)
23
27
  failure_message = expected_message.size_of(actual).to_not_be(expected).not(actual.size)
24
- expected === actual.size ? fail(failure_message) : pass(new_message.is_not_size(expected))
28
+ expected === actual.size ? fail(failure_message) : pass(new_message.is_size(expected))
25
29
  end
26
30
  end
27
31
  end
@@ -4,14 +4,24 @@ require 'riot/context_helpers'
4
4
  module Riot
5
5
  RootContext = Struct.new(:setups, :teardowns, :detailed_description, :options)
6
6
 
7
+ # Defines the classes {Riot::Context} will use when creating new assertions and situations.
7
8
  module ContextClassOverrides
9
+ # Returns the default class used for generating new {Riot::Assertion Assertion} instances. Defaults to
10
+ # {Riot::Assertion}.
11
+ #
12
+ # @return [Class]
8
13
  def assertion_class; Assertion; end
14
+
15
+ # Returns the default class used for generating new {Riot::Situation Situation} instances. Defaults to
16
+ # {Riot::Situation}.
17
+ #
18
+ # @return [Class]
9
19
  def situation_class; Situation; end
10
20
  end # ContextClassOverrides
11
21
 
12
- # You make your assertions within a Context. The context stores setup and teardown blocks, and allows for
13
- # nesting and refactoring into helpers. Extension developers may also configure ContextMiddleware objects
14
- # in order to extend the functionality of a Context.
22
+ # An {Riot::Assertion} is declared within a Context. The context stores setup and teardown
23
+ # blocks, and allows for nesting and refactoring. Extension developers may also configure
24
+ # {Riot::ContextMiddleware Middleware} objects in order to extend the functionality of a Context.
15
25
  class Context
16
26
  include ContextClassOverrides
17
27
  include ContextOptions
@@ -19,19 +29,24 @@ module Riot
19
29
 
20
30
  # The set of middleware helpers configured for the current test space.
21
31
  #
22
- # @return [Array]
32
+ # @return [Array<Riot::ContextMiddleware>]
23
33
  def self.middlewares; @middlewares ||= []; end
24
34
 
25
- # The description of the context.
35
+ # The partial description of just this context.
26
36
  #
27
37
  # @return [String]
28
38
  attr_reader :description
29
39
 
30
40
  # The parent context.
31
41
  #
32
- # @return [Riot::Context]
42
+ # @return [Riot::Context, nil] a context or nil
33
43
  attr_reader :parent
34
44
 
45
+ # Creates a new Context
46
+ #
47
+ # @param [String] description a partial description of this context
48
+ # @param [Riot::Context, nil] parent a parent context or nothing
49
+ # @param [lambda] definition the body of this context
35
50
  def initialize(description, parent=nil, &definition)
36
51
  @parent = parent || RootContext.new([],[], "", {})
37
52
  @description = description
@@ -43,25 +58,34 @@ module Riot
43
58
  # Create a new test context.
44
59
  #
45
60
  # @param [String] description
61
+ # @return [Riot::Context] the newly created context
46
62
  def context(description, &definition)
47
63
  new_context(description, self.class, &definition)
48
64
  end
49
65
  alias_method :describe, :context
50
66
 
67
+ # @private
51
68
  # Returns an ordered list of the setup blocks for the context.
52
69
  #
53
- # @return [Array[Riot::RunnableBlock]]
70
+ # @return [Array<Riot::RunnableBlock>]
54
71
  def setups
55
72
  @parent.setups + @setups
56
73
  end
57
74
 
75
+ # @private
58
76
  # Returns an ordered list of the teardown blocks for the context.
59
77
  #
60
- # @return [Array[Riot::RunnableBlock]]
78
+ # @return [Array<Riot::RunnableBlock>]
61
79
  def teardowns
62
80
  @parent.teardowns + @teardowns
63
81
  end
64
82
 
83
+ # Executes the setups, hookups, assertions, and teardowns and passes results on to a given
84
+ # {Riot::Reporter Reporter}. Sub-contexts will also be executed and provided the given reporter. A new
85
+ # {Riot::Situation Situation} will be created from the specified {#situation_class Situation class}.
86
+ #
87
+ # @param [Riot::Reporter] reporter the reporter to report results to
88
+ # @return [Riot::Reporter] the given reporter
65
89
  def run(reporter)
66
90
  reporter.describe_context(self) unless @assertions.empty?
67
91
  local_run(reporter, situation_class.new)
@@ -69,17 +93,26 @@ module Riot
69
93
  reporter
70
94
  end
71
95
 
96
+ # @private
97
+ # Used mostly for testing purposes; this method does the actual running of just this context.
98
+ # @param [Riot::Reporter] reporter the reporter to report results to
99
+ # @param [Riot::Situation] situation the situation to use for executing the context.
72
100
  def local_run(reporter, situation)
73
101
  runnables.each { |runnable| reporter.report(runnable.to_s, runnable.run(situation)) }
74
102
  end
75
103
 
76
- # Prints the full description from the context tree
104
+ # Prints the full description from the context tree, grabbing the description from the parent and
105
+ # appending the description given to this context.
106
+ #
107
+ # @return [String] the full description for this context
77
108
  def detailed_description
78
109
  "#{parent.detailed_description} #{description}".strip
79
110
  end
80
111
 
81
112
  private
82
113
 
114
+ # Iterative over the registered middlewares and let them configure this context instance if they so
115
+ # choose. {Riot::AllImportantMiddleware} will always be the last in the chain.
83
116
  def prepare_middleware(&context_definition)
84
117
  last_middleware = AllImportantMiddleware.new(&context_definition)
85
118
  Context.middlewares.inject(last_middleware) do |last_middleware, middleware|
@@ -87,12 +120,27 @@ module Riot
87
120
  end.call(self)
88
121
  end
89
122
 
123
+ # The collection of things that are {Riot::RunnableBlock} instances in this context.
124
+ #
125
+ # @return [Array<Riot::RunnableBlock>]
90
126
  def runnables
91
127
  setups + @assertions + teardowns
92
128
  end
93
129
 
94
- def run_sub_contexts(reporter) @contexts.each { |ctx| ctx.run(reporter) }; end
130
+ # Execute each sub context.
131
+ #
132
+ # @param [Riot::Reporter] reporter the reporter instance to use
133
+ # @return [nil]
134
+ def run_sub_contexts(reporter)
135
+ @contexts.each { |ctx| ctx.run(reporter) }
136
+ end
95
137
 
138
+ # Creates a new context instance and appends it to the set of immediate children sub-contexts.
139
+ #
140
+ # @param [String] description a partial description
141
+ # @param [Class] klass the context class that a sub-context will be generated from
142
+ # @param [lambda] definition the body of the sub-context
143
+ # @return [#run] something that hopefully responds to run and is context-like
96
144
  def new_context(description, klass, &definition)
97
145
  (@contexts << klass.new(description, self, &definition)).last
98
146
  end
@@ -14,6 +14,9 @@ module Riot
14
14
  #
15
15
  # If you provide +true+ as the first argument, the setup will be unshifted onto the list of setups,
16
16
  # ensuring it will be run before any other setups. This is really only useful for context middlewares.
17
+ #
18
+ # @param [Boolean] premium indicates importance of the setup
19
+ # @return [Riot::Setup]
17
20
  def setup(premium=false, &definition)
18
21
  setup = Setup.new(&definition)
19
22
  premium ? @setups.unshift(setup) : @setups.push(setup)
@@ -29,6 +32,9 @@ module Riot
29
32
  # helper(:foo) { "bar" }
30
33
  # asserts("a foo") { foo }.equals("bar")
31
34
  # end
35
+ #
36
+ # @param [String, Symbol] name the name of the helper
37
+ # @return [Riot::Helper]
32
38
  def helper(name, &block)
33
39
  (@setups << Helper.new(name, &block)).last
34
40
  end
@@ -44,6 +50,8 @@ module Riot
44
50
  # You would do this:
45
51
  #
46
52
  # hookup { topic.do_something } # Yay!
53
+ #
54
+ # @return [Riot::Setup]
47
55
  def hookup(&definition)
48
56
  setup { self.instance_eval(&definition); topic }
49
57
  end
@@ -51,6 +59,8 @@ module Riot
51
59
  # Add a teardown block. You may define multiple of these as well.
52
60
  #
53
61
  # teardown { Bombs.drop! }
62
+ #
63
+ # @return [Riot::Setup]
54
64
  def teardown(&definition)
55
65
  (@teardowns << Setup.new(&definition)).last
56
66
  end
@@ -73,7 +83,8 @@ module Riot
73
83
  # Passing a Symbol to +asserts+ enables this behaviour. For more information on
74
84
  # assertion macros, see {Riot::AssertionMacro}.
75
85
  #
76
- # @param [String, Symbol] the property being tested
86
+ # @param [String, Symbol] what description of test or property to inspect on the topic
87
+ # @return [Riot::Assertion]
77
88
  def asserts(what, &definition)
78
89
  new_assertion("asserts", what, &definition)
79
90
  end
@@ -83,7 +94,8 @@ module Riot
83
94
  #
84
95
  # should("ensure expected") { "bar" }.equals("bar")
85
96
  #
86
- # @param [String, Symbol] the property being tested
97
+ # @param [String, Symbol] what description of test or property to inspect on the topic
98
+ # @return [Riot::Assertion]
87
99
  def should(what, &definition)
88
100
  new_assertion("should", what, &definition)
89
101
  end
@@ -106,7 +118,8 @@ module Riot
106
118
  # Passing a Symbol to +denies+ enables this behaviour. For more information on
107
119
  # assertion macros, see {Riot::AssertionMacro}.
108
120
  #
109
- # @param [String, Symbol] the property being tested
121
+ # @param [String, Symbol] what description of test or property to inspect on the topic
122
+ # @return [Riot::Assertion]
110
123
  def denies(what, &definition)
111
124
  new_assertion("denies", what, true, &definition)
112
125
  end
@@ -114,6 +127,9 @@ module Riot
114
127
  # Makes an assertion on the topic itself, e.g.
115
128
  #
116
129
  # asserts_topic.matches(/^ab+/)
130
+ #
131
+ # @param [String] what description of test
132
+ # @return [Riot::Assertion]
117
133
  def asserts_topic(what="that it")
118
134
  asserts(what) { topic }
119
135
  end
@@ -124,7 +140,7 @@ module Riot
124
140
  description = "#{scope} ##{what}"
125
141
  elsif what.kind_of?(Array)
126
142
  definition ||= proc { topic.send(*what) }
127
- description = "#{scope} ##{what.shift} with argument(s): #{what}"
143
+ description = "#{scope} ##{what.first} with argument(s): #{what[1..-1]}"
128
144
  else
129
145
  description = "#{scope} #{what}"
130
146
  end