what_is_it_about 0.1.1 → 0.1.2
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 +4 -4
- data/lib/what_is_it_about/cli.rb +0 -5
- data/lib/what_is_it_about/config.rb +32 -24
- data/lib/what_is_it_about/gem_summary.rb +52 -45
- data/lib/what_is_it_about/github.rb +10 -3
- data/lib/what_is_it_about/report.rb +29 -44
- data/lib/what_is_it_about/summary.rb +10 -1
- data/lib/what_is_it_about/version.rb +1 -1
- data/what_is_it_about.gemspec +3 -4
- metadata +15 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc1d323e147bbc85db4eb4103db3e92ec1213fa6
|
4
|
+
data.tar.gz: 834de190243a099c414aed5910d9803171c55570
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5996f92c97cda653c1d4e99e62bc4744cb6db970bb73c237f45012fae3d04d038ff71db7bf39ed34f1dc0946ba3983fa7bb94ad5c1883ac0ac18da0fe3e01980
|
7
|
+
data.tar.gz: 01875162be31dbad054e9e7f447f0ffd23ca37392ca49e945dfb5f7635553e31fb4990d14e62b4d2fdbd378cb43af6d02f2937f86c73efae0ee3511bb770ff87
|
data/lib/what_is_it_about/cli.rb
CHANGED
@@ -4,36 +4,44 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
module WhatIsItAbout
|
6
6
|
def self.config
|
7
|
-
|
7
|
+
@config ||=
|
8
|
+
begin
|
9
|
+
file = "#{Dir.home}/.what_is_it_about"
|
10
|
+
File.exist?(file) ? YAML.load_file(file) : {}
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
data = @data
|
18
|
-
path.each do |branch|
|
19
|
-
data = data[branch]
|
20
|
-
return unless data
|
14
|
+
def self.gem_configs
|
15
|
+
@gem_configs ||= (config['gems'] || []).map! do |gem_config|
|
16
|
+
if gem_config['name']
|
17
|
+
gem_config['name'] = Regexp.compile gem_config['name']
|
18
|
+
gem_config
|
19
|
+
else
|
20
|
+
$stderr.puts "unspecified name in gems config #{gem_config}"
|
21
21
|
end
|
22
|
-
|
23
|
-
|
22
|
+
end.compact
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.gem_repo_from_config(name)
|
26
|
+
gem_configs.each do |gem_config|
|
27
|
+
match = gem_config['name'].match name
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
next unless match
|
30
|
+
|
31
|
+
url_template = "https://github.com/#{gem_config['github']}" if gem_config['github']
|
32
|
+
|
33
|
+
unless url_template
|
34
|
+
$stderr.puts "github repository not specified for #{gem_config['name']}"
|
35
|
+
next
|
32
36
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
|
38
|
+
match.names.each do |var_name|
|
39
|
+
url_template.gsub!("${#{var_name}}", match[var_name])
|
36
40
|
end
|
41
|
+
|
42
|
+
return url_template
|
37
43
|
end
|
44
|
+
|
45
|
+
nil
|
38
46
|
end
|
39
47
|
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
1
|
module WhatIsItAbout
|
4
2
|
class GemSummary
|
5
3
|
GITHUB_RX = %r{github\.com}
|
6
4
|
REPO_RX = %r{[/:](?<user>[\w-]+)/(?<repo>[\w-]+)(?<suffix>\.git)?}
|
7
5
|
|
8
|
-
def initialize(old_spec, new_spec)
|
6
|
+
def initialize(old_spec, new_spec, compare_cache:)
|
7
|
+
@compare_cache = compare_cache
|
9
8
|
@spec = {
|
10
9
|
old: old_spec,
|
11
10
|
new: new_spec
|
@@ -33,7 +32,7 @@ module WhatIsItAbout
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def versions
|
36
|
-
spec_map do |spec|
|
35
|
+
spec_map do |_v, spec|
|
37
36
|
spec.version.to_s
|
38
37
|
end
|
39
38
|
end
|
@@ -47,7 +46,7 @@ module WhatIsItAbout
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def source_types
|
50
|
-
spec_map do |spec|
|
49
|
+
spec_map do |_v, spec|
|
51
50
|
case spec.source
|
52
51
|
when Bundler::Source::Git
|
53
52
|
:git
|
@@ -64,7 +63,7 @@ module WhatIsItAbout
|
|
64
63
|
end
|
65
64
|
|
66
65
|
def paths
|
67
|
-
spec_map do |spec|
|
66
|
+
spec_map do |_v, spec|
|
68
67
|
spec.source.path.to_s if spec.source.class == Bundler::Source::Path
|
69
68
|
end
|
70
69
|
end
|
@@ -74,7 +73,7 @@ module WhatIsItAbout
|
|
74
73
|
end
|
75
74
|
|
76
75
|
def source_repositories
|
77
|
-
spec_map do |spec|
|
76
|
+
spec_map do |_v, spec|
|
78
77
|
spec.source.uri if spec.source.class == Bundler::Source::Git
|
79
78
|
end
|
80
79
|
end
|
@@ -84,7 +83,7 @@ module WhatIsItAbout
|
|
84
83
|
end
|
85
84
|
|
86
85
|
def source_branches
|
87
|
-
spec_map do |spec|
|
86
|
+
spec_map do |_v, spec|
|
88
87
|
next unless spec.source.class == Bundler::Source::Git
|
89
88
|
if spec.source.branch.to_s.empty?
|
90
89
|
'master'
|
@@ -99,30 +98,33 @@ module WhatIsItAbout
|
|
99
98
|
end
|
100
99
|
|
101
100
|
def source_revisions
|
102
|
-
spec_map do |spec|
|
101
|
+
spec_map do |_v, spec|
|
103
102
|
spec.source.revision if spec.source.class == Bundler::Source::Git
|
104
103
|
end
|
105
104
|
end
|
106
105
|
|
107
106
|
def commits_log
|
107
|
+
return unless changed?
|
108
|
+
|
108
109
|
@commits_log ||= {
|
109
|
-
|
110
|
-
|
110
|
+
removed: removed_compare,
|
111
|
+
added: added_compare
|
111
112
|
}
|
112
113
|
end
|
113
114
|
|
115
|
+
def group
|
116
|
+
commits_log && commits_log[:added] && commits_log[:added][:commits].any? && commits_log[:added][:html_url]
|
117
|
+
end
|
118
|
+
|
114
119
|
private
|
115
120
|
|
116
|
-
|
117
|
-
results = @spec.values.map do |spec|
|
118
|
-
next unless spec
|
119
|
-
block.call(spec)
|
120
|
-
end
|
121
|
+
attr_reader :compare_cache
|
121
122
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
def spec_map(&block)
|
124
|
+
@spec.map do |k, spec|
|
125
|
+
v = block.call(k, spec) if spec
|
126
|
+
[k, v]
|
127
|
+
end.to_h
|
126
128
|
end
|
127
129
|
|
128
130
|
def added_compare
|
@@ -130,9 +132,9 @@ module WhatIsItAbout
|
|
130
132
|
return if p.values.compact.size < 2
|
131
133
|
repo = "#{p[:old][:user]}/#{p[:old][:repo]}"
|
132
134
|
start = p[:old][:revision]
|
133
|
-
end_ = "#{p[:new][:user]}:#{p[:new][:revision]}"
|
134
|
-
puts "downloading commits #{repo} #{start} => #{end_}"
|
135
|
-
WhatIsItAbout.github.client.compare repo, start, end_
|
135
|
+
end_ = p[:old][:user] == p[:new][:user] ? p[:new][:revision] : "#{p[:new][:user]}:#{p[:new][:revision]}"
|
136
|
+
puts "downloading commits #{repo} #{start} => #{end_}" if ENV['VERBOSE']
|
137
|
+
compare_cache[[repo, start, end_]] ||= WhatIsItAbout.github.client.compare repo, start, end_
|
136
138
|
rescue Octokit::NotFound => e
|
137
139
|
$stderr.puts e.inspect if ENV['VERBOSE']
|
138
140
|
end
|
@@ -142,41 +144,42 @@ module WhatIsItAbout
|
|
142
144
|
return if p.values.compact.size < 2
|
143
145
|
repo = "#{p[:new][:user]}/#{p[:new][:repo]}"
|
144
146
|
start = p[:new][:revision]
|
145
|
-
end_ = "#{p[:old][:user]}:#{p[:old][:revision]}"
|
146
|
-
puts "downloading commits #{repo} #{start} => #{end_}"
|
147
|
-
WhatIsItAbout.github.client.compare repo, start, end_
|
147
|
+
end_ = p[:old][:user] == p[:new][:user] ? p[:old][:revision] : "#{p[:old][:user]}:#{p[:old][:revision]}"
|
148
|
+
puts "downloading commits #{repo} #{start} => #{end_}" if ENV['VERBOSE']
|
149
|
+
compare_cache[[repo, start, end_]] ||= WhatIsItAbout.github.client.compare repo, start, end_
|
148
150
|
rescue Octokit::NotFound => e
|
149
151
|
$stderr.puts e.inspect if ENV['VERBOSE']
|
150
152
|
end
|
151
153
|
|
152
154
|
def github_compare_params
|
153
155
|
@github_compare_params ||=
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
156
|
+
spec_map do |v, spec|
|
157
|
+
source_uri, revision =
|
158
|
+
case spec.source
|
159
|
+
when Bundler::Source::Git
|
160
|
+
[source_repositories[v], source_revisions[v]]
|
161
|
+
when Bundler::Source::Rubygems
|
162
|
+
uri = WhatIsItAbout.gem_repo_from_config(spec.name)
|
163
|
+
unless uri
|
162
164
|
uri = homepage(spec)
|
163
165
|
uri = rubygems_source_uri(spec) unless GITHUB_RX.match(uri)
|
164
|
-
[uri, "v#{versions[v]}"]
|
165
166
|
end
|
166
167
|
|
167
|
-
|
168
|
-
|
168
|
+
[uri, "v#{versions[v]}"]
|
169
|
+
end
|
169
170
|
|
170
|
-
|
171
|
+
next unless source_uri
|
172
|
+
next unless GITHUB_RX.match(source_uri)
|
171
173
|
|
172
|
-
|
174
|
+
match = REPO_RX.match(source_uri)
|
173
175
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
176
|
+
next unless match
|
177
|
+
|
178
|
+
{
|
179
|
+
user: match[:user],
|
180
|
+
repo: match[:repo],
|
181
|
+
revision: revision
|
182
|
+
}
|
180
183
|
end
|
181
184
|
end
|
182
185
|
|
@@ -195,6 +198,9 @@ module WhatIsItAbout
|
|
195
198
|
return fetcher.fetch_spec([spec.name, spec.version, spec.platform])
|
196
199
|
rescue Bundler::Fetcher::FallbackError => _e
|
197
200
|
next
|
201
|
+
rescue Bundler::HTTPError => e
|
202
|
+
$stderr.puts e.inspect
|
203
|
+
next
|
198
204
|
end
|
199
205
|
end
|
200
206
|
nil
|
@@ -211,6 +217,7 @@ module WhatIsItAbout
|
|
211
217
|
%w(source_code_uri project_uri homepage_uri).each do |field|
|
212
218
|
val = specification[field]
|
213
219
|
next unless val
|
220
|
+
|
214
221
|
next unless GITHUB_RX.match(val)
|
215
222
|
next unless REPO_RX.match(val)
|
216
223
|
@rubygems_source_uri[spec.name] = val
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
require 'octokit'
|
3
2
|
|
4
3
|
module WhatIsItAbout
|
@@ -10,8 +9,16 @@ module WhatIsItAbout
|
|
10
9
|
attr_reader :client
|
11
10
|
|
12
11
|
def initialize
|
13
|
-
token = WhatIsItAbout.config
|
14
|
-
|
12
|
+
token = WhatIsItAbout.config['github']['token'] if WhatIsItAbout.config['github']
|
13
|
+
unless token
|
14
|
+
$stderr.puts <<-MESSAGE
|
15
|
+
Set GITHUB TOKEN https://github.com/settings/tokens in ~/.what_is_it_about
|
16
|
+
|
17
|
+
github:
|
18
|
+
token: <YOU GITHUB TOKEN>
|
19
|
+
MESSAGE
|
20
|
+
exit(1)
|
21
|
+
end
|
15
22
|
@client = Octokit::Client.new(access_token: token)
|
16
23
|
end
|
17
24
|
end
|
@@ -8,42 +8,33 @@ module WhatIsItAbout
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def to_s
|
11
|
-
lines = @summary.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
gem_source(gem, :old)
|
26
|
-
].join(' ')
|
27
|
-
when gem.changed?
|
28
|
-
version =
|
29
|
-
if gem.version_changed?
|
30
|
-
"#{gem.versions[:old]} => #{gem.versions[:new]}"
|
31
|
-
else
|
32
|
-
gem.versions[:old]
|
33
|
-
end
|
34
|
-
source =
|
35
|
-
if gem.source_changed?
|
36
|
-
"#{gem_source(gem, :old)} => #{gem_source(gem, :new)}"
|
37
|
-
else
|
11
|
+
lines = @summary.gem_groups.each_with_object([]) do |(_group, gems), lines|
|
12
|
+
gems.each do |gem|
|
13
|
+
if gem.added?
|
14
|
+
lines << [
|
15
|
+
'+',
|
16
|
+
gem.name,
|
17
|
+
gem.versions[:new],
|
18
|
+
gem_source(gem, :new)
|
19
|
+
].join(' ')
|
20
|
+
elsif gem.removed?
|
21
|
+
lines << [
|
22
|
+
'-',
|
23
|
+
gem.name,
|
24
|
+
gem.versions[:old],
|
38
25
|
gem_source(gem, :old)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
26
|
+
].join(' ')
|
27
|
+
elsif gem.changed?
|
28
|
+
version_line = "#{gem_source(gem, :old)} => #{gem_source(gem, :new)}"
|
29
|
+
lines << [
|
30
|
+
'C',
|
31
|
+
gem.name,
|
32
|
+
version_line
|
33
|
+
].join(' ')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if gems.first.changed?
|
37
|
+
gems.first.commits_log.each do |type, log|
|
47
38
|
next unless log
|
48
39
|
next if log[:commits].empty?
|
49
40
|
padding = ' '*4
|
@@ -51,6 +42,7 @@ module WhatIsItAbout
|
|
51
42
|
padding *= 2
|
52
43
|
message_padding = padding * 2
|
53
44
|
log[:commits].each do |commit|
|
45
|
+
next if commit[:parents].size == 2 # merge
|
54
46
|
lines << [
|
55
47
|
padding + commit[:commit][:author][:name],
|
56
48
|
commit[:html_url]
|
@@ -61,13 +53,6 @@ module WhatIsItAbout
|
|
61
53
|
lines << padded_message
|
62
54
|
end
|
63
55
|
end
|
64
|
-
else
|
65
|
-
lines << [
|
66
|
-
'=',
|
67
|
-
gem.name,
|
68
|
-
gem.versions[:old],
|
69
|
-
gem_source(gem, :old)
|
70
|
-
].join(' ')
|
71
56
|
end
|
72
57
|
end
|
73
58
|
lines.join("\n")
|
@@ -78,11 +63,11 @@ module WhatIsItAbout
|
|
78
63
|
def gem_source(gem, version)
|
79
64
|
case gem.source_types[version]
|
80
65
|
when :rubygems
|
81
|
-
|
66
|
+
gem.versions[version]
|
82
67
|
when :path
|
83
68
|
gem.paths[version]
|
84
69
|
when :git
|
85
|
-
"#{gem.
|
70
|
+
"#{gem.source_branches[version]}##{gem.source_revisions[version]}"
|
86
71
|
else
|
87
72
|
raise "Unknown source type for #{gem.inspect}"
|
88
73
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module WhatIsItAbout
|
4
4
|
class Summary
|
5
5
|
def initialize(old_gemfile_lock_content, new_gemfile_lock_content)
|
6
|
+
@compare_cache = {}
|
6
7
|
@old_definition = definition(old_gemfile_lock_content)
|
7
8
|
@new_definition = definition(new_gemfile_lock_content)
|
8
9
|
end
|
@@ -15,8 +16,16 @@ module WhatIsItAbout
|
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
19
|
+
def gem_groups
|
20
|
+
@gem_groups = gems.group_by do |gem|
|
21
|
+
gem.group || gem.name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
18
25
|
private
|
19
26
|
|
27
|
+
attr_reader :compare_cache
|
28
|
+
|
20
29
|
def definition(gemfile_lock_content)
|
21
30
|
Bundler::LockfileParser.new(gemfile_lock_content)
|
22
31
|
end
|
@@ -24,7 +33,7 @@ module WhatIsItAbout
|
|
24
33
|
def gem_summary(name)
|
25
34
|
old_spec = @old_definition.specs.find { |spec| spec.name == name }
|
26
35
|
new_spec = @new_definition.specs.find { |spec| spec.name == name }
|
27
|
-
GemSummary.new(old_spec, new_spec)
|
36
|
+
GemSummary.new(old_spec, new_spec, compare_cache: compare_cache)
|
28
37
|
end
|
29
38
|
end
|
30
39
|
end
|
data/what_is_it_about.gemspec
CHANGED
@@ -19,11 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_dependency 'bundler'
|
23
|
-
spec.add_dependency 'octokit'
|
24
|
-
spec.add_dependency 'thor'
|
22
|
+
spec.add_dependency 'bundler', '1.15.4'
|
23
|
+
spec.add_dependency 'octokit', '4.7.0'
|
24
|
+
spec.add_dependency 'thor', '0.20.0'
|
25
25
|
|
26
|
-
spec.add_development_dependency "bundler", "~> 1.12"
|
27
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
28
|
end
|
metadata
CHANGED
@@ -1,71 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: what_is_it_about
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Bochkarev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.15.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.15.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: octokit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 4.7.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 4.7.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: thor
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.20.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: bundler
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.12'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.12'
|
54
|
+
version: 0.20.0
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: rake
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,9 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
127
|
version: '0'
|
142
128
|
requirements: []
|
143
129
|
rubyforge_project:
|
144
|
-
rubygems_version: 2.
|
130
|
+
rubygems_version: 2.4.8
|
145
131
|
signing_key:
|
146
132
|
specification_version: 4
|
147
133
|
summary: Write a short summary, because Rubygems requires one.
|
148
134
|
test_files: []
|
149
|
-
has_rdoc:
|