sovren 0.0.3
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 +15 -0
- data/.gitignore +19 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +41 -0
- data/Rakefile +7 -0
- data/lib/sovren.rb +30 -0
- data/lib/sovren/achievement.rb +16 -0
- data/lib/sovren/association.rb +17 -0
- data/lib/sovren/certification.rb +18 -0
- data/lib/sovren/client.rb +45 -0
- data/lib/sovren/competency.rb +18 -0
- data/lib/sovren/contact_information.rb +33 -0
- data/lib/sovren/education.rb +30 -0
- data/lib/sovren/employment.rb +29 -0
- data/lib/sovren/language.rb +31 -0
- data/lib/sovren/military.rb +19 -0
- data/lib/sovren/patent.rb +19 -0
- data/lib/sovren/publication.rb +35 -0
- data/lib/sovren/reference.rb +18 -0
- data/lib/sovren/resume.rb +28 -0
- data/lib/sovren/version.rb +3 -0
- data/sovren.gemspec +30 -0
- data/spec/sovren/achievement_spec.rb +24 -0
- data/spec/sovren/association_spec.rb +25 -0
- data/spec/sovren/certification_spec.rb +26 -0
- data/spec/sovren/client_spec.rb +28 -0
- data/spec/sovren/competency_spec.rb +26 -0
- data/spec/sovren/contact_information_spec.rb +73 -0
- data/spec/sovren/education_spec.rb +48 -0
- data/spec/sovren/employment_spec.rb +45 -0
- data/spec/sovren/language_spec.rb +27 -0
- data/spec/sovren/military_spec.rb +29 -0
- data/spec/sovren/patent_spec.rb +27 -0
- data/spec/sovren/publication_spec.rb +70 -0
- data/spec/sovren/reference_spec.rb +34 -0
- data/spec/sovren/resume_spec.rb +42 -0
- data/spec/sovren_spec.rb +4 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/ResumeSample.doc +0 -0
- data/spec/support/_resume.xml +970 -0
- data/spec/support/achievements.xml +5 -0
- data/spec/support/associations.xml +8 -0
- data/spec/support/certifications.xml +23 -0
- data/spec/support/competencies.xml +353 -0
- data/spec/support/competencies_sparse.xml +3 -0
- data/spec/support/contact_information.xml +69 -0
- data/spec/support/contact_information_sparse.xml +10 -0
- data/spec/support/education.xml +81 -0
- data/spec/support/education_sparse.xml +10 -0
- data/spec/support/employment.xml +179 -0
- data/spec/support/employment_sparse.xml +11 -0
- data/spec/support/languages.xml +23 -0
- data/spec/support/military.xml +19 -0
- data/spec/support/patents.xml +14 -0
- data/spec/support/publications.xml +60 -0
- data/spec/support/references.xml +36 -0
- data/spec/support/resume.json +466 -0
- data/spec/support/resume.xml +1072 -0
- data/spec/support/speaking_events.xml +7 -0
- data/spec/vcr/parsed_resume.yml +3695 -0
- metadata +215 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZGI2YjYyNjA3NDlkOTcwOWExOTk4MTdmNjc1ZGI2MWQ4NWY2NDI3Yw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjU3ZDU1MzFjYWEyMDQ4MWQ5NTQ3NzQ4MTk0NzFiNTRjNGY2OWIwYg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjBlMTc0ODVhMTMxZjZjODM2ZjkzZTRkNGZhMWQ4NmI5YjE5NTViYTZkZmNl
|
10
|
+
NzM0OGUzMzNkMDBjZjlkZDVlNTgwMGJjZTEyNDc3YzU5MjIzODMyZGMwOWE4
|
11
|
+
M2JkYmM3MzQ2N2EzNjQ0ZTJlZDBhZGNlYTE1MjNhZThiN2Q3Y2I=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NWMwODgwNDA5MmM2OTc5MDU3MzUxY2QwNzg2OGNmZTJlODYyMmFiYjNhODdk
|
14
|
+
Y2ZjM2ZlNGJjZDZkYTJhNzA4NjgwYWMwMTc2MzE4YjAwMjc5NGIwYjA0NjBi
|
15
|
+
OTYxNWJhMGRlYWU4NjA2NWI3ZmI2NDBmZGFiNTMzZTk0ZDE2NTU=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Eric Fleming
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Sovren
|
2
|
+
|
3
|
+
A simple ruby gem that parses a resume using the sovren resume parser and returns the resume back as a ruby object.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sovren'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sovren
|
18
|
+
|
19
|
+
## Usage Example
|
20
|
+
|
21
|
+
1. Create a client
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
client = Sovren::Client.new(endpoint: "http://yourhost.com/SovrenConvertAndParse/ConvertAndParse.asmx?WSDL", username: "http basic username (optional)", password: "http basic password (optional)")
|
25
|
+
```
|
26
|
+
|
27
|
+
2. Parse a resume
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
resume = client.parse(File.read('/path/to/your/file/resume.doc'))
|
31
|
+
```
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
The testing could use some more coverage for other hr-xml use cases. I also haven't added any of the sovren specific fields returned but those could be added if you need them.
|
36
|
+
|
37
|
+
1. Fork it
|
38
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
39
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
40
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
41
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/sovren.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "sovren/version"
|
3
|
+
require "savon"
|
4
|
+
|
5
|
+
module Sovren
|
6
|
+
class << self
|
7
|
+
FIELDS = [:endpoint, :username, :password, :timeout, :hard_time_out_multiplier, :parser_configuration_params]
|
8
|
+
attr_accessor(*FIELDS)
|
9
|
+
|
10
|
+
def configure
|
11
|
+
yield self
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require_relative "sovren/achievement"
|
17
|
+
require_relative "sovren/association"
|
18
|
+
require_relative "sovren/certification"
|
19
|
+
require_relative "sovren/client"
|
20
|
+
require_relative "sovren/competency"
|
21
|
+
require_relative "sovren/contact_information"
|
22
|
+
require_relative "sovren/education"
|
23
|
+
require_relative "sovren/employment"
|
24
|
+
require_relative "sovren/resume"
|
25
|
+
require_relative "sovren/language"
|
26
|
+
require_relative "sovren/military"
|
27
|
+
require_relative "sovren/patent"
|
28
|
+
require_relative "sovren/publication"
|
29
|
+
require_relative "sovren/reference"
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Achievement
|
3
|
+
attr_accessor :description
|
4
|
+
|
5
|
+
def self.parse(achievements)
|
6
|
+
return Array.new if achievements.nil?
|
7
|
+
result = achievements.css('Achievement').collect do |item|
|
8
|
+
c = Achievement.new
|
9
|
+
c.description = item.css('Description').text
|
10
|
+
c
|
11
|
+
end
|
12
|
+
result
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Association
|
3
|
+
attr_accessor :name, :role
|
4
|
+
|
5
|
+
def self.parse(associations)
|
6
|
+
return Array.new if associations.nil?
|
7
|
+
result = associations.css('Association').collect do |item|
|
8
|
+
c = Association.new
|
9
|
+
c.name = item.css('Name').first.text
|
10
|
+
c.role = item.css('Role Name').text
|
11
|
+
c
|
12
|
+
end
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Certification
|
3
|
+
attr_accessor :name, :description, :effective_date
|
4
|
+
|
5
|
+
def self.parse(certifications)
|
6
|
+
return Array.new if certifications.nil?
|
7
|
+
result = certifications.css('LicenseOrCertification').collect do |item|
|
8
|
+
c = Certification.new
|
9
|
+
c.name = item.css('Name').text
|
10
|
+
c.description = item.css('Description').text
|
11
|
+
c.effective_date = Date.parse(item.css('EffectiveDate FirstIssuedDate AnyDate').text) rescue nil
|
12
|
+
c
|
13
|
+
end
|
14
|
+
result
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Client
|
3
|
+
attr_reader :endpoint, :username, :password, :timeout, :hard_time_out_multiplier, :parser_configuration_params
|
4
|
+
|
5
|
+
#Initialize the client class that will be used for all sovren requests.
|
6
|
+
#
|
7
|
+
#Certain requests will require an oauth token. See http://developer.foursquare.com/docs/index_docs.html for the full list.
|
8
|
+
#
|
9
|
+
# @param [Hash] options
|
10
|
+
# @option options String :endpoint The url that the web service is located at
|
11
|
+
# @option options String :username The HTTP Basic auth username for the webservice
|
12
|
+
# @option options String :password The HTTP Basic auth password for the webservice
|
13
|
+
# @option options Integer :timeout The timeout for the parser
|
14
|
+
# @option options Integer :hard_time_out_multiplier The hard timeout for the parser
|
15
|
+
# @option options Integer :parser_configuration_params The parser configuration params, used to tweak the output of the parser
|
16
|
+
|
17
|
+
def initialize(options={})
|
18
|
+
@endpoint = options[:endpoint]
|
19
|
+
@username = options[:username]
|
20
|
+
@password = options[:password]
|
21
|
+
@timeout = options[:timout] || 30000
|
22
|
+
@hard_time_out_multiplier = options[:hard_time_out_multiplier] || 2
|
23
|
+
@parser_configuration_params = options[:parser_configuration_params] || "_100000_0_00000010_0000000110101100_1_0000000000000111111102000000000010000100000000000000"
|
24
|
+
end
|
25
|
+
|
26
|
+
def connection
|
27
|
+
Savon.client(wsdl: endpoint, log: false)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse(file)
|
31
|
+
result = connection.call(:parse) do |c|
|
32
|
+
c.message({
|
33
|
+
"DocumentAsByteArray" => Base64.encode64(file),
|
34
|
+
"ParserConfigurationParams" => parser_configuration_params,
|
35
|
+
"AlsoUseSovrenTaxonomy" => true,
|
36
|
+
"EmbedConvertedTextInHrXml" => true,
|
37
|
+
"HardTimeOutMultiplier" => hard_time_out_multiplier,
|
38
|
+
"TimeOutInMs" => timeout})
|
39
|
+
end
|
40
|
+
|
41
|
+
Resume.parse(result.body[:parse_response][:parse_result])
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Competency
|
3
|
+
attr_accessor :name, :months, :last_used_date
|
4
|
+
|
5
|
+
def self.parse(competencies)
|
6
|
+
return Array.new if competencies.nil?
|
7
|
+
results = competencies.css('Competency').collect do |item|
|
8
|
+
c = Competency.new
|
9
|
+
c.name = item['name']
|
10
|
+
c.months = item.css('CompetencyEvidence NumericValue').text.to_i rescue nil
|
11
|
+
c.last_used_date = Date.parse(item.css('CompetencyEvidence').first['lastUsed']) rescue nil
|
12
|
+
c
|
13
|
+
end
|
14
|
+
results
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sovren
|
2
|
+
class ContactInformation
|
3
|
+
attr_accessor :first_name, :middle_name, :last_name, :aristocratic_title, :form_of_address, :generation, :qualification, :address_line_1, :address_line_2, :city, :state, :country, :postal_code, :home_phone, :mobile_phone, :email, :website
|
4
|
+
|
5
|
+
def self.parse(contact_information)
|
6
|
+
return nil if contact_information.nil?
|
7
|
+
result = self.new
|
8
|
+
result.first_name = contact_information.css('PersonName GivenName').collect(&:text).join(" ")
|
9
|
+
result.middle_name = contact_information.css('PersonName MiddleName').collect(&:text).join(" ")
|
10
|
+
result.last_name = contact_information.css('PersonName FamilyName').collect(&:text).join(" ")
|
11
|
+
result.aristocratic_title = contact_information.css('PersonName Affix[type=aristocraticTitle]').collect(&:text).join(" ")
|
12
|
+
result.form_of_address = contact_information.css('PersonName Affix[type=formOfAddress]').collect(&:text).join(" ")
|
13
|
+
result.generation = contact_information.css('PersonName Affix[type=generation]').collect(&:text).join(" ")
|
14
|
+
result.qualification = contact_information.css('PersonName Affix[type=qualification]').collect(&:text).join(" ")
|
15
|
+
|
16
|
+
address = contact_information.css('PostalAddress DeliveryAddress AddressLine').collect(&:text)
|
17
|
+
result.address_line_1 = address[0] if address.length > 0
|
18
|
+
result.address_line_2 = address[1] if address.length > 1
|
19
|
+
result.city = contact_information.css('PostalAddress').first.css('Municipality').text rescue nil
|
20
|
+
result.state = contact_information.css('PostalAddress').first.css('Region').text rescue nil
|
21
|
+
result.postal_code = contact_information.css('PostalAddress').first.css('PostalCode').text rescue nil
|
22
|
+
result.country = contact_information.css('PostalAddress').first.css('CountryCode').text rescue nil
|
23
|
+
|
24
|
+
result.home_phone = contact_information.css('Telephone FormattedNumber').first.text rescue nil
|
25
|
+
result.mobile_phone = contact_information.css('Mobile FormattedNumber').first.text rescue nil
|
26
|
+
|
27
|
+
result.website = contact_information.css('InternetWebAddress').first.text rescue nil
|
28
|
+
result.email = contact_information.css('InternetEmailAddress').first.text rescue nil
|
29
|
+
|
30
|
+
result
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Education
|
3
|
+
attr_accessor :school_name, :city, :state, :country, :degree_name, :degree_type, :major, :minor, :gpa, :gpa_out_of, :start_date, :end_date, :graduated
|
4
|
+
|
5
|
+
def self.parse(education_history)
|
6
|
+
return Array.new if education_history.nil?
|
7
|
+
result = education_history.css('SchoolOrInstitution').collect do |item|
|
8
|
+
e = Education.new
|
9
|
+
e.school_name = item.css('SchoolName').text
|
10
|
+
e.city, e.state, e.country = item.css('PostalAddress Municipality, PostalAddress Region, PostalAddress CountryCode').collect(&:text)
|
11
|
+
e.degree_type = item.css('Degree').first['degreeType']
|
12
|
+
e.degree_name = item.css('Degree DegreeName').text
|
13
|
+
e.major = item.css('DegreeMajor Name').text
|
14
|
+
e.minor = item.css('DegreeMinor name').text
|
15
|
+
e.gpa = item.css('EducationalMeasure MeasureValue StringValue').text.to_f rescue nil
|
16
|
+
e.gpa_out_of = item.css('EducationalMeasure HighestPossibleValue StringValue').text.to_f rescue nil
|
17
|
+
e.start_date = Date.parse(item.css('DatesOfAttendance StartDate AnyDate').text) rescue nil
|
18
|
+
e.end_date = Date.parse(item.css('DatesOfAttendance EndDate AnyDate').text) rescue nil
|
19
|
+
e.graduated = item.css('Degree DegreeDate AnyDate').text != ""
|
20
|
+
e
|
21
|
+
end
|
22
|
+
result
|
23
|
+
end
|
24
|
+
|
25
|
+
def graduated?
|
26
|
+
!graduated.nil? && graduated
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Employment
|
3
|
+
attr_accessor :employer, :division, :city, :state, :country, :title, :description, :start_date, :end_date, :current_employer
|
4
|
+
|
5
|
+
def self.parse(employment_history)
|
6
|
+
return Array.new if employment_history.nil?
|
7
|
+
result = employment_history.css('EmployerOrg').collect do |item|
|
8
|
+
position = item.css('PositionHistory').first
|
9
|
+
e = Employment.new
|
10
|
+
e.employer = item.css('EmployerOrgName').text
|
11
|
+
e.division = position.css('OrganizationName').text
|
12
|
+
e.division = nil if e.employer == e.division
|
13
|
+
e.city, e.state, e.country = item.css('PositionLocation Municipality, PositionLocation Region, PositionLocation CountryCode').collect(&:text)
|
14
|
+
e.title = position.css('Title').text
|
15
|
+
e.description = position.css('Description').text
|
16
|
+
e.start_date = Date.parse(position.css('StartDate').text) rescue nil
|
17
|
+
e.current_employer = position['currentEmployer'] == "true"
|
18
|
+
e.end_date = e.current_employer ? nil : (Date.parse(position.css('EndDate').text) rescue nil)
|
19
|
+
e
|
20
|
+
end
|
21
|
+
result
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_employer?
|
25
|
+
!current_employer.nil? && current_employer
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Language
|
3
|
+
attr_accessor :language_code, :read, :write, :speak
|
4
|
+
|
5
|
+
def self.parse(languages)
|
6
|
+
return Array.new if languages.nil?
|
7
|
+
result = languages.css('Language').collect do |item|
|
8
|
+
c = Language.new
|
9
|
+
c.language_code = item.css('LanguageCode').text
|
10
|
+
c.read = item.css('Read').text == "true" rescue nil
|
11
|
+
c.write = item.css('Write').text == "true" rescue nil
|
12
|
+
c.speak = item.css('Speak').text == "true" rescue nil
|
13
|
+
c
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
def read?
|
19
|
+
!read.nil? && read
|
20
|
+
end
|
21
|
+
|
22
|
+
def write?
|
23
|
+
!write.nil? && write
|
24
|
+
end
|
25
|
+
|
26
|
+
def speak?
|
27
|
+
!speak.nil? && speak
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Military
|
3
|
+
attr_accessor :country_served, :branch, :rank_achieved, :recognition_achieved, :discharge_status, :start_date, :end_date
|
4
|
+
|
5
|
+
def self.parse(military_history)
|
6
|
+
return nil if military_history.nil?
|
7
|
+
e = Military.new
|
8
|
+
e.country_served = military_history.css('CountryServed').text
|
9
|
+
e.branch = military_history.css('ServiceDetail').first['branch']
|
10
|
+
e.rank_achieved = military_history.css('ServiceDetail RankAchieved CurrentOrEndRank').text
|
11
|
+
e.recognition_achieved = military_history.css('ServiceDetail RecognitionAchieved').text
|
12
|
+
e.discharge_status = military_history.css('ServiceDetail DischargeStatus').text
|
13
|
+
e.start_date = Date.parse(military_history.css('DatesOfService StartDate AnyDate').text) rescue nil
|
14
|
+
e.end_date = Date.parse(military_history.css('DatesOfService EndDate AnyDate').text) rescue nil
|
15
|
+
e
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sovren
|
2
|
+
class Patent
|
3
|
+
attr_accessor :title, :description, :inventor_name, :patent_id
|
4
|
+
|
5
|
+
def self.parse(patents)
|
6
|
+
return Array.new if patents.nil?
|
7
|
+
result = patents.css('Patent').collect do |item|
|
8
|
+
c = Patent.new
|
9
|
+
c.title = item.css('PatentTitle').text
|
10
|
+
c.description = item.css('Description').text
|
11
|
+
c.inventor_name = item.css('Inventors InventorName').first.text rescue nil
|
12
|
+
c.patent_id = item.css('PatentDetail PatentMilestone Id').text
|
13
|
+
c
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|