git-contest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/Gemfile +5 -0
  6. data/LICENSE.txt +24 -0
  7. data/README.md +217 -0
  8. data/Rakefile +4 -0
  9. data/bin/git-contest +43 -0
  10. data/bin/git-contest-finish +163 -0
  11. data/bin/git-contest-init +77 -0
  12. data/bin/git-contest-rebase +76 -0
  13. data/bin/git-contest-start +68 -0
  14. data/bin/git-contest-submit +188 -0
  15. data/git-contest.gemspec +34 -0
  16. data/lib/contest/driver.rb +15 -0
  17. data/lib/contest/driver/aizu_online_judge.rb +159 -0
  18. data/lib/contest/driver/base.rb +103 -0
  19. data/lib/contest/driver/codeforces.rb +196 -0
  20. data/lib/contest/driver/common.rb +72 -0
  21. data/lib/contest/driver/driver_event.rb +30 -0
  22. data/lib/contest/driver/uva_online_judge.rb +131 -0
  23. data/lib/git/contest.rb +14 -0
  24. data/lib/git/contest/common.rb +48 -0
  25. data/lib/git/contest/git.rb +189 -0
  26. data/lib/git/contest/test.rb +10 -0
  27. data/lib/git/contest/version.rb +12 -0
  28. data/spec/bin/t004_git_contest_submit_spec.rb +143 -0
  29. data/spec/bin/t005_git_contest_branching_spec.rb +83 -0
  30. data/spec/bin/t007_git_contest_start_spec.rb +121 -0
  31. data/spec/bin/t008_git_contest_finish_spec.rb +229 -0
  32. data/spec/bin/t009_git_contest_init_spec.rb +82 -0
  33. data/spec/lib/contest/driver/t001_aizu_online_judge_spec.rb +177 -0
  34. data/spec/lib/contest/driver/t002_codeforces_spec.rb +34 -0
  35. data/spec/lib/contest/driver/t003_uva_online_judge_spec.rb +33 -0
  36. data/spec/mock/default_config/config.yml +0 -0
  37. data/spec/mock/default_config/plugins/driver_dummy.rb +113 -0
  38. data/spec/mock/t001/002.status_log.xml +55 -0
  39. data/spec/mock/t001/config.yml +5 -0
  40. data/spec/mock/t001/description.html +48 -0
  41. data/spec/mock/t001/status.html +49 -0
  42. data/spec/mock/t001/status_log.xml +29 -0
  43. data/spec/mock/t002/my_submissions.html +58 -0
  44. data/spec/mock/t003/after_submit.html +28 -0
  45. data/spec/mock/t003/my_submissions.compile_error.html +160 -0
  46. data/spec/mock/t003/my_submissions.sent_to_judge.html +358 -0
  47. data/spec/mock/t004/config.yml +17 -0
  48. data/spec/mock/t005/001/config.yml +5 -0
  49. data/spec/mock/t006/001/001/001/config.yml +8 -0
  50. data/spec/mock/t006/001/001/002/config.yml +8 -0
  51. data/spec/mock/t006/001/001/003/config.yml +8 -0
  52. data/spec/mock/t006/001/002/001/config.yml +8 -0
  53. data/spec/mock/t006/001/002/002/config.yml +8 -0
  54. data/spec/mock/t006/001/002/003/config.yml +8 -0
  55. data/spec/mock/t006/001/003/001/config.yml +9 -0
  56. data/spec/mock/t006/001/003/002/config.yml +9 -0
  57. data/spec/mock/t006/001/003/003/config.yml +9 -0
  58. data/spec/spec_helper.rb +45 -0
  59. data/spec/spec_list.txt +1 -0
  60. data/spec/t006_config_spec.rb +168 -0
  61. metadata +269 -0
@@ -0,0 +1,10 @@
1
+ #
2
+ # test.rb
3
+ #
4
+ # Copyright (c) 2013 Hiroyuki Sano <sh19910711 at gmail.com>
5
+ # Licensed under the MIT-License.
6
+ #
7
+
8
+ def is_test_mode?
9
+ ENV['TEST_MODE'] === 'TRUE'
10
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # version.rb
3
+ #
4
+ # Copyright (c) 2013 Hiroyuki Sano <sh19910711 at gmail.com>
5
+ # Licensed under the MIT-License.
6
+ #
7
+
8
+ module Git
9
+ module Contest
10
+ VERSION = "0.0.1"
11
+ end
12
+ end
@@ -0,0 +1,143 @@
1
+ require "spec_helper"
2
+
3
+ describe "T004: bin/git-contest-submit" do
4
+
5
+ before(:each) do
6
+ init_env
7
+ ENV['GIT_CONTEST_HOME'] = get_path('/mock/default_config')
8
+ ENV['GIT_CONTEST_CONFIG'] = get_path('/mock/t004/config.yml')
9
+ @test_dir = "#{ENV['GIT_CONTEST_TEMP_DIR']}/t004"
10
+ Dir.mkdir @test_dir
11
+ Dir.chdir @test_dir
12
+ end
13
+
14
+ after(:each) do
15
+ Dir.chdir '..'
16
+ FileUtils.remove_dir @test_dir, :force => true
17
+ end
18
+
19
+ describe "001: version option check" do
20
+
21
+ it "001: git-contest-submit --version" do
22
+ ret = `#{bin_path("git-contest-submit")} --version`
23
+ (!!ret.match(/git-contest [0-9]+\.[0-9]+\.[0-9]+/)).should === true
24
+ end
25
+
26
+ it "002: git-contest submit --version" do
27
+ ret = `#{bin_path("git-contest submit")} --version`
28
+ (!!ret.match(/git-contest [0-9]+\.[0-9]+\.[0-9]+/)).should === true
29
+ end
30
+
31
+ it "003: git contest submit --version" do
32
+ ret = `git contest submit --version`
33
+ (!!ret.match(/git-contest [0-9]+\.[0-9]+\.[0-9]+/)).should === true
34
+ end
35
+
36
+ end
37
+
38
+ describe "002: help check" do
39
+
40
+ before do
41
+ Dir.mkdir '002'
42
+ Dir.chdir '002'
43
+ Dir.mkdir 'working'
44
+ Dir.chdir 'working'
45
+ File.open 'main.cpp', 'w' do |file|
46
+ file.write 'ac-code'
47
+ end
48
+ end
49
+
50
+ after do
51
+ Dir.chdir '..'
52
+ Dir.chdir '..'
53
+ end
54
+
55
+ describe '001: dummy driver available only test-mode' do
56
+
57
+ it "001: git-contest-submit --help" do
58
+ ret = `#{bin_path("git-contest-submit")} --help`
59
+ ret.include?('test_dummy').should === true
60
+ ret.include?('test_11111').should === true
61
+ ret.include?('test_22222').should === true
62
+ ret.include?('test_33333').should === true
63
+ end
64
+
65
+ end
66
+
67
+ it "002: git-contest-submit test_dummy" do
68
+ ret = `#{bin_path("git-contest-submit")} test_dummy 2>&1`
69
+ ret.include?('Error').should === true
70
+ end
71
+
72
+ it "003: git-contest-submit test_dummy -c 100" do
73
+ ret = `#{bin_path("git-contest-submit")} test_dummy -c 100 2>&1`
74
+ ret.include?('Error').should === true
75
+ end
76
+
77
+ it "004: git-contest-submit test_dummy -c 100 -p A" do
78
+ ret = `#{bin_path("git-contest-submit")} test_dummy -c 100 -p A 2>&1`
79
+ ret.include?("99999").should === true
80
+ ret.include?("Accepted").should === true
81
+ end
82
+
83
+ end
84
+
85
+ describe '003: after init git repo' do
86
+
87
+ before do
88
+ Dir.mkdir '003'
89
+ Dir.chdir '003'
90
+ Dir.mkdir 'working'
91
+ Dir.chdir 'working'
92
+ File.open 'main.cpp', 'w' do |file|
93
+ file.write 'ac-code'
94
+ end
95
+ end
96
+
97
+ after do
98
+ Dir.chdir '..'
99
+ Dir.chdir '..'
100
+ end
101
+
102
+ before do
103
+ `#{bin_path("git-contest")} init --defaults`
104
+ end
105
+
106
+ after do
107
+ end
108
+
109
+ it '001: submit' do
110
+ ret_submit = `#{bin_path("git-contest-submit")} test_dummy -c 100 -p A 2>&1`
111
+ ret_submit.include?("99999").should === true
112
+ ret_submit.include?("Accepted").should === true
113
+ ret_git = `git log --oneline --decorate --graph`
114
+ ret_git.include?("Dummy 100A: Accepted").should === true
115
+ end
116
+
117
+ end
118
+
119
+ describe "004: with commit message" do
120
+
121
+ before do
122
+ Dir.mkdir '004'
123
+ Dir.chdir '004'
124
+ File.open "main.cpp", "w" do |file|
125
+ file.write "ac-code"
126
+ end
127
+ bin_exec "init --defaults"
128
+ end
129
+
130
+ after do
131
+ Dir.chdir '..'
132
+ end
133
+
134
+ it "001" do
135
+ bin_exec "submit test_dummy -c 100 -p A -m 'this is commit message'"
136
+ ret = git_do "log --oneline"
137
+ ret.include? "this is commit message"
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+
@@ -0,0 +1,83 @@
1
+ require "spec_helper"
2
+
3
+ describe "T005" do
4
+
5
+ before(:each) do
6
+ init_env
7
+ ENV['GIT_CONTEST_HOME'] = get_path('/mock/default_config')
8
+ @test_dir = "#{ENV['GIT_CONTEST_TEMP_DIR']}/t005"
9
+ Dir.mkdir @test_dir
10
+ Dir.chdir @test_dir
11
+ # ENV['GIT_CONTEST_DEBUG'] = 'ON'
12
+ end
13
+
14
+ after(:each) do
15
+ Dir.chdir '..'
16
+ FileUtils.remove_dir @test_dir, :force => true
17
+ end
18
+
19
+ describe "001" do
20
+
21
+ before do
22
+ ENV['GIT_CONTEST_CONFIG'] = get_path('/mock/t005/001/config.yml')
23
+ Dir.mkdir '001'
24
+ Dir.chdir '001'
25
+ end
26
+
27
+ describe '001' do
28
+
29
+ before do
30
+ Dir.mkdir '001'
31
+ Dir.chdir '001'
32
+ end
33
+
34
+ it '001: init -> start -> submit -> submit -> finish' do
35
+ Dir.mkdir 'test1'
36
+ Dir.chdir 'test1'
37
+ # Init
38
+ bin_exec "init --defaults"
39
+ git_current_branch.should === 'master'
40
+ ret = git_do "log --oneline"
41
+ ret.include?('Initial commit').should === true
42
+ # Start
43
+ bin_exec "start contest1"
44
+ git_current_branch.should === 'contest/contest1'
45
+ # Edit.1
46
+ File.open 'main.c', 'w' do |file|
47
+ file.write 'wa-code'
48
+ end
49
+ # Submit.1
50
+ bin_exec "submit test_dummy -c 1000 -p A"
51
+ ret = git_do "log --oneline"
52
+ ret.include?('Dummy 1000A: Wrong Answer').should === true
53
+ ret = git_do "ls-files"
54
+ ret.include?('main.c').should === true
55
+ # Edit.2 fixed
56
+ File.open 'main.c', 'w' do |file|
57
+ file.write 'ac-code'
58
+ end
59
+ # Submit.2
60
+ bin_exec "submit test_dummy -c 1000 -p A"
61
+ ret = git_do "log --oneline"
62
+ ret.include?('Dummy 1000A: Accepted').should === true
63
+ ret = git_do "ls-files"
64
+ ret.include?('main.c').should === true
65
+ # Finish
66
+ bin_exec "finish --no-edit"
67
+ git_current_branch.should === 'master'
68
+ ret = git_do "log --oneline"
69
+ ret.include?('Dummy 1000A: Wrong Answer').should === true
70
+ ret.include?('Dummy 1000A: Accepted').should === true
71
+ # Clean
72
+ FileUtils.remove_dir '.git', :force => true
73
+ FileUtils.remove 'main.c'
74
+ Dir.chdir '..'
75
+ Dir.rmdir 'test1'
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
@@ -0,0 +1,121 @@
1
+ require "spec_helper"
2
+
3
+ describe "T007: git-contest-start" do
4
+
5
+ before(:each) do
6
+ init_env
7
+ @test_dir = "#{ENV['GIT_CONTEST_TEMP_DIR']}/t007"
8
+ Dir.mkdir @test_dir
9
+ Dir.chdir @test_dir
10
+ # debug_on
11
+ end
12
+
13
+ after(:each) do
14
+ Dir.chdir '..'
15
+ FileUtils.remove_dir @test_dir, :force => true
16
+ end
17
+
18
+ describe "001: specify based branch" do
19
+
20
+ before do
21
+ Dir.mkdir "001"
22
+ Dir.chdir "001"
23
+ bin_exec "init --defaults"
24
+ end
25
+
26
+ after do
27
+ Dir.chdir ".."
28
+ end
29
+
30
+ it "001" do
31
+ git_do "checkout -b base1"
32
+ git_do "commit --allow-empty -m 'this is commit'"
33
+ git_do "checkout master"
34
+ bin_exec "start test1"
35
+ ret1 = git_do "log --oneline"
36
+ ret1.include?("this is commit").should === false
37
+ bin_exec "start test2 base1"
38
+ ret2 = git_do "log --oneline"
39
+ ret2.include?("this is commit").should === true
40
+ end
41
+
42
+ it "002" do
43
+ git_do "checkout -b base1"
44
+ git_do "commit --allow-empty -m 'this is commit'"
45
+ git_do "checkout master"
46
+ bin_exec "start test1 base1"
47
+ ret1 = git_do "log --oneline"
48
+ ret1.include?("this is commit").should === true
49
+ bin_exec "start test2"
50
+ ret2 = git_do "log --oneline"
51
+ ret2.include?("this is commit").should === false
52
+ end
53
+
54
+ it "003" do
55
+ git_do "checkout -b base1"
56
+ git_do "commit --allow-empty -m 'this is commit'"
57
+ bin_exec "start test1 base1"
58
+ ret1 = git_do "log --oneline"
59
+ ret1.include?("this is commit").should === true
60
+ bin_exec "start test2"
61
+ ret2 = git_do "log --oneline"
62
+ ret2.include?("this is commit").should === false
63
+ end
64
+
65
+ it "004" do
66
+ git_do "checkout -b base1"
67
+ git_do "commit --allow-empty -m 'this is commit'"
68
+ bin_exec "start test1"
69
+ ret1 = git_do "log --oneline"
70
+ ret1.include?("this is commit").should === false
71
+ bin_exec "start test2 base1"
72
+ ret2 = git_do "log --oneline"
73
+ ret2.include?("this is commit").should === true
74
+ end
75
+
76
+ end
77
+
78
+ describe "002: --fetch" do
79
+
80
+ before do
81
+ Dir.mkdir "002"
82
+ Dir.chdir "002"
83
+ end
84
+
85
+ after do
86
+ Dir.chdir ".."
87
+ end
88
+
89
+ it "001" do
90
+ Dir.mkdir "test1"
91
+ Dir.chdir "test1"
92
+ bin_exec "init --defaults"
93
+ Dir.chdir ".."
94
+ git_do "clone test1 test2"
95
+ Dir.chdir "test1"
96
+ 10.times {|x| git_do "commit --allow-empty -m 'this is commit'" }
97
+ ret1 = git_do "log --oneline master"
98
+ Dir.chdir ".."
99
+ Dir.chdir "test2"
100
+ # init
101
+ bin_exec "init --defaults"
102
+ # fetch
103
+ ret2 = git_do "log --oneline origin/master"
104
+ ret_start1 = bin_exec "start branch1 --fetch"
105
+ ret3 = git_do "log --oneline origin/master"
106
+ git_do "pull origin master"
107
+ ret_start2 = bin_exec "start branch2 --fetch"
108
+ # check
109
+ ret1.include?("this is commit").should === true
110
+ ret2.include?("this is commit").should === false
111
+ ret3.include?("this is commit").should === true
112
+ ret_start1.include?("Summary of actions:").should === false
113
+ ret_start2.include?("Summary of actions:").should === true
114
+ # clean
115
+ Dir.chdir ".."
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+
@@ -0,0 +1,229 @@
1
+ require "spec_helper"
2
+
3
+ # Do not forget --no-edit option
4
+
5
+ describe "T008: git-contest-finish" do
6
+
7
+ before(:each) do
8
+ init_env
9
+ @test_dir = "#{ENV['GIT_CONTEST_TEMP_DIR']}/t008"
10
+ Dir.mkdir @test_dir
11
+ Dir.chdir @test_dir
12
+ # debug_on
13
+ end
14
+
15
+ after(:each) do
16
+ Dir.chdir '..'
17
+ FileUtils.remove_dir @test_dir, :force => true
18
+ end
19
+
20
+ describe "001: --keep" do
21
+
22
+ before do
23
+ Dir.mkdir "001"
24
+ Dir.chdir "001"
25
+ end
26
+
27
+ after do
28
+ Dir.chdir ".."
29
+ end
30
+
31
+ it "001: init -> start -> empty-commits -> finish" do
32
+ bin_exec "init --defaults"
33
+ bin_exec "start branch1"
34
+ git_do "commit --allow-empty -m 'this is commit'"
35
+ bin_exec "finish --no-edit"
36
+ ret1 = git_do "branch"
37
+ ret_log1 = git_do "log --oneline master"
38
+ ret1.include?("branch1").should === false
39
+ ret_log1.include?("this is commit").should === true
40
+ end
41
+
42
+ it "002: init -> start -> empty-commits -> finish --keep" do
43
+ bin_exec "init --defaults"
44
+ bin_exec "start branch1"
45
+ git_do "commit --allow-empty -m 'this is commit'"
46
+ bin_exec "finish --no-edit --keep"
47
+ ret1 = git_do "branch"
48
+ ret_log1 = git_do "log --oneline master"
49
+ ret1.include?("branch1").should === true
50
+ ret_log1.include?("this is commit").should === true
51
+ end
52
+
53
+ it "003: init -> start -> empty-commits -> finish -k" do
54
+ bin_exec "init --defaults"
55
+ bin_exec "start branch1"
56
+ git_do "commit --allow-empty -m 'this is commit'"
57
+ bin_exec "finish --no-edit -k"
58
+ ret1 = git_do "branch"
59
+ ret_log1 = git_do "log --oneline master"
60
+ ret1.include?("branch1").should === true
61
+ ret_log1.include?("this is commit").should === true
62
+ end
63
+
64
+ end
65
+
66
+ describe "002: --rebase" do
67
+
68
+ before do
69
+ Dir.mkdir "002"
70
+ Dir.chdir "002"
71
+ end
72
+
73
+ after do
74
+ Dir.chdir ".."
75
+ end
76
+
77
+ it "001: init -> start -> empty-commits -> finish --rebase" do
78
+ # create branches: branch1(normal) -> branch2(rebase) -> branch3(normal)
79
+ bin_exec "init --defaults"
80
+ bin_exec "start branch1"
81
+ 10.times {|x|
82
+ name = "test-1.#{x}"
83
+ FileUtils.touch name
84
+ git_do "add #{name}"
85
+ git_do "commit -m 'Add #{name}'"
86
+ }
87
+ bin_exec "start branch2"
88
+ 10.times {|x|
89
+ name = "test-2.#{x}"
90
+ FileUtils.touch name
91
+ git_do "add #{name}"
92
+ git_do "commit -m 'Add #{name}'"
93
+ }
94
+ bin_exec "start branch3"
95
+ 10.times {|x|
96
+ name = "test-3.#{x}"
97
+ FileUtils.touch name
98
+ git_do "add #{name}"
99
+ git_do "commit -m 'Add #{name}'"
100
+ }
101
+ # finish branches
102
+ ret_branch_1 = git_do "branch"
103
+ bin_exec "finish branch1 --no-edit"
104
+ bin_exec "finish branch2 --no-edit --rebase"
105
+ bin_exec "finish branch3 --no-edit"
106
+ ret_branch_2 = git_do "branch"
107
+ ret_log = git_do "log --oneline"
108
+ ret_branch_1.include?("branch1").should === true
109
+ ret_branch_1.include?("branch2").should === true
110
+ ret_branch_1.include?("branch3").should === true
111
+ ret_branch_2.include?("branch1").should === false
112
+ ret_branch_2.include?("branch2").should === false
113
+ ret_branch_2.include?("branch3").should === false
114
+ (!!ret_log.match(/test-2.*test-3.*test-1/m)).should === true
115
+ end
116
+
117
+ end
118
+
119
+ describe "003: --force-delete" do
120
+
121
+ before do
122
+ Dir.mkdir "003"
123
+ Dir.chdir "003"
124
+ end
125
+
126
+ after do
127
+ Dir.chdir ".."
128
+ end
129
+
130
+ # TODO: recheck
131
+ it "001: init -> start -> trigger merge error -> finish --force-delete" do
132
+ # make conflict
133
+ bin_exec "init --defaults"
134
+ FileUtils.touch "test.txt"
135
+ git_do "add test.txt"
136
+ git_do "commit -m 'Add test.txt'"
137
+ bin_exec "start branch1"
138
+ bin_exec "start branch2"
139
+ git_do "checkout contest/branch1"
140
+ File.open "test.txt", "w" do |file|
141
+ file.write "test1"
142
+ end
143
+ # git_do "add test.txt"
144
+ # git_do "commit -m 'Edit test.txt @ branch1'"
145
+ git_do "checkout contest/branch2"
146
+ File.open "test.txt", "w" do |file|
147
+ file.write "test2"
148
+ end
149
+ git_do "add test.txt"
150
+ git_do "commit -m 'Edit test.txt @ branch2'"
151
+ # finish
152
+ bin_exec "finish branch1 --no-edit"
153
+ bin_exec "finish branch2 --force-delete --no-edit"
154
+ ret_branch = git_do "branch"
155
+ ret_branch.include?("contest/branch1").should === false
156
+ ret_branch.include?("contest/branch2").should === false
157
+ end
158
+
159
+ end
160
+
161
+ describe "004: --squash" do
162
+
163
+ before do
164
+ Dir.mkdir "004"
165
+ Dir.chdir "004"
166
+ end
167
+
168
+ after do
169
+ Dir.chdir ".."
170
+ end
171
+
172
+ it "001: init -> start -> empty-commits -> finish --squash" do
173
+ bin_exec "init --defaults"
174
+ bin_exec "start branch1"
175
+ 10.times {|x|
176
+ filename = "test#{x}.txt"
177
+ FileUtils.touch filename
178
+ git_do "add #{filename}"
179
+ git_do "commit -m 'this is commit #{x}'"
180
+ }
181
+ bin_exec "finish --no-edit --squash branch1"
182
+ ret_log1 = git_do "log --oneline"
183
+ ret_branch1 = git_do "branch"
184
+ ret_branch1.include?("branch1").should === false
185
+ ret_log1.include?("this is commit").should === true
186
+ ret_log1.include?("Squashed commit").should === true
187
+ end
188
+
189
+ end
190
+
191
+ describe "005: --fetch" do
192
+
193
+ before do
194
+ Dir.mkdir "005"
195
+ Dir.chdir "005"
196
+ Dir.mkdir "src"
197
+ Dir.chdir "src"
198
+ bin_exec "init --defaults"
199
+ bin_exec "start branch1"
200
+ 10.times {|x| git_do "commit --allow-empty -m 'this is commit #{x}'" }
201
+ Dir.chdir ".."
202
+ git_do "clone src dest"
203
+
204
+ Dir.chdir "dest"
205
+ end
206
+
207
+ after do
208
+ Dir.chdir ".."
209
+ Dir.chdir ".."
210
+ end
211
+
212
+ it "001: init -> start -> clone -> checkout@dest -> empty-commits@dest -> finish@dest" do
213
+ git_do "checkout -b master origin/master"
214
+ bin_exec "init --defaults"
215
+ bin_exec "start --fetch branch1"
216
+ bin_exec "finish --fetch branch1 --no-edit"
217
+ ret_branch2 = git_do "branch"
218
+ Dir.chdir ".."
219
+ Dir.chdir "src"
220
+ ret_branch1 = git_do "branch"
221
+ git_do "checkout master"
222
+ ret_branch1.include?('branch1').should === true
223
+ ret_branch2.include?('branch1').should === false
224
+ end
225
+
226
+ end
227
+
228
+ end
229
+