br_documents 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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/config.yml +11 -25
  3. data/.rubocop.yml +29 -21
  4. data/.tool-versions +1 -0
  5. data/Gemfile.lock +6 -3
  6. data/Rakefile +1 -1
  7. data/br_documents.gemspec +3 -0
  8. data/lib/br_documents/cnpj_cpf/document.rb +1 -1
  9. data/lib/br_documents/{gtin/gtin.rb → gtin.rb} +2 -2
  10. data/lib/br_documents/ie/ba.rb +1 -1
  11. data/lib/br_documents/ie_validator.rb +1 -1
  12. data/lib/br_documents/suframa.rb +46 -0
  13. data/lib/br_documents/version.rb +1 -1
  14. data/spec/{cnpj_cpf → br_documents/cnpj_cpf}/cnpj_spec.rb +13 -13
  15. data/spec/{cnpj_cpf → br_documents/cnpj_cpf}/cpf_spec.rb +13 -13
  16. data/spec/br_documents/cnpj_validator_spec.rb +36 -0
  17. data/spec/br_documents/cpf_validator_spec.rb +36 -0
  18. data/spec/{gtin → br_documents}/gtin_spec.rb +2 -2
  19. data/spec/{gtin_validator_spec.rb → br_documents/gtin_validator_spec.rb} +3 -3
  20. data/spec/{ie → br_documents/ie}/ac_spec.rb +3 -3
  21. data/spec/{ie → br_documents/ie}/al_spec.rb +2 -2
  22. data/spec/{ie → br_documents/ie}/am_spec.rb +3 -3
  23. data/spec/{ie → br_documents/ie}/ap_spec.rb +2 -2
  24. data/spec/{ie → br_documents/ie}/ba_spec.rb +4 -4
  25. data/spec/{ie → br_documents/ie}/ce_spec.rb +0 -0
  26. data/spec/{ie → br_documents/ie}/df_spec.rb +3 -3
  27. data/spec/{ie → br_documents/ie}/es_spec.rb +0 -0
  28. data/spec/{ie → br_documents/ie}/factory_spec.rb +28 -28
  29. data/spec/{ie → br_documents/ie}/go_spec.rb +3 -3
  30. data/spec/{ie → br_documents/ie}/ma_spec.rb +0 -0
  31. data/spec/{ie → br_documents/ie}/mg_spec.rb +3 -3
  32. data/spec/{ie → br_documents/ie}/ms_spec.rb +0 -0
  33. data/spec/{ie → br_documents/ie}/mt_spec.rb +3 -3
  34. data/spec/{ie → br_documents/ie}/pa_spec.rb +3 -3
  35. data/spec/{ie → br_documents/ie}/pb_spec.rb +0 -0
  36. data/spec/{ie → br_documents/ie}/pe_spec.rb +4 -4
  37. data/spec/{ie → br_documents/ie}/pi_spec.rb +0 -0
  38. data/spec/{ie → br_documents/ie}/pr_spec.rb +2 -2
  39. data/spec/{ie → br_documents/ie}/rj_spec.rb +3 -3
  40. data/spec/{ie → br_documents/ie}/rn_spec.rb +4 -4
  41. data/spec/{ie → br_documents/ie}/ro_spec.rb +4 -4
  42. data/spec/{ie → br_documents/ie}/rr_spec.rb +3 -3
  43. data/spec/{ie → br_documents/ie}/rs_spec.rb +3 -3
  44. data/spec/{ie → br_documents/ie}/sc_spec.rb +3 -3
  45. data/spec/{ie → br_documents/ie}/se_spec.rb +0 -0
  46. data/spec/{ie → br_documents/ie}/shared_examples_for_pattern1.rb +3 -3
  47. data/spec/{ie → br_documents/ie}/shared_examples_for_to_remove_all_masks.rb +0 -0
  48. data/spec/{ie → br_documents/ie}/sp_spec.rb +2 -2
  49. data/spec/{ie → br_documents/ie}/to_spec.rb +6 -6
  50. data/spec/{ie_validator_spec.rb → br_documents/ie_validator_spec.rb} +7 -6
  51. data/spec/br_documents/suframa_spec.rb +73 -0
  52. data/spec/{suframa_validator_spec.rb → br_documents/suframa_validator_spec.rb} +4 -4
  53. metadata +97 -82
  54. data/lib/br_documents/suframa/suframa.rb +0 -60
  55. data/spec/cnpj_validator_spec.rb +0 -36
  56. data/spec/cpf_validator_spec.rb +0 -36
  57. data/spec/suframa/suframa_spec.rb +0 -109
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe CnpjValidator do
4
+ subject { described_class.new(attributes: 'cnpj') }
5
+
6
+ let(:mock) { instance_double('model') }
7
+
8
+ before do
9
+ allow(mock).to receive(:errors).and_return([])
10
+ allow(mock.errors).to receive(:messages).and_return({})
11
+ allow(mock.errors).to receive(:add) do |attribute, error|
12
+ mock.errors.messages[attribute] = [error]
13
+ end
14
+ end
15
+
16
+ context 'when Cnpj is valid' do
17
+ it "doesn't add errors in model" do
18
+ subject.validate_each(mock, 'cnpj', '85961757000102')
19
+ expect(mock.errors.messages).to be_empty
20
+ end
21
+ end
22
+
23
+ context 'when Cnpj is blank' do
24
+ it "doesn't add errors in model" do
25
+ subject.validate_each(mock, 'cnpj', '')
26
+ expect(mock.errors.messages).to be_empty
27
+ end
28
+ end
29
+
30
+ context 'when Cnpj is invalid' do
31
+ it 'adds errors in model' do
32
+ subject.validate_each(mock, 'cnpj', '85961757000103')
33
+ expect(mock.errors.messages).not_to be_empty
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe CpfValidator do
4
+ subject { described_class.new(attributes: 'cpf') }
5
+
6
+ let(:mock) { instance_double('model') }
7
+
8
+ before do
9
+ allow(mock).to receive(:errors).and_return([])
10
+ allow(mock.errors).to receive(:messages).and_return({})
11
+ allow(mock.errors).to receive(:add) do |attribute, error|
12
+ mock.errors.messages[attribute] = [error]
13
+ end
14
+ end
15
+
16
+ context 'when Cpf is valid' do
17
+ it "doesn't add errors in model" do
18
+ subject.validate_each(mock, 'cpf', '01233254120')
19
+ expect(mock.errors.messages).to be_empty
20
+ end
21
+ end
22
+
23
+ context 'when Cpf is blank' do
24
+ it "doesn't add errors in model" do
25
+ subject.validate_each(mock, 'cpf', '')
26
+ expect(mock.errors.messages).to be_empty
27
+ end
28
+ end
29
+
30
+ context 'when Cpf is invalid' do
31
+ it 'adds errors in model' do
32
+ subject.validate_each(mock, 'cpf', '01233254121')
33
+ expect(mock.errors.messages).not_to be_empty
34
+ end
35
+ end
36
+ end
@@ -36,14 +36,14 @@ describe BrDocuments::Gtin do
36
36
  context 'when the number of digits is different of 8, 13 or 14' do
37
37
  subject { described_class.new('12345678901234560') }
38
38
 
39
- it { is_expected.to_not be_valid }
39
+ it { is_expected.not_to be_valid }
40
40
  end
41
41
  end
42
42
 
43
43
  context 'when the checksum is invald' do
44
44
  subject { described_class.new('1145678548712') }
45
45
 
46
- it { is_expected.to_not be_valid }
46
+ it { is_expected.not_to be_valid }
47
47
  end
48
48
  end
49
49
  end
@@ -1,7 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GtinValidator do
4
- let(:record) { double('model') }
4
+ subject { described_class.new(attributes: 'gtin') }
5
+
6
+ let(:record) { instance_double('model') }
5
7
 
6
8
  before do
7
9
  allow(record).to receive(:errors).and_return([])
@@ -11,8 +13,6 @@ describe GtinValidator do
11
13
  end
12
14
  end
13
15
 
14
- subject { GtinValidator.new(attributes: 'gtin') }
15
-
16
16
  context 'when GTIN code is valid' do
17
17
  before { subject.validate_each(record, 'gtin', '1243658721548') }
18
18
 
@@ -13,21 +13,21 @@ RSpec.describe BrDocuments::IE::AC do
13
13
  it 'is invalid with malformed number' do
14
14
  ['01.448.52/88.91-50', '01.278.704/5555-7', '01.AB7.904/028-50'].each do |number|
15
15
  ie = described_class.new(number)
16
- expect(ie).to_not be_valid
16
+ expect(ie).not_to be_valid
17
17
  end
18
18
  end
19
19
 
20
20
  it 'is invalid with length different to 13' do
21
21
  ['1234567890', '123456789012'].each do |number|
22
22
  ie = described_class.new(number)
23
- expect(ie).to_not be_valid
23
+ expect(ie).not_to be_valid
24
24
  end
25
25
  end
26
26
 
27
27
  it 'is invalid with invalid check number' do
28
28
  ['0135184641523', '0172567054082'].each do |number|
29
29
  ie = described_class.new(number)
30
- expect(ie).to_not be_valid
30
+ expect(ie).not_to be_valid
31
31
  end
32
32
  end
33
33
 
@@ -13,14 +13,14 @@ describe BrDocuments::IE::AL do
13
13
  it 'is invalid with length different to 9' do
14
14
  ['1234567', '122345678901'].each do |number|
15
15
  ie = described_class.new(number)
16
- expect(ie).to_not be_valid
16
+ expect(ie).not_to be_valid
17
17
  end
18
18
  end
19
19
 
20
20
  it 'is invalid with invalid check number' do
21
21
  ['245320152', '240046248'].each do |number|
22
22
  ie = described_class.new(number)
23
- expect(ie).to_not be_valid
23
+ expect(ie).not_to be_valid
24
24
  end
25
25
  end
26
26
 
@@ -13,21 +13,21 @@ describe BrDocuments::IE::AM do
13
13
  it 'is invalid with malformed number' do
14
14
  ['8.535.410-60', '884.67.826-1', '13.BA9.093-6'].each do |number|
15
15
  ie = described_class.new(number)
16
- expect(ie).to_not be_valid
16
+ expect(ie).not_to be_valid
17
17
  end
18
18
  end
19
19
 
20
20
  it 'is invalid with length different to 9' do
21
21
  ['1234567', '12345678901'].each do |number|
22
22
  ie = described_class.new(number)
23
- expect(ie).to_not be_valid
23
+ expect(ie).not_to be_valid
24
24
  end
25
25
  end
26
26
 
27
27
  it 'is invalid with invalid check number' do
28
28
  ['500085276', '886770232'].each do |number|
29
29
  ie = described_class.new(number)
30
- expect(ie).to_not be_valid
30
+ expect(ie).not_to be_valid
31
31
  end
32
32
  end
33
33
 
@@ -13,14 +13,14 @@ RSpec.describe BrDocuments::IE::AP do
13
13
  it 'is invalid with length different to 9' do
14
14
  ['1234567', '123456789012'].each do |number|
15
15
  ie = described_class.new(number)
16
- expect(ie).to_not be_valid
16
+ expect(ie).not_to be_valid
17
17
  end
18
18
  end
19
19
 
20
20
  it 'is invalid with invalid check number' do
21
21
  ['030123456', '030182454'].each do |number|
22
22
  ie = described_class.new(number)
23
- expect(ie).to_not be_valid
23
+ expect(ie).not_to be_valid
24
24
  end
25
25
  end
26
26
 
@@ -22,14 +22,14 @@ RSpec.describe BrDocuments::IE::BA do
22
22
  it 'is invalid with malformed number' do
23
23
  ['82.060.187.373', '528843171-72', 'AD402552219'].each do |number|
24
24
  ie = described_class.new(number)
25
- expect(ie).to_not be_valid
25
+ expect(ie).not_to be_valid
26
26
  end
27
27
  end
28
28
 
29
29
  it 'is invalid with length different to 8 or 9' do
30
30
  ['1234567', '1234567890'].each do |number|
31
31
  ie = described_class.new(number)
32
- expect(ie).to_not be_valid
32
+ expect(ie).not_to be_valid
33
33
  end
34
34
  end
35
35
 
@@ -37,7 +37,7 @@ RSpec.describe BrDocuments::IE::BA do
37
37
  it 'is invalid with invalid check number' do
38
38
  ['12345682', '61934523', '39034325'].each do |number|
39
39
  ie = described_class.new(number)
40
- expect(ie).to_not be_valid
40
+ expect(ie).not_to be_valid
41
41
  end
42
42
  end
43
43
 
@@ -52,7 +52,7 @@ RSpec.describe BrDocuments::IE::BA do
52
52
  context 'when having 9 digits' do
53
53
  it 'is invalid with invalid check number' do
54
54
  ie = described_class.new('100052398')
55
- expect(ie).to_not be_valid
55
+ expect(ie).not_to be_valid
56
56
  end
57
57
 
58
58
  it 'is valid with valid number' do
File without changes
@@ -13,21 +13,21 @@ describe BrDocuments::IE::DF do
13
13
  it 'is invalid with malformed number' do
14
14
  ['070648022871-3', '07.064.802.287-13', '0AB49871799-12'].each do |number|
15
15
  ie = described_class.new(number)
16
- expect(ie).to_not be_valid
16
+ expect(ie).not_to be_valid
17
17
  end
18
18
  end
19
19
 
20
20
  it 'is invalid with length different to 13' do
21
21
  ['1234567890', '123456789012345'].each do |number|
22
22
  ie = described_class.new(number)
23
- expect(ie).to_not be_valid
23
+ expect(ie).not_to be_valid
24
24
  end
25
25
  end
26
26
 
27
27
  it 'is invalid with invalid check number' do
28
28
  ['0733002219945', '0733002219943'].each do |number|
29
29
  ie = described_class.new(number)
30
- expect(ie).to_not be_valid
30
+ expect(ie).not_to be_valid
31
31
  end
32
32
  end
33
33
 
File without changes
@@ -4,189 +4,189 @@ describe BrDocuments::IE::Factory do
4
4
  describe '.create' do
5
5
  context 'when uf is AC' do
6
6
  it 'returns an instance of BrDocuments::IE::AC' do
7
- ie = BrDocuments::IE::Factory.create('AC', '123456789')
7
+ ie = described_class.create('AC', '123456789')
8
8
  expect(ie).to be_an_instance_of BrDocuments::IE::AC
9
9
  end
10
10
  end
11
11
 
12
12
  context 'when uf is AL' do
13
13
  it 'returns an instance of BrDocuments::IE::AL' do
14
- ie = BrDocuments::IE::Factory.create('AL', '123456789')
14
+ ie = described_class.create('AL', '123456789')
15
15
  expect(ie).to be_an_instance_of BrDocuments::IE::AL
16
16
  end
17
17
  end
18
18
 
19
19
  context 'when uf is AP' do
20
20
  it 'returns an instance of BrDocuments::IE::AP' do
21
- ie = BrDocuments::IE::Factory.create('AP', '123456789')
21
+ ie = described_class.create('AP', '123456789')
22
22
  expect(ie).to be_an_instance_of BrDocuments::IE::AP
23
23
  end
24
24
  end
25
25
 
26
26
  context 'when uf is AM' do
27
27
  it 'returns an instance of BrDocuments::IE::AM' do
28
- ie = BrDocuments::IE::Factory.create('AM', '123456789')
28
+ ie = described_class.create('AM', '123456789')
29
29
  expect(ie).to be_an_instance_of BrDocuments::IE::AM
30
30
  end
31
31
  end
32
32
 
33
33
  context 'when uf is BA' do
34
34
  it 'returns an instance of BrDocuments::IE::BA' do
35
- ie = BrDocuments::IE::Factory.create('BA', '123456789')
35
+ ie = described_class.create('BA', '123456789')
36
36
  expect(ie).to be_an_instance_of BrDocuments::IE::BA
37
37
  end
38
38
  end
39
39
 
40
40
  context 'when uf is CE' do
41
41
  it 'returns an instance of BrDocuments::IE::CE' do
42
- ie = BrDocuments::IE::Factory.create('CE', '123456789')
42
+ ie = described_class.create('CE', '123456789')
43
43
  expect(ie).to be_an_instance_of BrDocuments::IE::CE
44
44
  end
45
45
  end
46
46
 
47
47
  context 'when uf is DF' do
48
48
  it 'returns an instance of BrDocuments::IE::DF' do
49
- ie = BrDocuments::IE::Factory.create('DF', '123456789')
49
+ ie = described_class.create('DF', '123456789')
50
50
  expect(ie).to be_an_instance_of BrDocuments::IE::DF
51
51
  end
52
52
  end
53
53
 
54
54
  context 'when uf is ES' do
55
55
  it 'returns an instance of BrDocuments::IE::ES' do
56
- ie = BrDocuments::IE::Factory.create('ES', '123456789')
56
+ ie = described_class.create('ES', '123456789')
57
57
  expect(ie).to be_an_instance_of BrDocuments::IE::ES
58
58
  end
59
59
  end
60
60
 
61
61
  context 'when uf is GO' do
62
62
  it 'returns an instance of BrDocuments::IE::GO' do
63
- ie = BrDocuments::IE::Factory.create('GO', '123456789')
63
+ ie = described_class.create('GO', '123456789')
64
64
  expect(ie).to be_an_instance_of BrDocuments::IE::GO
65
65
  end
66
66
  end
67
67
 
68
68
  context 'when uf is MA' do
69
69
  it 'returns an instance of BrDocuments::IE::MA' do
70
- ie = BrDocuments::IE::Factory.create('MA', '123456789')
70
+ ie = described_class.create('MA', '123456789')
71
71
  expect(ie).to be_an_instance_of BrDocuments::IE::MA
72
72
  end
73
73
  end
74
74
 
75
75
  context 'when uf is MG' do
76
76
  it 'returns an instance of BrDocuments::IE::MG' do
77
- ie = BrDocuments::IE::Factory.create('MG', '123456789')
77
+ ie = described_class.create('MG', '123456789')
78
78
  expect(ie).to be_an_instance_of BrDocuments::IE::MG
79
79
  end
80
80
  end
81
81
 
82
82
  context 'when uf is MS' do
83
83
  it 'returns an instance of BrDocuments::IE::MS' do
84
- ie = BrDocuments::IE::Factory.create('MS', '123456789')
84
+ ie = described_class.create('MS', '123456789')
85
85
  expect(ie).to be_an_instance_of BrDocuments::IE::MS
86
86
  end
87
87
  end
88
88
 
89
89
  context 'when uf is MT' do
90
90
  it 'returns an instance of BrDocuments::IE::MT' do
91
- ie = BrDocuments::IE::Factory.create('MT', '123456789')
91
+ ie = described_class.create('MT', '123456789')
92
92
  expect(ie).to be_an_instance_of BrDocuments::IE::MT
93
93
  end
94
94
  end
95
95
 
96
96
  context 'when uf is PA' do
97
97
  it 'returns an instance of BrDocuments::IE::PA' do
98
- ie = BrDocuments::IE::Factory.create('PA', '123456789')
98
+ ie = described_class.create('PA', '123456789')
99
99
  expect(ie).to be_an_instance_of BrDocuments::IE::PA
100
100
  end
101
101
  end
102
102
 
103
103
  context 'when uf is PB' do
104
104
  it 'returns an instance of BrDocuments::IE::PB' do
105
- ie = BrDocuments::IE::Factory.create('PB', '123456789')
105
+ ie = described_class.create('PB', '123456789')
106
106
  expect(ie).to be_an_instance_of BrDocuments::IE::PB
107
107
  end
108
108
  end
109
109
 
110
110
  context 'when uf is PR' do
111
111
  it 'returns an instance of BrDocuments::IE::PR' do
112
- ie = BrDocuments::IE::Factory.create('PR', '123456789')
112
+ ie = described_class.create('PR', '123456789')
113
113
  expect(ie).to be_an_instance_of BrDocuments::IE::PR
114
114
  end
115
115
  end
116
116
 
117
117
  context 'when uf is PE' do
118
118
  it 'returns an instance of BrDocuments::IE::PE' do
119
- ie = BrDocuments::IE::Factory.create('PE', '123456789')
119
+ ie = described_class.create('PE', '123456789')
120
120
  expect(ie).to be_an_instance_of BrDocuments::IE::PE
121
121
  end
122
122
  end
123
123
 
124
124
  context 'when uf is PI' do
125
125
  it 'returns an instance of BrDocuments::IE::PI' do
126
- ie = BrDocuments::IE::Factory.create('PI', '123456789')
126
+ ie = described_class.create('PI', '123456789')
127
127
  expect(ie).to be_an_instance_of BrDocuments::IE::PI
128
128
  end
129
129
  end
130
130
 
131
131
  context 'when uf is RJ' do
132
132
  it 'returns an instance of BrDocuments::IE::RJ' do
133
- ie = BrDocuments::IE::Factory.create('RJ', '123456789')
133
+ ie = described_class.create('RJ', '123456789')
134
134
  expect(ie).to be_an_instance_of BrDocuments::IE::RJ
135
135
  end
136
136
  end
137
137
 
138
138
  context 'when uf is returns' do
139
139
  it 'returns an instance of BrDocuments::IE::RN' do
140
- ie = BrDocuments::IE::Factory.create('RN', '123456789')
140
+ ie = described_class.create('RN', '123456789')
141
141
  expect(ie).to be_an_instance_of BrDocuments::IE::RN
142
142
  end
143
143
  end
144
144
 
145
145
  context 'when uf is RS' do
146
146
  it 'returns an instance of BrDocuments::IE::RS' do
147
- ie = BrDocuments::IE::Factory.create('RS', '123456789')
147
+ ie = described_class.create('RS', '123456789')
148
148
  expect(ie).to be_an_instance_of BrDocuments::IE::RS
149
149
  end
150
150
  end
151
151
 
152
152
  context 'when uf is RO' do
153
153
  it 'returns an instance of BrDocuments::IE::RO' do
154
- ie = BrDocuments::IE::Factory.create('RO', '123456789')
154
+ ie = described_class.create('RO', '123456789')
155
155
  expect(ie).to be_an_instance_of BrDocuments::IE::RO
156
156
  end
157
157
  end
158
158
 
159
159
  context 'when uf is RR' do
160
160
  it 'returns an instance of BrDocuments::IE::RR' do
161
- ie = BrDocuments::IE::Factory.create('RR', '123456789')
161
+ ie = described_class.create('RR', '123456789')
162
162
  expect(ie).to be_an_instance_of BrDocuments::IE::RR
163
163
  end
164
164
  end
165
165
 
166
166
  context 'when uf is SC' do
167
167
  it 'returns an instance of BrDocuments::IE::SC' do
168
- ie = BrDocuments::IE::Factory.create('SC', '123456789')
168
+ ie = described_class.create('SC', '123456789')
169
169
  expect(ie).to be_an_instance_of BrDocuments::IE::SC
170
170
  end
171
171
  end
172
172
 
173
173
  context 'when uf is SP' do
174
174
  it 'returns an instance of BrDocuments::IE::SP' do
175
- ie = BrDocuments::IE::Factory.create('SP', '123456789')
175
+ ie = described_class.create('SP', '123456789')
176
176
  expect(ie).to be_an_instance_of BrDocuments::IE::SP
177
177
  end
178
178
  end
179
179
 
180
180
  context 'when uf is SE' do
181
181
  it 'returns an instance of BrDocuments::IE::SE' do
182
- ie = BrDocuments::IE::Factory.create('SE', '123456789')
182
+ ie = described_class.create('SE', '123456789')
183
183
  expect(ie).to be_an_instance_of BrDocuments::IE::SE
184
184
  end
185
185
  end
186
186
 
187
187
  context 'when uf is TO' do
188
188
  it 'returns an instance of BrDocuments::IE::TO' do
189
- ie = BrDocuments::IE::Factory.create('TO', '123456789')
189
+ ie = described_class.create('TO', '123456789')
190
190
  expect(ie).to be_an_instance_of BrDocuments::IE::TO
191
191
  end
192
192
  end
@@ -194,7 +194,7 @@ describe BrDocuments::IE::Factory do
194
194
  context 'when uf is invalid' do
195
195
  it 'is returns an error' do
196
196
  expect do
197
- BrDocuments::IE::Factory.create('', '')
197
+ described_class.create('', '')
198
198
  end.to raise_error(ArgumentError, t('validator.ie.uf.invalid'))
199
199
  end
200
200
  end