letitcrash 0.1.0
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.
- checksums.yaml +7 -0
- data/lib/letitcrash/builders/file_builder.rb +75 -0
- data/lib/letitcrash/builders/report_builder.rb +52 -0
- data/lib/letitcrash/formatter.rb +29 -0
- data/lib/letitcrash/matcher.rb +46 -0
- data/lib/letitcrash/matchers/app_veyor.rb +19 -0
- data/lib/letitcrash/matchers/base.rb +31 -0
- data/lib/letitcrash/matchers/buildkite.rb +19 -0
- data/lib/letitcrash/matchers/circle_ci.rb +19 -0
- data/lib/letitcrash/matchers/codefresh.rb +20 -0
- data/lib/letitcrash/matchers/codeship.rb +19 -0
- data/lib/letitcrash/matchers/drone.rb +19 -0
- data/lib/letitcrash/matchers/git.rb +27 -0
- data/lib/letitcrash/matchers/gitlab_ci.rb +20 -0
- data/lib/letitcrash/matchers/jenkins.rb +20 -0
- data/lib/letitcrash/matchers/semaphore.rb +19 -0
- data/lib/letitcrash/matchers/shippable.rb +19 -0
- data/lib/letitcrash/matchers/snap_ci.rb +19 -0
- data/lib/letitcrash/matchers/solano_ci.rb +19 -0
- data/lib/letitcrash/matchers/team_city.rb +19 -0
- data/lib/letitcrash/matchers/travis_ci.rb +19 -0
- data/lib/letitcrash/matchers/wercker.rb +20 -0
- data/lib/letitcrash/proto/structs.rb +34 -0
- data/lib/letitcrash/reporters/stream.rb +19 -0
- data/lib/letitcrash/reporters/upload.rb +40 -0
- data/lib/letitcrash/sanitizer.rb +37 -0
- data/lib/letitcrash/version.rb +5 -0
- data/lib/letitcrash.rb +36 -0
- data/spec/builders/file_builder_spec.rb +68 -0
- data/spec/builders/report_builder_spec.rb +62 -0
- data/spec/formatter_spec.rb +57 -0
- data/spec/matcher_spec.rb +31 -0
- data/spec/matchers/app_veyor_spec.rb +44 -0
- data/spec/matchers/base_spec.rb +15 -0
- data/spec/matchers/buildkite_spec.rb +44 -0
- data/spec/matchers/circle_ci_spec.rb +44 -0
- data/spec/matchers/codefresh_spec.rb +34 -0
- data/spec/matchers/codeship_spec.rb +44 -0
- data/spec/matchers/drone_spec.rb +44 -0
- data/spec/matchers/git_spec.rb +60 -0
- data/spec/matchers/gitlab_ci_spec.rb +36 -0
- data/spec/matchers/jenkins_ci_spec.rb +36 -0
- data/spec/matchers/semaphore_spec.rb +44 -0
- data/spec/matchers/shared_helpers.rb +17 -0
- data/spec/matchers/shippable_spec.rb +44 -0
- data/spec/matchers/snap_ci_spec.rb +44 -0
- data/spec/matchers/solano_ci_spec.rb +36 -0
- data/spec/matchers/team_city_spec.rb +36 -0
- data/spec/matchers/travis_ci_spec.rb +44 -0
- data/spec/matchers/wercker_spec.rb +42 -0
- data/spec/reporters/stream_spec.rb +26 -0
- data/spec/reporters/upload_spec.rb +45 -0
- data/spec/sanitizer_spec.rb +23 -0
- data/spec/spec_helper.rb +19 -0
- metadata +374 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe Jenkins do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:jenkins_url) { 'true' }
|
11
|
+
let(:environment) do
|
12
|
+
{
|
13
|
+
'JENKINS_URL' => jenkins_url,
|
14
|
+
'GIT_BRANCH' => branch,
|
15
|
+
'GIT_COMMIT' => sha
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
it_behaves_like 'reports_branch_and_sha'
|
20
|
+
|
21
|
+
describe '#matches?' do
|
22
|
+
let(:result) { matcher.matches? }
|
23
|
+
|
24
|
+
context 'with JENKINS_URL set to `true` (default)' do
|
25
|
+
it { expect(result).to be_truthy }
|
26
|
+
end # context 'with JENKINS_URL set to `true` (default)'
|
27
|
+
|
28
|
+
context 'with JENKINS_URL set to nil' do
|
29
|
+
let(:jenkins_url) { nil }
|
30
|
+
|
31
|
+
it { expect(result).to be_falsey }
|
32
|
+
end # context 'with JENKINS_URL set to nil'
|
33
|
+
end # describe '#matches?'
|
34
|
+
end # RSpec.describe Jenkins
|
35
|
+
end # module Matchers
|
36
|
+
end # module LetItCrash
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe Semaphore do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:ci) { 'true' }
|
11
|
+
let(:semaphore) { 'true' }
|
12
|
+
let(:environment) do
|
13
|
+
{
|
14
|
+
'CI' => ci,
|
15
|
+
'SEMAPHORE' => semaphore,
|
16
|
+
'BRANCH_NAME' => branch,
|
17
|
+
'REVISION' => sha
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it_behaves_like 'reports_branch_and_sha'
|
22
|
+
|
23
|
+
describe '#matches?' do
|
24
|
+
let(:result) { matcher.matches? }
|
25
|
+
|
26
|
+
context 'with CI and SEMAPHORE set to `true` (default)' do
|
27
|
+
it { expect(result).to be_truthy }
|
28
|
+
end # context 'with CI and SEMAPHORE set to `true` (default)'
|
29
|
+
|
30
|
+
context 'with CI set to nil' do
|
31
|
+
let(:ci) { nil }
|
32
|
+
|
33
|
+
it { expect(result).to be_falsey }
|
34
|
+
end # context 'with CI set to nil'
|
35
|
+
|
36
|
+
context 'with SEMAPHORE set to nil' do
|
37
|
+
let(:semaphore) { nil }
|
38
|
+
|
39
|
+
it { expect(result).to be_falsey }
|
40
|
+
end # context 'with SEMAPHORE set to nil'
|
41
|
+
end # describe '#matches?'
|
42
|
+
end # RSpec.describe Semaphore
|
43
|
+
end # module Matchers
|
44
|
+
end # module LetItCrash
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_context 'with_branch_and_sha' do
|
4
|
+
let(:matcher) { described_class.new(environment: environment) }
|
5
|
+
let(:branch) { 'branch' }
|
6
|
+
let(:sha) { 'sha' }
|
7
|
+
end # RSpec.shared_context 'with_branch_and_sha'
|
8
|
+
|
9
|
+
RSpec.shared_examples 'reports_branch_and_sha' do
|
10
|
+
describe '#branch' do
|
11
|
+
it { expect(matcher.branch).to eq branch }
|
12
|
+
end # describe '#branch'
|
13
|
+
|
14
|
+
describe '#sha' do
|
15
|
+
it { expect(matcher.sha).to eq sha }
|
16
|
+
end # describe '#sha'
|
17
|
+
end # RSpec.shared_examples 'reports_branch_and_sha'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe Shippable do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:ci) { 'true' }
|
11
|
+
let(:shippable) { 'true' }
|
12
|
+
let(:environment) do
|
13
|
+
{
|
14
|
+
'CI' => ci,
|
15
|
+
'SHIPPABLE' => shippable,
|
16
|
+
'BRANCH' => branch,
|
17
|
+
'COMMIT' => sha
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it_behaves_like 'reports_branch_and_sha'
|
22
|
+
|
23
|
+
describe '#matches?' do
|
24
|
+
let(:result) { matcher.matches? }
|
25
|
+
|
26
|
+
context 'with CI and SHIPPABLE set to `true` (default)' do
|
27
|
+
it { expect(result).to be_truthy }
|
28
|
+
end # context 'with CI and SHIPPABLE set to `true` (default)'
|
29
|
+
|
30
|
+
context 'with CI set to nil' do
|
31
|
+
let(:ci) { nil }
|
32
|
+
|
33
|
+
it { expect(result).to be_falsey }
|
34
|
+
end # context 'with CI set to nil'
|
35
|
+
|
36
|
+
context 'with SHIPPABLE set to nil' do
|
37
|
+
let(:shippable) { nil }
|
38
|
+
|
39
|
+
it { expect(result).to be_falsey }
|
40
|
+
end # context 'with SHIPPABLE set to nil'
|
41
|
+
end # describe '#matches?'
|
42
|
+
end # RSpec.describe Shippable
|
43
|
+
end # module Matchers
|
44
|
+
end # module LetItCrash
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe SnapCI do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:ci) { 'true' }
|
11
|
+
let(:snap_ci) { 'true' }
|
12
|
+
let(:environment) do
|
13
|
+
{
|
14
|
+
'CI' => ci,
|
15
|
+
'SNAP_CI' => snap_ci,
|
16
|
+
'SNAP_BRANCH' => branch,
|
17
|
+
'SNAP_COMMIT' => sha
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it_behaves_like 'reports_branch_and_sha'
|
22
|
+
|
23
|
+
describe '#matches?' do
|
24
|
+
let(:result) { matcher.matches? }
|
25
|
+
|
26
|
+
context 'with CI and SNAP_CI set to `true` (default)' do
|
27
|
+
it { expect(result).to be_truthy }
|
28
|
+
end # context 'with CI and SNAP_CI set to `true` (default)'
|
29
|
+
|
30
|
+
context 'with CI set to nil' do
|
31
|
+
let(:ci) { nil }
|
32
|
+
|
33
|
+
it { expect(result).to be_falsey }
|
34
|
+
end # context 'with CI set to nil'
|
35
|
+
|
36
|
+
context 'with SNAP_CI set to nil' do
|
37
|
+
let(:snap_ci) { nil }
|
38
|
+
|
39
|
+
it { expect(result).to be_falsey }
|
40
|
+
end # context 'with SNAP_CI set to nil'
|
41
|
+
end # describe '#matches?'
|
42
|
+
end # RSpec.describe SnapCI
|
43
|
+
end # module Matchers
|
44
|
+
end # module LetItCrash
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe SolanoCI do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:tddium) { 'true' }
|
11
|
+
let(:environment) do
|
12
|
+
{
|
13
|
+
'TDDIUM' => tddium,
|
14
|
+
'TDDIUM_CURRENT_BRANCH' => branch,
|
15
|
+
'TDDIUM_CURRENT_COMMIT' => sha
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
it_behaves_like 'reports_branch_and_sha'
|
20
|
+
|
21
|
+
describe '#matches?' do
|
22
|
+
let(:result) { matcher.matches? }
|
23
|
+
|
24
|
+
context 'with TDDIUM set to `true` (default)' do
|
25
|
+
it { expect(result).to be_truthy }
|
26
|
+
end # context 'with TDDIUM set to `true` (default)'
|
27
|
+
|
28
|
+
context 'with TDDIUM set to nil' do
|
29
|
+
let(:tddium) { nil }
|
30
|
+
|
31
|
+
it { expect(result).to be_falsey }
|
32
|
+
end # context 'with TDDIUM set to nil'
|
33
|
+
end # describe '#matches?'
|
34
|
+
end # RSpec.describe SolanoCI
|
35
|
+
end # module Matchers
|
36
|
+
end # module LetItCrash
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe TeamCity do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:ci_server_name) { 'TeamCity' }
|
11
|
+
let(:environment) do
|
12
|
+
{
|
13
|
+
'CI_SERVER_NAME' => ci_server_name,
|
14
|
+
'TEAMCITY_BUILD_BRANCH' => branch,
|
15
|
+
'TEAMCITY_BUILD_COMMIT' => sha
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
it_behaves_like 'reports_branch_and_sha'
|
20
|
+
|
21
|
+
describe '#matches?' do
|
22
|
+
let(:result) { matcher.matches? }
|
23
|
+
|
24
|
+
context 'with CI_SERVER_NAME set to `TeamCity` (default)' do
|
25
|
+
it { expect(result).to be_truthy }
|
26
|
+
end # context 'with CI_SERVER_NAME set to `TeamCity` (default)'
|
27
|
+
|
28
|
+
context 'with CI_SERVER_NAME set to nil' do
|
29
|
+
let(:ci_server_name) { nil }
|
30
|
+
|
31
|
+
it { expect(result).to be_falsey }
|
32
|
+
end # context 'with CI_SERVER_NAME set to nil'
|
33
|
+
end # describe '#matches?'
|
34
|
+
end # RSpec.describe TeamCity
|
35
|
+
end # module Matchers
|
36
|
+
end # module LetItCrash
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe TravisCI do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:ci) { 'true' }
|
11
|
+
let(:travis) { 'true' }
|
12
|
+
let(:environment) do
|
13
|
+
{
|
14
|
+
'CI' => ci,
|
15
|
+
'TRAVIS' => travis,
|
16
|
+
'TRAVIS_BRANCH' => branch,
|
17
|
+
'TRAVIS_COMMIT' => sha
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it_behaves_like 'reports_branch_and_sha'
|
22
|
+
|
23
|
+
describe '#matches?' do
|
24
|
+
let(:result) { matcher.matches? }
|
25
|
+
|
26
|
+
context 'with CI and TRAVIS set to `true` (default)' do
|
27
|
+
it { expect(result).to be_truthy }
|
28
|
+
end # context 'with CI and TRAVIS set to `true` (default)'
|
29
|
+
|
30
|
+
context 'with CI set to nil' do
|
31
|
+
let(:ci) { nil }
|
32
|
+
|
33
|
+
it { expect(result).to be_falsey }
|
34
|
+
end # context 'with CI set to nil'
|
35
|
+
|
36
|
+
context 'with TRAVIS set to nil' do
|
37
|
+
let(:travis) { nil }
|
38
|
+
|
39
|
+
it { expect(result).to be_falsey }
|
40
|
+
end # context 'with TRAVIS set to nil'
|
41
|
+
end # describe '#matches?'
|
42
|
+
end # RSpec.describe TravisCI
|
43
|
+
end # module Matchers
|
44
|
+
end # module LetItCrash
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'matchers/shared_helpers'
|
5
|
+
|
6
|
+
module LetItCrash
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe Wercker do
|
9
|
+
include_context 'with_branch_and_sha'
|
10
|
+
let(:ci) { 'true' }
|
11
|
+
let(:environment) do
|
12
|
+
{
|
13
|
+
'CI' => ci,
|
14
|
+
'WERCKER_GIT_BRANCH' => branch,
|
15
|
+
'WERCKER_GIT_COMMIT' => sha
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
it_behaves_like 'reports_branch_and_sha'
|
20
|
+
|
21
|
+
describe '#matches?' do
|
22
|
+
let(:result) { matcher.matches? }
|
23
|
+
|
24
|
+
context 'when CI and WERCKER_GIT_BRANCH set (default)' do
|
25
|
+
it { expect(result).to be_truthy }
|
26
|
+
end # context 'when CI and WERCKER_GIT_BRANCH set (default)'
|
27
|
+
|
28
|
+
context 'when WERCKER_GIT_BRANCH not set' do
|
29
|
+
let(:branch) { nil }
|
30
|
+
|
31
|
+
it { expect(result).to be_falsey }
|
32
|
+
end # context 'when WERCKER_GIT_BRANCH not set'
|
33
|
+
|
34
|
+
context 'when CI not set' do
|
35
|
+
let(:ci) { nil }
|
36
|
+
|
37
|
+
it { expect(result).to be_falsey }
|
38
|
+
end # context 'when CI not set'
|
39
|
+
end # describe '#matches?'
|
40
|
+
end # RSpec.describe Wercker
|
41
|
+
end # module Matchers
|
42
|
+
end # module LetItCrash
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# rubocop:disable RSpec/VerifiedDoubles
|
6
|
+
module LetItCrash
|
7
|
+
module Reporters
|
8
|
+
RSpec.describe Stream do
|
9
|
+
let(:message) { 'message' }
|
10
|
+
let(:input) { double(to_json: message) }
|
11
|
+
let(:output) { StringIO.new }
|
12
|
+
let(:reporter) { described_class.new(output: output) }
|
13
|
+
|
14
|
+
describe '#report' do
|
15
|
+
let(:result) { reporter.report(input) }
|
16
|
+
|
17
|
+
it 'changes output' do
|
18
|
+
expect { result }
|
19
|
+
.to change { output.string }
|
20
|
+
.from('')
|
21
|
+
.to(message)
|
22
|
+
end
|
23
|
+
end # describe '#report'
|
24
|
+
end # RSpec.describe Stream
|
25
|
+
end # module Reporters
|
26
|
+
end # module LetItCrash
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# rubocop:disable RSpec/VerifiedDoubles, RSpec/MessageSpies
|
6
|
+
module LetItCrash
|
7
|
+
module Reporters
|
8
|
+
RSpec.describe Upload do
|
9
|
+
let(:message) { 'message' }
|
10
|
+
let(:input) { double(to_json: message) }
|
11
|
+
let(:endpoint) { 'endpoint' }
|
12
|
+
let(:token) { 'token' }
|
13
|
+
|
14
|
+
describe '.from_env' do
|
15
|
+
let(:reporter) { described_class.from_env }
|
16
|
+
|
17
|
+
before do
|
18
|
+
expect(ENV)
|
19
|
+
.to receive(:fetch)
|
20
|
+
.with('LETITCRASH_ENDPOINT', start_with('https://'))
|
21
|
+
.and_return(endpoint)
|
22
|
+
expect(ENV)
|
23
|
+
.to receive(:fetch)
|
24
|
+
.with('LETITCRASH_TOKEN')
|
25
|
+
.and_return(token)
|
26
|
+
end
|
27
|
+
|
28
|
+
it { expect(reporter).to be_a described_class }
|
29
|
+
end # describe '.from_env'
|
30
|
+
|
31
|
+
describe '#report' do
|
32
|
+
let(:reporter) { described_class.new(endpoint: endpoint, token: token) }
|
33
|
+
let(:result) { reporter.report(input) }
|
34
|
+
|
35
|
+
before do
|
36
|
+
expect(RestClient)
|
37
|
+
.to receive(:post)
|
38
|
+
.with(endpoint, message, include('X-LetItCrash-Token' => token))
|
39
|
+
end
|
40
|
+
|
41
|
+
it { expect { result }.not_to raise_error }
|
42
|
+
end # describe '#report'
|
43
|
+
end # RSpec.describe Upload
|
44
|
+
end # module Reporters
|
45
|
+
end # module LetItCrash
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module LetItCrash
|
6
|
+
describe Sanitizer do
|
7
|
+
let(:sanitizer) do
|
8
|
+
described_class.from_path(path: 'spec/fixtures/source.file')
|
9
|
+
end
|
10
|
+
|
11
|
+
it { expect(sanitizer).to be_a described_class }
|
12
|
+
it { expect(sanitizer).not_to include 1 }
|
13
|
+
it { expect(sanitizer).not_to include 2 }
|
14
|
+
it { expect(sanitizer).to include 3 }
|
15
|
+
it { expect(sanitizer).to include 4 }
|
16
|
+
it { expect(sanitizer).to include 5 }
|
17
|
+
it { expect(sanitizer).to include 6 }
|
18
|
+
it { expect(sanitizer).to include 7 }
|
19
|
+
it { expect(sanitizer).not_to include 8 }
|
20
|
+
it { expect(sanitizer).not_to include 9 }
|
21
|
+
it { expect(sanitizer).not_to include 10 }
|
22
|
+
end # describe Sanitizer
|
23
|
+
end # module LetItCrash
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
if ENV['CI'] == 'true'
|
9
|
+
require 'simplecov'
|
10
|
+
SimpleCov.start do
|
11
|
+
add_filter '/spec/'
|
12
|
+
add_filter '/lib/letitcrash/proto/'
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'codecov'
|
16
|
+
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'letitcrash'
|