fbo 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +2 -2
- data/README.md +23 -0
- data/lib/fbo.rb +17 -0
- data/lib/fbo/notices/archive.rb +8 -0
- data/lib/fbo/notices/fair_opportunity.rb +15 -0
- data/lib/fbo/notices/foreign_standard.rb +13 -0
- data/lib/fbo/notices/intent_to_bundle.rb +13 -0
- data/lib/fbo/notices/justification_approval.rb +18 -0
- data/lib/fbo/notices/sale_of_surplus.rb +13 -0
- data/lib/fbo/notices/special_notice.rb +13 -0
- data/lib/fbo/notices/unarchive.rb +9 -0
- data/lib/fbo/parser.rb +2 -15
- data/lib/fbo/parser/archive_handler.rb +41 -0
- data/lib/fbo/parser/fair_opportunity_handler.rb +61 -0
- data/lib/fbo/parser/foreign_standard_handler.rb +57 -0
- data/lib/fbo/parser/handler_selector.rb +37 -0
- data/lib/fbo/parser/intent_to_bundle_handler.rb +56 -0
- data/lib/fbo/parser/justification_approval_handler.rb +60 -0
- data/lib/fbo/parser/parser_helper.rb +40 -0
- data/lib/fbo/parser/sale_of_surplus_handler.rb +57 -0
- data/lib/fbo/parser/special_notice_handler.rb +57 -0
- data/lib/fbo/parser/unarchive_handler.rb +42 -0
- data/lib/fbo/version.rb +1 -1
- data/spec/fbo/parser/amendment_handler_spec.rb +28 -23
- data/spec/fbo/parser/archive_handler_spec.rb +36 -0
- data/spec/fbo/parser/award_handler_spec.rb +5 -0
- data/spec/fbo/parser/combined_solicitation_handler_spec.rb +4 -0
- data/spec/fbo/parser/fair_opportunity_handler_spec.rb +56 -0
- data/spec/fbo/parser/foreign_standard_handler_spec.rb +51 -0
- data/spec/fbo/parser/handler_selector_spec.rb +40 -0
- data/spec/fbo/parser/intent_to_bundle_handler_spec.rb +52 -0
- data/spec/fbo/parser/justification_approval_handler_spec.rb +53 -0
- data/spec/fbo/parser/modification_handler_spec.rb +5 -0
- data/spec/fbo/parser/presolicitation_handler_spec.rb +5 -0
- data/spec/fbo/parser/sale_of_surplus_handler_spec.rb +53 -0
- data/spec/fbo/parser/sources_sought_handler_spec.rb +27 -22
- data/spec/fbo/parser/special_notice_handler_spec.rb +53 -0
- data/spec/fbo/parser/unarchive_handler_spec.rb +37 -0
- data/spec/fbo/parser/unknown_handler_spec.rb +5 -0
- data/spec/fbo/parser_spec.rb +18 -49
- data/spec/fixtures/notices/archive +10 -0
- data/spec/fixtures/notices/fairopp +29 -0
- data/spec/fixtures/notices/fstd +24 -0
- data/spec/fixtures/notices/itb +19 -0
- data/spec/fixtures/notices/ja +30 -0
- data/spec/fixtures/notices/notanotice +7 -0
- data/spec/fixtures/notices/ssale +24 -0
- data/spec/fixtures/notices/unarchive +10 -0
- metadata +53 -2
@@ -0,0 +1,56 @@
|
|
1
|
+
module FBO::Parser::IntentToBundleHandler
|
2
|
+
TAGS = %w( ITB DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
|
3
|
+
%w( OFFICE LOCATION SUBJECT SOLNBR NTYPE ARCHDATE CONTACT DESC AWDNBR ) +
|
4
|
+
%w( DONBR LINK URL EMAIL ADDRESS \/ITB )
|
5
|
+
|
6
|
+
ANY_ITB_TAG = TAGS.join("|")
|
7
|
+
INTENT_TO_BUNDLE_PATTERN = /^<ITB>/
|
8
|
+
|
9
|
+
|
10
|
+
def is_intent_to_bundle?(text)
|
11
|
+
text =~ INTENT_TO_BUNDLE_PATTERN
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(text)
|
15
|
+
params = {
|
16
|
+
date: date(text),
|
17
|
+
year: year(text),
|
18
|
+
zip: zip(text),
|
19
|
+
class_code: classification_code(text),
|
20
|
+
naics_code: naics_code(text),
|
21
|
+
agency: agency(text),
|
22
|
+
office: office(text),
|
23
|
+
location: location(text),
|
24
|
+
office_address: office_address(text),
|
25
|
+
subject: subject(text),
|
26
|
+
solicitation_number: solicitation_number(text),
|
27
|
+
archive_date: archive_date(text),
|
28
|
+
contact_info: contact(text),
|
29
|
+
description: description(text),
|
30
|
+
notice_type: notice_type(text),
|
31
|
+
award_number: award_number(text),
|
32
|
+
delivery_order_number: delivery_order_number(text),
|
33
|
+
link_url: link_url(text),
|
34
|
+
link_description: link_description(text),
|
35
|
+
email_address: email_address(text),
|
36
|
+
email_description: email_description(text),
|
37
|
+
correction: correction?(text)
|
38
|
+
}
|
39
|
+
FBO::Notices::IntentToBundle.new(params)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
# Returns a concatenated list of all tags for the notice
|
46
|
+
#
|
47
|
+
# @return [String]
|
48
|
+
def any_notice_tag
|
49
|
+
ANY_ITB_TAG
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
extend FBO::Parser::NoticeHandler
|
54
|
+
extend FBO::Parser::ParserHelper
|
55
|
+
extend self
|
56
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module FBO::Parser::JustificationApprovalHandler
|
2
|
+
TAGS = %w( JA DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD ) +
|
3
|
+
%w( AGENCY OFFICE LOCATION SUBJECT SOLNBR NTYPE DESC CONTACT AWDNBR ) +
|
4
|
+
%w( AWDDATE ARCHDATE LINK URL EMAIL ADDRESS STAUTH MODNBR ) +
|
5
|
+
%w( FILELIST FILE MIMETYPE /FILE /FILELIST CORRECTION /JA )
|
6
|
+
|
7
|
+
ANY_JUSTIFICATION_APPROVAL_TAG = TAGS.join("|")
|
8
|
+
JA_PATTERN = /^<JA>/
|
9
|
+
|
10
|
+
|
11
|
+
def is_justification_approval?(text)
|
12
|
+
text =~ JA_PATTERN
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(text)
|
16
|
+
params = {
|
17
|
+
date: date(text),
|
18
|
+
year: year(text),
|
19
|
+
zip: zip(text),
|
20
|
+
class_code: classification_code(text),
|
21
|
+
naics_code: naics_code(text),
|
22
|
+
agency: agency(text),
|
23
|
+
office: office(text),
|
24
|
+
location: location(text),
|
25
|
+
office_address: office_address(text),
|
26
|
+
subject: subject(text),
|
27
|
+
solicitation_number: solicitation_number(text),
|
28
|
+
notice_type: notice_type(text),
|
29
|
+
description: description(text),
|
30
|
+
contact_info: contact(text),
|
31
|
+
statutory_authority: statutory_authority(text),
|
32
|
+
award_number: award_number(text),
|
33
|
+
modification_number: modification_number(text),
|
34
|
+
award_date: award_date(text),
|
35
|
+
archive_date: archive_date(text),
|
36
|
+
link_url: link_url(text),
|
37
|
+
link_description: link_description(text),
|
38
|
+
email_address: email_address(text),
|
39
|
+
email_description: email_description(text),
|
40
|
+
file_list: file_list(text),
|
41
|
+
correction: correction?(text)
|
42
|
+
}
|
43
|
+
FBO::Notices::JustificationApproval.new(params)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# Returns a concatenated list of all tags for the notice
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def any_notice_tag
|
53
|
+
ANY_JUSTIFICATION_APPROVAL_TAG
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
extend FBO::Parser::NoticeHandler
|
58
|
+
extend FBO::Parser::ParserHelper
|
59
|
+
extend self
|
60
|
+
end
|
@@ -272,4 +272,44 @@ module FBO::Parser::ParserHelper
|
|
272
272
|
false
|
273
273
|
end
|
274
274
|
|
275
|
+
# Get the file list associated with the notice.
|
276
|
+
#
|
277
|
+
# @param text [String] the full text of the notice
|
278
|
+
# @return [Array] the file list
|
279
|
+
def file_list(text)
|
280
|
+
[]
|
281
|
+
end
|
282
|
+
|
283
|
+
# Get the statutory authority.
|
284
|
+
#
|
285
|
+
# @param text [String] the full text of the notice
|
286
|
+
# @return [String] the name of the statutory authority
|
287
|
+
def statutory_authority(text)
|
288
|
+
simple_tag_contents(text, "STAUTH")
|
289
|
+
end
|
290
|
+
|
291
|
+
# Get the modification number.
|
292
|
+
#
|
293
|
+
# @param text [String] the full text of the notice
|
294
|
+
# @return [String] the modification number
|
295
|
+
def modification_number(text)
|
296
|
+
simple_tag_contents(text, "MODNBR")
|
297
|
+
end
|
298
|
+
|
299
|
+
# Get the delivery order number.
|
300
|
+
#
|
301
|
+
# @param text [String] the full text of the notice
|
302
|
+
# @return [String] the delivery order number
|
303
|
+
def delivery_order_number(text)
|
304
|
+
simple_tag_contents(text, "DONBR")
|
305
|
+
end
|
306
|
+
|
307
|
+
# Get the justification authority (reason).
|
308
|
+
#
|
309
|
+
# @param text [String] the full text of the notice
|
310
|
+
# @return [String] the judstification authority
|
311
|
+
def justification_authority(text)
|
312
|
+
simple_tag_contents(text, "FOJA")
|
313
|
+
end
|
314
|
+
|
275
315
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module FBO::Parser::SaleOfSurplusHandler
|
2
|
+
TAGS = %w( SSALE DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
|
3
|
+
%w( OFFICE LOCATION SUBJECT SOLNBR RESPDATE ARCHDATE CONTACT DESC LINK ) +
|
4
|
+
%w( URL EMAIL ADDRESS SETASIDE POPADDRESS POPZIP POPCOUNTRY \/SSALE )
|
5
|
+
|
6
|
+
ANY_SSALE_TAG = TAGS.join("|")
|
7
|
+
SALE_OF_SURPLUS_PATTERN = /^<SSALE>/
|
8
|
+
|
9
|
+
|
10
|
+
def is_sale_of_surplus?(text)
|
11
|
+
text =~ SALE_OF_SURPLUS_PATTERN
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(text)
|
15
|
+
params = {
|
16
|
+
date: date(text),
|
17
|
+
year: year(text),
|
18
|
+
zip: zip(text),
|
19
|
+
class_code: classification_code(text),
|
20
|
+
naics_code: naics_code(text),
|
21
|
+
agency: agency(text),
|
22
|
+
office: office(text),
|
23
|
+
location: location(text),
|
24
|
+
office_address: office_address(text),
|
25
|
+
subject: subject(text),
|
26
|
+
solicitation_number: solicitation_number(text),
|
27
|
+
response_date: response_date(text),
|
28
|
+
archive_date: archive_date(text),
|
29
|
+
contact_info: contact(text),
|
30
|
+
description: description(text),
|
31
|
+
link_url: link_url(text),
|
32
|
+
link_description: link_description(text),
|
33
|
+
email_address: email_address(text),
|
34
|
+
email_description: email_description(text),
|
35
|
+
setaside: set_aside(text),
|
36
|
+
pop_address: pop_address(text),
|
37
|
+
pop_zip: pop_zip_code(text),
|
38
|
+
pop_country: pop_country(text)
|
39
|
+
}
|
40
|
+
FBO::Notices::SaleOfSurplus.new(params)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
# Returns a concatenated list of all tags for the notice
|
47
|
+
#
|
48
|
+
# @return [String]
|
49
|
+
def any_notice_tag
|
50
|
+
ANY_SSALE_TAG
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
extend FBO::Parser::NoticeHandler
|
55
|
+
extend FBO::Parser::ParserHelper
|
56
|
+
extend self
|
57
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module FBO::Parser::SpecialNoticeHandler
|
2
|
+
TAGS = %w( SNOTE DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
|
3
|
+
%w( OFFICE LOCATION SUBJECT SOLNBR RESPDATE ARCHDATE CONTACT DESC LINK ) +
|
4
|
+
%w( URL EMAIL ADDRESS SETASIDE POPADDRESS POPZIP POPCOUNTRY \/SNOTE )
|
5
|
+
|
6
|
+
ANY_SNOTE_TAG = TAGS.join("|")
|
7
|
+
SPECIAL_NOTICE_PATTERN = /^<SNOTE>/
|
8
|
+
|
9
|
+
|
10
|
+
def is_special_notice?(text)
|
11
|
+
text =~ SPECIAL_NOTICE_PATTERN
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(text)
|
15
|
+
params = {
|
16
|
+
date: date(text),
|
17
|
+
year: year(text),
|
18
|
+
zip: zip(text),
|
19
|
+
class_code: classification_code(text),
|
20
|
+
naics_code: naics_code(text),
|
21
|
+
agency: agency(text),
|
22
|
+
office: office(text),
|
23
|
+
location: location(text),
|
24
|
+
office_address: office_address(text),
|
25
|
+
subject: subject(text),
|
26
|
+
solicitation_number: solicitation_number(text),
|
27
|
+
response_date: response_date(text),
|
28
|
+
archive_date: archive_date(text),
|
29
|
+
contact_info: contact(text),
|
30
|
+
description: description(text),
|
31
|
+
link_url: link_url(text),
|
32
|
+
link_description: link_description(text),
|
33
|
+
email_address: email_address(text),
|
34
|
+
email_description: email_description(text),
|
35
|
+
setaside: set_aside(text),
|
36
|
+
pop_address: pop_address(text),
|
37
|
+
pop_zip: pop_zip_code(text),
|
38
|
+
pop_country: pop_country(text)
|
39
|
+
}
|
40
|
+
FBO::Notices::SpecialNotice.new(params)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
# Returns a concatenated list of all tags for the notice
|
47
|
+
#
|
48
|
+
# @return [String]
|
49
|
+
def any_notice_tag
|
50
|
+
ANY_SNOTE_TAG
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
extend FBO::Parser::NoticeHandler
|
55
|
+
extend FBO::Parser::ParserHelper
|
56
|
+
extend self
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module FBO::Parser::UnarchiveHandler
|
2
|
+
TAGS = %w( UNARCHIVE DATE YEAR CBAC PASSWORD AGENCY OFFICE LOCATION NTYPE ) +
|
3
|
+
%w( SOLNBR ARCHDATE AWDNBR \/UNARCHIVE )
|
4
|
+
|
5
|
+
ANY_UNARCHIVE_TAG = TAGS.join("|")
|
6
|
+
UNARCHIVE_PATTERN = /^<UNARCHIVE>/
|
7
|
+
|
8
|
+
|
9
|
+
def is_unarchive?(text)
|
10
|
+
text =~ UNARCHIVE_PATTERN
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(text)
|
14
|
+
params = {
|
15
|
+
date: date(text),
|
16
|
+
year: year(text),
|
17
|
+
agency: agency(text),
|
18
|
+
office: office(text),
|
19
|
+
location: location(text),
|
20
|
+
solicitation_number: solicitation_number(text),
|
21
|
+
notice_type: notice_type(text),
|
22
|
+
archive_date: archive_date(text),
|
23
|
+
award_number: award_number(text)
|
24
|
+
}
|
25
|
+
FBO::Notices::Unarchive.new(params)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
# Returns a concatenated list of all tags for the notice
|
32
|
+
#
|
33
|
+
# @return [String]
|
34
|
+
def any_notice_tag
|
35
|
+
ANY_UNARCHIVE_TAG
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
extend FBO::Parser::NoticeHandler
|
40
|
+
extend FBO::Parser::ParserHelper
|
41
|
+
extend self
|
42
|
+
end
|
data/lib/fbo/version.rb
CHANGED
@@ -12,31 +12,36 @@ describe FBO::Parser::AmendmentHandler do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should parse all fields correctly" do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
15
|
+
amendment = subject.parse(contents)
|
16
|
+
amendment.date.strftime("%Y-%m-%d").should eq Date.parse("2013-03-26").strftime("%Y-%m-%d")
|
17
|
+
amendment.year.should eq 2013
|
18
|
+
amendment.agency.should eq "Department of the Air Force"
|
19
|
+
amendment.office.should eq "Air Force Materiel Command"
|
20
|
+
amendment.location.should eq "Tinker AFB - OC-ALC/PKO"
|
21
|
+
amendment.zip.should eq "73145-9106"
|
22
|
+
amendment.class_code.should eq "R"
|
23
|
+
amendment.naics_code.should eq "541611"
|
24
|
+
amendment.office_address.should eq "7858 5th Street Ste 1 Tinker AFB OK 73145-9106"
|
25
|
+
amendment.subject.should eq "ISO 9001:2008 AS9100/9110 Registration/Surveillance/Reassessment Audit"
|
26
|
+
amendment.solicitation_number.should eq "FA8101-13-Q-0014"
|
27
|
+
amendment.response_date.strftime("%Y-%m-%d").should eq "2013-03-27"
|
28
|
+
amendment.archive_date.strftime("%Y-%m-%d").should eq "2013-04-26"
|
29
|
+
amendment.contact_info.should eq "Matthew Kinney, Contract Specialist, Phone 4057393745, Email matthew.kinney@tinker.af.mil - Kimberly L DeLong, Contracting Officer, Phone (405) 739-3514, Fax (405) 739-7957, Email kimberly.delong2@tinker.af.mil"
|
30
|
+
amendment.description.should eq "<p>***All quotes need to be based off of the scope and figures in the PWS and not OASIS<br />***IAW PWS para 1.1(e) the audit will be scheduled in May and must be completed in one week<br />***Organizations OIN 6115237940</p>"
|
31
|
+
amendment.link_url.should eq "https://www.fbo.gov/spg/USAF/AFMC/OCALCBC/FA8101-13-Q-0014/listing.html"
|
32
|
+
amendment.link_description.should eq "Link To Document"
|
33
|
+
amendment.setaside.should eq "Total Small Business"
|
34
|
+
amendment.pop_country.should eq "US"
|
35
|
+
amendment.pop_zip.should eq "73145"
|
36
|
+
amendment.pop_address.should eq "Tinker AFB\nTinker AFB, OK"
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
it "should return an Amendment notice" do
|
40
|
+
amendment = subject.parse(contents)
|
41
|
+
amendment.should be_instance_of(FBO::Notices::Amendment)
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when not an amendment" do
|
40
45
|
let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "presol") }
|
41
46
|
|
42
47
|
it "should not recognize other notice content" do
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FBO::Parser::ArchiveHandler do
|
4
|
+
let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "archive") }
|
5
|
+
let(:file) { File.new(filename) }
|
6
|
+
let(:contents) { file.read }
|
7
|
+
|
8
|
+
it "should recognize archive content" do
|
9
|
+
subject.is_archive?(contents).should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should parse all fields correctly" do
|
13
|
+
archive = subject.parse(contents)
|
14
|
+
archive.date.strftime("%Y-%m-%d").should eq Date.parse("2013-03-01").strftime("%Y-%m-%d")
|
15
|
+
archive.year.should eq 2013
|
16
|
+
archive.agency.should eq "Department of Veterans Affairs"
|
17
|
+
archive.office.should eq "VA Technology Acquisition Center"
|
18
|
+
archive.location.should eq "VA Technology Acquisition Center"
|
19
|
+
archive.solicitation_number.should eq "VA11813Q0109"
|
20
|
+
archive.notice_type.should eq "COMBINE"
|
21
|
+
archive.archive_date.strftime("%Y-%m-%d").should eq "2013-04-07"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return an Archive notice" do
|
25
|
+
archive = subject.parse(contents)
|
26
|
+
archive.should be_instance_of(FBO::Notices::Archive)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when not an archive notice" do
|
30
|
+
let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "presol") }
|
31
|
+
|
32
|
+
it "should not recognize other notice content" do
|
33
|
+
subject.is_archive?(contents).should_not be_true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -41,6 +41,11 @@ describe FBO::Parser::AwardHandler do
|
|
41
41
|
award.correction.should be_false
|
42
42
|
end
|
43
43
|
|
44
|
+
it "should return an Award notice" do
|
45
|
+
award = subject.parse(contents)
|
46
|
+
award.should be_instance_of(FBO::Notices::Award)
|
47
|
+
end
|
48
|
+
|
44
49
|
context "when not an award" do
|
45
50
|
let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "presol") }
|
46
51
|
|
@@ -34,7 +34,11 @@ describe FBO::Parser::CombinedSolicitationHandler do
|
|
34
34
|
combine.pop_country.should eq "US"
|
35
35
|
combine.pop_zip.should eq "20005-4026"
|
36
36
|
combine.pop_address.should eq "Washington, DC 20005"
|
37
|
+
end
|
37
38
|
|
39
|
+
it "should return a CombinedSolicitation notice" do
|
40
|
+
combine = subject.parse(contents)
|
41
|
+
combine.should be_instance_of(FBO::Notices::CombinedSolicitation)
|
38
42
|
end
|
39
43
|
|
40
44
|
context "when not a combined solicitation" do
|