vedeu 0.2.0 → 0.2.1

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -9
  3. data/docs/api.md +70 -42
  4. data/elements.txt +118 -0
  5. data/lib/vedeu.rb +14 -4
  6. data/lib/vedeu/api/api.rb +67 -24
  7. data/lib/vedeu/api/composition.rb +19 -0
  8. data/lib/vedeu/api/defined.rb +7 -0
  9. data/lib/vedeu/api/interface.rb +103 -75
  10. data/lib/vedeu/api/keymap.rb +62 -0
  11. data/lib/vedeu/api/menu.rb +3 -1
  12. data/lib/vedeu/configuration.rb +24 -6
  13. data/lib/vedeu/models/attributes/coercions.rb +18 -26
  14. data/lib/vedeu/models/attributes/colour_translator.rb +7 -7
  15. data/lib/vedeu/models/attributes/presentation.rb +12 -1
  16. data/lib/vedeu/models/geometry.rb +5 -1
  17. data/lib/vedeu/models/interface.rb +6 -47
  18. data/lib/vedeu/models/keymap.rb +66 -0
  19. data/lib/vedeu/models/line.rb +3 -1
  20. data/lib/vedeu/models/stream.rb +10 -1
  21. data/lib/vedeu/models/style.rb +10 -1
  22. data/lib/vedeu/output/compositor.rb +3 -0
  23. data/lib/vedeu/output/refresh.rb +16 -74
  24. data/lib/vedeu/output/render.rb +44 -17
  25. data/lib/vedeu/output/view.rb +3 -0
  26. data/lib/vedeu/repositories/buffers.rb +32 -42
  27. data/lib/vedeu/repositories/events.rb +8 -11
  28. data/lib/vedeu/repositories/focus.rb +15 -13
  29. data/lib/vedeu/repositories/groups.rb +20 -2
  30. data/lib/vedeu/repositories/interfaces.rb +22 -2
  31. data/lib/vedeu/repositories/keymap_validator.rb +104 -0
  32. data/lib/vedeu/repositories/keymaps.rb +239 -0
  33. data/lib/vedeu/repositories/menus.rb +12 -3
  34. data/lib/vedeu/support/common.rb +2 -2
  35. data/lib/vedeu/support/cursor.rb +3 -0
  36. data/lib/vedeu/support/event.rb +48 -7
  37. data/lib/vedeu/support/grid.rb +1 -1
  38. data/lib/vedeu/support/registrar.rb +66 -0
  39. data/lib/vedeu/support/trace.rb +71 -12
  40. data/test/lib/vedeu/api/api_test.rb +27 -9
  41. data/test/lib/vedeu/api/composition_test.rb +10 -0
  42. data/test/lib/vedeu/api/defined_test.rb +14 -0
  43. data/test/lib/vedeu/api/interface_test.rb +86 -85
  44. data/test/lib/vedeu/api/keymap_test.rb +61 -0
  45. data/test/lib/vedeu/configuration_test.rb +12 -0
  46. data/test/lib/vedeu/models/attributes/coercions_test.rb +3 -4
  47. data/test/lib/vedeu/models/interface_test.rb +0 -43
  48. data/test/lib/vedeu/models/keymap_test.rb +19 -0
  49. data/test/lib/vedeu/models/style_test.rb +10 -0
  50. data/test/lib/vedeu/output/refresh_test.rb +0 -12
  51. data/test/lib/vedeu/output/render_test.rb +51 -0
  52. data/test/lib/vedeu/repositories/buffers_test.rb +39 -12
  53. data/test/lib/vedeu/repositories/events_test.rb +6 -0
  54. data/test/lib/vedeu/repositories/focus_test.rb +12 -0
  55. data/test/lib/vedeu/repositories/keymap_validator_test.rb +81 -0
  56. data/test/lib/vedeu/repositories/keymaps_test.rb +254 -0
  57. data/test/lib/vedeu/support/common_test.rb +26 -0
  58. data/test/lib/vedeu/support/registrar_test.rb +68 -0
  59. data/vedeu.gemspec +1 -1
  60. metadata +18 -2
@@ -115,6 +115,12 @@ module Vedeu
115
115
  debug: false,
116
116
  interactive: true,
117
117
  once: false,
118
+ system_keys: {
119
+ exit: "q",
120
+ focus_next: :tab,
121
+ focus_prev: :shift_tab,
122
+ mode_switch: :escape
123
+ },
118
124
  terminal_mode: :raw,
119
125
  trace: false
120
126
  }
@@ -131,6 +137,12 @@ module Vedeu
131
137
  once: true,
132
138
  colour_mode: 16777216,
133
139
  debug: false,
140
+ system_keys: {
141
+ exit: "q",
142
+ focus_next: :tab,
143
+ focus_prev: :shift_tab,
144
+ mode_switch: :escape
145
+ },
134
146
  terminal_mode: :raw,
135
147
  trace: false
136
148
  }
@@ -9,7 +9,6 @@ module Vedeu
9
9
  def initialize(attributes = {})
10
10
  @attributes = attributes
11
11
  @name = attributes[:name]
12
- @parent = attributes[:parent]
13
12
  end
14
13
  end
15
14
 
@@ -30,7 +29,7 @@ module Vedeu
30
29
  it 'returns a collection of models when a single hash' do
31
30
  coerced = TestClass.coercer({ :name => 'test1' })
32
31
  coerced.must_be_instance_of(Array)
33
- coerced.first.attributes.must_equal({ name: "test1", parent: nil })
32
+ coerced.first.attributes.must_equal({ name: "test1" })
34
33
  end
35
34
 
36
35
  it 'returns a collection of models when multiple hashes' do
@@ -39,14 +38,14 @@ module Vedeu
39
38
  ])
40
39
  coerced.size.must_equal(2)
41
40
  coerced.map(&:attributes).must_equal(
42
- [{ name: "test1", parent: nil }, { name: "test2", parent: nil }]
41
+ [{ name: "test1" }, { name: "test2" }]
43
42
  )
44
43
  end
45
44
 
46
45
  it 'returns a collection of models when a single array' do
47
46
  coerced = TestClass.coercer([{ :name => 'test3' }])
48
47
  coerced.size.must_equal(1)
49
- coerced.first.attributes.must_equal({ name: "test3", parent: nil })
48
+ coerced.first.attributes.must_equal({ name: "test3" })
50
49
  end
51
50
  end
52
51
  end
@@ -95,48 +95,5 @@ module Vedeu
95
95
  end
96
96
  end
97
97
 
98
- describe '#to_s' do
99
- it 'returns an string' do
100
- Interface.new({
101
- name: '#to_s',
102
- lines: [],
103
- colour: {
104
- foreground: '#ff0000',
105
- background: '#000000'
106
- },
107
- geometry: {
108
- width: 9,
109
- height: 3
110
- }
111
- }).to_s.must_equal(
112
- "\e[38;2;255;0;0m\e[48;2;0;0;0m" \
113
- "\e[1;1H \e[1;1H" \
114
- "\e[2;1H \e[2;1H" \
115
- "\e[3;1H \e[3;1H\e[?25h"
116
- )
117
- end
118
- end
119
-
120
- describe '#clear' do
121
- it 'delegates to the Clear class to return an empty interface' do
122
- Interface.new({
123
- name: '#to_s',
124
- lines: [],
125
- colour: {
126
- foreground: '#ff0000',
127
- background: '#000000'
128
- },
129
- geometry: {
130
- width: 9,
131
- height: 3
132
- }
133
- }).clear.must_equal(
134
- "\e[38;2;255;0;0m\e[48;2;0;0;0m" \
135
- "\e[1;1H \e[1;1H" \
136
- "\e[2;1H \e[2;1H" \
137
- "\e[3;1H \e[3;1H"
138
- )
139
- end
140
- end
141
98
  end
142
99
  end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ module Vedeu
4
+ describe Keymap do
5
+
6
+ describe '.define' do
7
+ it '' do
8
+ skip
9
+ end
10
+ end
11
+
12
+ describe '#initialize' do
13
+ it 'returns an instance of itself' do
14
+ Keymap.new.must_be_instance_of(Keymap)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -10,6 +10,16 @@ module Vedeu
10
10
  end
11
11
  end
12
12
 
13
+ describe '#attributes' do
14
+ it 'returns an attributes hash for this instance' do
15
+ Style.new(['bold']).attributes.must_equal(
16
+ {
17
+ style: ['bold']
18
+ }
19
+ )
20
+ end
21
+ end
22
+
13
23
  describe '#to_s' do
14
24
  describe 'for a single style' do
15
25
  let(:values) { 'normal' }
@@ -2,18 +2,6 @@ require 'test_helper'
2
2
 
3
3
  module Vedeu
4
4
  describe Refresh do
5
- describe '.add_interface' do
6
- it 'returns false when provided with no attributes' do
7
- Refresh.add_interface({}).must_equal(false)
8
- end
9
- end
10
-
11
- describe '.add_group' do
12
- it 'returns false when provided with no attributes' do
13
- Refresh.add_group({}).must_equal(false)
14
- end
15
- end
16
-
17
5
  describe '.all' do
18
6
  it 'returns an empty collection when there are no registered ' \
19
7
  'interfaces' do
@@ -131,6 +131,57 @@ module Vedeu
131
131
  )
132
132
  end
133
133
 
134
+ it 'returns to using the presentation attributes of the line after a ' \
135
+ 'stream finishes' do
136
+ Vedeu.interface 'oxygen' do
137
+ width 40
138
+ height 2
139
+ end
140
+
141
+ class OxygenView < Vedeu::View
142
+ def render
143
+ Vedeu.view 'oxygen' do
144
+ line do
145
+ colour background: '#000000', foreground: '#ffffff'
146
+ stream do
147
+ text 'the grass is '
148
+ end
149
+ stream do
150
+ colour foreground: '#00ff00'
151
+ text 'green'
152
+ end
153
+ stream do
154
+ text ' and the sky is '
155
+ end
156
+ stream do
157
+ colour foreground: '#0000ff'
158
+ text 'blue'
159
+ end
160
+ stream do
161
+ text '.'
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ IO.console.stub(:print, nil) do
169
+ OxygenView.render
170
+
171
+ Compositor.render('oxygen').must_equal([
172
+ "\e[1;1H \e[1;1H" \
173
+ "\e[2;1H \e[2;1H" \
174
+ "\e[1;1H\e[38;2;255;255;255m\e[48;2;0;0;0m" \
175
+ "the grass is \e[38;2;255;255;255m\e[48;2;0;0;0m" \
176
+ "\e[38;2;0;255;0mgreen\e[38;2;255;255;255m\e[48;2;0;0;0m" \
177
+ " and the sky is \e[38;2;255;255;255m\e[48;2;0;0;0m" \
178
+ "\e[38;2;0;0;255mblue\e[38;2;255;255;255m\e[48;2;0;0;0m" \
179
+ ".\e[38;2;255;255;255m\e[48;2;0;0;0m" \
180
+ "\e[?25h"
181
+ ])
182
+ end
183
+ end
184
+
134
185
  end
135
186
  end
136
187
  end
@@ -3,45 +3,72 @@ require 'test_helper'
3
3
  module Vedeu
4
4
  describe Buffers do
5
5
 
6
- describe '.create' do
7
- end
8
-
9
6
  describe '.add' do
10
- end
7
+ before { Buffers.reset }
11
8
 
12
- describe '.find' do
13
- context 'when the buffer does not exist by this name' do
9
+ it 'returns the name of the buffer added to storage' do
10
+ Buffers.add({ name: 'molybdenum' }).must_equal('molybdenum')
14
11
  end
15
12
 
16
- context 'when the buffer can be found by name' do
13
+ context 'when the buffer is already registered' do
14
+ it 'retrieves the buffer in storage, and adds the attributes to the ' \
15
+ 'back buffer, preserving the front which may already have content' do
16
+ skip
17
+ end
18
+ end
19
+
20
+ context 'when the buffer was not registered' do
21
+ it 'stores a new buffer by name, and adds the attributes to the back ' \
22
+ 'buffer' do
23
+ skip
24
+ end
17
25
  end
18
26
  end
19
27
 
20
- describe '.latest' do
28
+ describe '.find' do
21
29
  context 'when the buffer does not exist by this name' do
30
+ it '' do
31
+ skip
32
+ end
22
33
  end
23
34
 
24
35
  context 'when the buffer can be found by name' do
36
+ it '' do
37
+ skip
38
+ end
25
39
  end
26
40
  end
27
41
 
28
- describe '.content' do
42
+ describe '.latest' do
29
43
  context 'when the buffer does not exist by this name' do
44
+ it '' do
45
+ skip
46
+ end
30
47
  end
31
48
 
32
49
  context 'when the buffer can be found by name' do
50
+ it '' do
51
+ skip
52
+ end
33
53
  end
34
54
  end
35
55
 
36
- describe '.swap_buffers' do
37
- context 'when the buffer does not exist by this name' do
56
+ describe '.registered' do
57
+ it '' do
58
+ skip
38
59
  end
60
+ end
39
61
 
40
- context 'when the buffer can be found by name' do
62
+ describe '.registered>' do
63
+ it '' do
64
+ skip
41
65
  end
42
66
  end
43
67
 
44
68
  describe '.reset' do
69
+ it '' do
70
+ skip
71
+ end
45
72
  end
46
73
 
47
74
  end
@@ -37,6 +37,12 @@ module Vedeu
37
37
  end
38
38
  end
39
39
 
40
+ describe '#registered?' do
41
+ it '' do
42
+ skip
43
+ end
44
+ end
45
+
40
46
  describe '#trigger' do
41
47
  it 'returns a collection containing the event when the event is ' \
42
48
  'pre-registered' do
@@ -70,5 +70,17 @@ module Vedeu
70
70
  Focus.registered.must_equal(['thallium', 'lead', 'bismuth'])
71
71
  end
72
72
  end
73
+
74
+ describe '.registered?' do
75
+ it '' do
76
+ skip
77
+ end
78
+ end
79
+
80
+ describe '.reset' do
81
+ it '' do
82
+ skip
83
+ end
84
+ end
73
85
  end
74
86
  end
@@ -0,0 +1,81 @@
1
+ require 'test_helper'
2
+
3
+ module Vedeu
4
+ describe KeymapValidator do
5
+ let(:storage) {
6
+ {
7
+ 'dubnium' => {
8
+ 'a' => proc { :do_something }
9
+ },
10
+ '_global_keymap_' => {
11
+ 'g' => proc { :do_something }
12
+ }
13
+ }
14
+ }
15
+ let(:key) { 'a' }
16
+ let(:interface) { 'dubnium' }
17
+
18
+ describe '.check' do
19
+ context 'when already in use as a system key' do
20
+ it 'returns false with a message' do
21
+ result = KeymapValidator.check(storage, :shift_tab, interface)
22
+ result.must_include(false)
23
+ result.last.must_match(/by the system/)
24
+ end
25
+ end
26
+
27
+ context 'when already in use as a global key' do
28
+ it 'returns false with a message' do
29
+ result = KeymapValidator.check(storage, 'g', interface)
30
+ result.must_include(false)
31
+ result.last.must_match(/as a global key/)
32
+ end
33
+ end
34
+
35
+ context 'when already in use by the interface' do
36
+ it 'returns false with a message' do
37
+ result = KeymapValidator.check(storage, 'a', interface)
38
+ result.must_include(false)
39
+ result.last.must_match(/by this interface/)
40
+ end
41
+ end
42
+
43
+ context 'when attempting to register a global key which is already in ' \
44
+ 'use by an interface' do
45
+ it 'returns false with a message' do
46
+ result = KeymapValidator.check(storage, 'a', '')
47
+ result.must_include(false)
48
+ result.last.must_match(/therefore cannot be global/)
49
+ end
50
+ end
51
+
52
+ context 'when valid as a global key' do
53
+ it 'returns true with a message' do
54
+ result = KeymapValidator.check(storage, 'h', '')
55
+ result.must_include(true)
56
+ result.last.must_match(/can be registered/)
57
+ end
58
+ end
59
+
60
+ context 'when valid as an interface key' do
61
+ it 'returns true with a message' do
62
+ result = KeymapValidator.check(storage, 'b', 'dubnium')
63
+ result.must_include(true)
64
+ result.last.must_match(/can be registered/)
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '#initialize' do
70
+ it 'returns an instance of itself' do
71
+ storage = {}
72
+ key = ''
73
+ interface = ''
74
+
75
+ KeymapValidator.new(storage, key, interface)
76
+ .must_be_instance_of(KeymapValidator)
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,254 @@
1
+ require 'test_helper'
2
+
3
+ module Vedeu
4
+ describe Keymaps do
5
+
6
+ describe '#add' do
7
+ before { Keymaps.reset }
8
+
9
+ it 'returns false when there are no keys defined' do
10
+ attributes = {}
11
+
12
+ Keymaps.add(attributes).must_equal(false)
13
+ end
14
+
15
+ it 'returns true when the key was registered with keymap storage' do
16
+ attributes = { interfaces: ['gold'], keys: [{ 'a' => proc { :gold } }] }
17
+
18
+ Keymaps.add(attributes).must_equal(true)
19
+ end
20
+ end
21
+
22
+ describe '#all' do
23
+ before { Keymaps.reset }
24
+
25
+ it 'returns all stored keymaps' do
26
+ Keymaps.all.must_equal({ '_global_keymap_' => {} })
27
+ end
28
+ end
29
+
30
+ describe '#find' do
31
+ let(:attributes) {
32
+ {
33
+ interfaces: ['flerovium'],
34
+ keys: [{ key: 'u', action: proc { :some_action } }]
35
+ }
36
+ }
37
+
38
+ before do
39
+ Keymaps.reset
40
+ Keymaps.add(attributes)
41
+ end
42
+
43
+ it 'returns false when the named keymap cannot be found' do
44
+ Keymaps.find('vanadium').must_equal({})
45
+ end
46
+
47
+ it 'returns the keymap when the named keymap was found' do
48
+ Keymaps.find('flerovium').wont_be_empty
49
+ end
50
+ end
51
+
52
+ describe '#global_key?' do
53
+ before do
54
+ Keymaps.reset
55
+ Keymaps.stubs(:global_keys).returns(['i', 'j'])
56
+ end
57
+
58
+ it 'returns false when the key is not registered as a global key' do
59
+ Keymaps.global_key?('h').must_equal(false)
60
+ end
61
+
62
+ it 'returns true when the key is registered as a global key' do
63
+ Keymaps.global_key?('j').must_equal(true)
64
+ end
65
+ end
66
+
67
+ describe '#global_keys' do
68
+ let(:attributes) {
69
+ {
70
+ keys: [
71
+ {
72
+ key: 'a', action: proc { :action_a }
73
+ },{
74
+ key: 'b', action: proc { :action_b }
75
+ },{
76
+ key: 'c', action: proc { :action_c }
77
+ }
78
+ ]
79
+ }
80
+ }
81
+
82
+ before do
83
+ Keymaps.reset
84
+ Keymaps.add(attributes)
85
+ end
86
+
87
+ it 'returns the defined global keys' do
88
+ Keymaps.global_keys.must_equal(['a', 'b', 'c'])
89
+ end
90
+ end
91
+
92
+ describe '#interface_key?' do
93
+ before do
94
+ Keymaps.reset
95
+ Keymaps.stubs(:interface_keys).returns(['g', 'h'])
96
+ end
97
+
98
+ it 'returns false when the key is not registered with an interface' do
99
+ Keymaps.interface_key?('f').must_equal(false)
100
+ end
101
+
102
+ it 'returns true when the key is registered with an interface' do
103
+ Keymaps.interface_key?('g').must_equal(true)
104
+ end
105
+
106
+ context 'when the interface argument is provided' do
107
+ before do
108
+ Keymaps.stubs(:find).returns({ 'j' => proc { :some_action } })
109
+ end
110
+
111
+ it 'return false when the key is not registered with the specified ' \
112
+ 'interface' do
113
+ Keymaps.interface_key?('k', 'cadmium').must_equal(false)
114
+ end
115
+
116
+ it 'return true when the key is registered with the specified ' \
117
+ 'interface' do
118
+ Keymaps.interface_key?('j', 'cadmium').must_equal(true)
119
+ end
120
+ end
121
+ end
122
+
123
+ describe '#interface_keys' do
124
+ let(:rhodium_attributes) {
125
+ {
126
+ interfaces: ['rhodium'],
127
+ keys: [
128
+ {
129
+ key: 'd', action: proc { :action_d }
130
+ },{
131
+ key: 'e', action: proc { :action_e }
132
+ }
133
+ ]
134
+ }
135
+ }
136
+ let(:magnesium_attributes) {
137
+ {
138
+ interfaces: ['magnesium'],
139
+ keys: [
140
+ {
141
+ key: 'e', action: proc { :action_e }
142
+ },{
143
+ key: 'f', action: proc { :action_g }
144
+ }
145
+ ]
146
+ }
147
+ }
148
+
149
+ before do
150
+ Keymaps.reset
151
+ Keymaps.add(rhodium_attributes)
152
+ Keymaps.add(magnesium_attributes)
153
+ end
154
+
155
+ it 'returns the defined keys for all interfaces' do
156
+ Keymaps.interface_keys.must_equal(['d', 'e', 'f'])
157
+ end
158
+ end
159
+
160
+ describe '#registered' do
161
+ before { Keymaps.reset }
162
+
163
+ it 'returns a collection of the interface names of all registered ' \
164
+ 'keymaps' do
165
+ Keymaps.registered.must_equal(['_global_keymap_'])
166
+ end
167
+ end
168
+
169
+ describe '#registered?' do
170
+ it 'returns false when the named keymap is not registered' do
171
+ Keymaps.registered?('vanadium').must_equal(false)
172
+ end
173
+
174
+ it 'returns true when the named keymap is registered' do
175
+ Keymaps.registered?('_global_keymap_').must_equal(true)
176
+ end
177
+ end
178
+
179
+ describe '#reset' do
180
+ it 'removes all stored keymaps' do
181
+ Keymaps.reset.must_equal({ '_global_keymap_' => {} })
182
+ end
183
+ end
184
+
185
+ describe '#system_key?' do
186
+ it 'returns false when the key is not registered as a system key' do
187
+ Keymaps.system_key?('r').must_equal(false)
188
+ end
189
+
190
+ it 'returns true when the key is registered as a system key' do
191
+ Keymaps.system_key?('q').must_equal(true)
192
+ end
193
+ end
194
+
195
+ describe '#system_keys' do
196
+ it 'returns the defined system keys' do
197
+ Keymaps.system_keys.must_equal(['q', :tab, :shift_tab, :escape])
198
+ end
199
+ end
200
+
201
+ describe '#use' do
202
+ let(:meitnerium_attributes) {
203
+ {
204
+ interfaces: ['meitnerium'],
205
+ keys: [{
206
+ key: 'm', action: proc { :key_m_pressed }
207
+ }]
208
+ }
209
+ }
210
+ let(:global_attributes) {
211
+ {
212
+ keys: [{
213
+ key: 'o', action: proc { :key_o_pressed }
214
+ }]
215
+ }
216
+ }
217
+
218
+ before do
219
+ Keymaps.reset
220
+ Keymaps.add(meitnerium_attributes)
221
+ Keymaps.add(global_attributes)
222
+ Vedeu::Focus.stubs(:current).returns('meitnerium')
223
+ Vedeu::Configuration.stubs(:system_keys).returns({ :key_p_pressed => 'p' })
224
+ Vedeu.stubs(:trigger).returns(:system_key_p_pressed)
225
+ end
226
+
227
+ context 'when not registered' do
228
+ it 'returns false' do
229
+ Keymaps.use('l').must_equal(false)
230
+ end
231
+ end
232
+
233
+ context 'when registered as an interface key and the interface is in ' \
234
+ 'focus' do
235
+ it 'returns the result of the keypress' do
236
+ Keymaps.use('m').must_equal(:key_m_pressed)
237
+ end
238
+ end
239
+
240
+ context 'when registered as a global key' do
241
+ it 'returns the result of the keypress' do
242
+ Keymaps.use('o').must_equal(:key_o_pressed)
243
+ end
244
+ end
245
+
246
+ context 'when registered as a system key' do
247
+ it 'returns the result of the keypress' do
248
+ Keymaps.use('p').must_equal(:system_key_p_pressed)
249
+ end
250
+ end
251
+ end
252
+
253
+ end
254
+ end