defcli 0.0.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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/defcli.rb +44 -0
- data/lib/defcli/formatting.rb +114 -0
- data/tests/formatting_tests.rb +96 -0
- data/tests/tests.rb +54 -0
- metadata +157 -0
- metadata.gz.sig +2 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 671ad3b060e2945f7eeda6802e5327565596986a2934c85635efcb7678ad065e
|
4
|
+
data.tar.gz: 22927817e5e29dc4845b44575af9ca1d061b81ff7f8bd4cae047d4aba86c11bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5be8378f87f339c13a49c660d01dca507b59467ffd5ae033f487f562b22cd2210ab2bf65d36a96bb346625a6110b2f1169406515caef9e97ea2206fedd112eb4
|
7
|
+
data.tar.gz: 43fdb3e659694db3b5a34c5fedbe3d56f40ba0f0ba0a8089c9bca9c0446d30209dd2f9210d7c815d57a6f0565f3e4e9c826f32c72e6b5929afdde325e6c612e6
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/lib/defcli.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "json"
|
5
|
+
require "open-uri"
|
6
|
+
|
7
|
+
require_relative "./defcli/formatting"
|
8
|
+
|
9
|
+
module Defcli
|
10
|
+
class << self
|
11
|
+
def version
|
12
|
+
"0.0.1"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Format results for output
|
16
|
+
# @param results [Array] array of results
|
17
|
+
# @param color [Boolean] colored output
|
18
|
+
# @return [String]
|
19
|
+
def format_results(results, color = true)
|
20
|
+
Defcli::Formatting.format_results(results, color)
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_url(url)
|
24
|
+
OpenURI.open_uri(url).read
|
25
|
+
end
|
26
|
+
|
27
|
+
def open_in_browser(url)
|
28
|
+
system open_cmd, url
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def open_cmd
|
34
|
+
case RbConfig::CONFIG["host_os"]
|
35
|
+
when /darwin/
|
36
|
+
"open"
|
37
|
+
when /bsd|linux/
|
38
|
+
"xdg-open"
|
39
|
+
when /cygwin|mingw|mswin/
|
40
|
+
"start"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
|
3
|
+
module Defcli
|
4
|
+
module Formatting
|
5
|
+
class << self
|
6
|
+
# Fit a text in a given width (number of chars).
|
7
|
+
# @param txt [String]
|
8
|
+
# @param width [Integer] maximum width
|
9
|
+
# @return [Array] list of lines of text
|
10
|
+
def fit(txt, width = 79)
|
11
|
+
return [] if width < 1
|
12
|
+
|
13
|
+
# from https://stackoverflow.com/a/7567210/735926
|
14
|
+
r = /(.{1,#{width}})(?:\s|$)/m
|
15
|
+
txt.split("\n").map { |l| l.scan(r) }.flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
# Add a tab at the beginning of a text. If it's a list, add a tab at
|
19
|
+
# the beginning of each element.
|
20
|
+
# @param txt [String] The text to tab, may be a string or a list of
|
21
|
+
# strings
|
22
|
+
# @param width [Integer] tab width
|
23
|
+
# @return [String]
|
24
|
+
def tab(txt, width = 4)
|
25
|
+
return txt if width <= 0
|
26
|
+
|
27
|
+
tab = " " * width
|
28
|
+
|
29
|
+
return tab + txt if txt.is_a? String
|
30
|
+
|
31
|
+
txt.map { |l| tab + l }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Format results for text output (e.g. in the terminal)
|
35
|
+
# @param results [Array<Hash>] array of results
|
36
|
+
# @param color [Boolean] colored output
|
37
|
+
# @return [String]
|
38
|
+
def format_results(results, color = true)
|
39
|
+
results.map { |r| format_result(r, color) }.join "\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_result(r, color = true)
|
43
|
+
require "colored" if color
|
44
|
+
|
45
|
+
word = r[:word]
|
46
|
+
word = word.bold if color
|
47
|
+
|
48
|
+
rating = format_result_rating(r, color)
|
49
|
+
|
50
|
+
definition = tab(fit(r[:definition], 75)).join "\n"
|
51
|
+
|
52
|
+
text = "* #{word}"
|
53
|
+
text << " (#{rating})" if rating
|
54
|
+
text << ":\n\n#{definition}\n"
|
55
|
+
|
56
|
+
text << "(📍 #{r[:location]})\n" if r[:location]
|
57
|
+
|
58
|
+
text << (format_result_examples(r, color) or "")
|
59
|
+
|
60
|
+
text + "\n\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def format_result_examples(r, color = true)
|
66
|
+
examples = if r[:example]
|
67
|
+
[r[:example]]
|
68
|
+
elsif r[:examples]
|
69
|
+
r[:examples]
|
70
|
+
else
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
|
74
|
+
if examples.count == 1
|
75
|
+
example = tab(fit(examples.first, 75)).join "\n"
|
76
|
+
"\n Example:\n#{example}\n"
|
77
|
+
|
78
|
+
elsif examples.count > 1
|
79
|
+
examples = examples.map do |e|
|
80
|
+
tab(fit(e, 75)).join "\n"
|
81
|
+
end.join "\n"
|
82
|
+
"\n Examples:\n#{examples}\n"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def format_result_rating(r, color = true)
|
87
|
+
if r[:upvotes]
|
88
|
+
# upvotes/downvotes
|
89
|
+
upvotes = r[:upvotes]
|
90
|
+
downvotes = r[:downvotes]
|
91
|
+
if color
|
92
|
+
upvotes = upvotes.to_s.green
|
93
|
+
downvotes = downvotes.to_s.red
|
94
|
+
end
|
95
|
+
|
96
|
+
"#{upvotes}/#{downvotes}"
|
97
|
+
elsif r[:ratio]
|
98
|
+
percentage = r[:ratio] * 100.0
|
99
|
+
rating = format("%2d%%", percentage)
|
100
|
+
|
101
|
+
if color
|
102
|
+
if percentage > 60
|
103
|
+
rating = rating.green
|
104
|
+
else
|
105
|
+
rating = rating.red
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
rating
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class DefcliFormattingTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
# == Defcli::Formatting.format_results == #
|
4
|
+
|
5
|
+
def test_format_results_empty_list
|
6
|
+
assert_equal('', Defcli.format_results([]))
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_format_results_one_element_no_color
|
10
|
+
res = {
|
11
|
+
:word => 'XYZ',
|
12
|
+
:upvotes => 42,
|
13
|
+
:downvotes => 78,
|
14
|
+
:definition => 'xyz',
|
15
|
+
:example => 'zyx'
|
16
|
+
}
|
17
|
+
|
18
|
+
output = Defcli.format_results([res], false).strip
|
19
|
+
expected = <<EOS
|
20
|
+
* XYZ (42/78):
|
21
|
+
|
22
|
+
xyz
|
23
|
+
|
24
|
+
Example:
|
25
|
+
zyx
|
26
|
+
EOS
|
27
|
+
|
28
|
+
assert_equal(expected.strip, output)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_format_results_one_element_color
|
32
|
+
green = "\e[32m"
|
33
|
+
bold = "\e[1m"
|
34
|
+
red = "\e[31m"
|
35
|
+
reset = "\e[0m"
|
36
|
+
res = {
|
37
|
+
:word => 'XYZ',
|
38
|
+
:upvotes => 42,
|
39
|
+
:downvotes => 78,
|
40
|
+
:definition => 'xyz',
|
41
|
+
:example => 'zyx'
|
42
|
+
}
|
43
|
+
|
44
|
+
output = Defcli.format_results([res], true).strip
|
45
|
+
expected = <<EOS
|
46
|
+
* #{bold}XYZ#{reset} (#{green}42#{reset}/#{red}78#{reset}):
|
47
|
+
|
48
|
+
xyz
|
49
|
+
|
50
|
+
Example:
|
51
|
+
zyx
|
52
|
+
EOS
|
53
|
+
|
54
|
+
assert_equal(expected.strip, output)
|
55
|
+
end
|
56
|
+
|
57
|
+
# == Defcli::Formatting.fit == #
|
58
|
+
|
59
|
+
def test_fit_0_width
|
60
|
+
assert_equal([], Defcli::Formatting.fit('foo', 0))
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_fit_negative_width
|
64
|
+
assert_equal([], Defcli::Formatting.fit('foo', -1))
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_fit_right_width
|
68
|
+
assert_equal(['foo'], Defcli::Formatting.fit('foo', 3))
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_fit_larger_width
|
72
|
+
assert_equal(['foo'], Defcli::Formatting.fit('foo', 4))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_fit_smaller_width
|
76
|
+
assert_equal(['a', 'b'], Defcli::Formatting.fit('a b', 2))
|
77
|
+
end
|
78
|
+
|
79
|
+
# == Defcli::Formatting.tab == #
|
80
|
+
|
81
|
+
def test_tab_0_width
|
82
|
+
assert_equal('foo', Defcli::Formatting.tab('foo', 0))
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_tab_negative_width
|
86
|
+
assert_equal('foo', Defcli::Formatting.tab('foo', -1))
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_tab_2_width
|
90
|
+
assert_equal(' foo', Defcli::Formatting.tab('foo', 2))
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_tab_array
|
94
|
+
assert_equal([' a', ' b'], Defcli::Formatting.tab(['a', 'b'], 1))
|
95
|
+
end
|
96
|
+
end
|
data/tests/tests.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
ci = ENV["CI"] || ENV["CONTINUOUS_INTEGRATION"]
|
4
|
+
|
5
|
+
if ci
|
6
|
+
require 'coveralls'
|
7
|
+
Coveralls.wear!
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'test/unit'
|
11
|
+
require 'simplecov'
|
12
|
+
|
13
|
+
test_dir = File.expand_path( File.dirname(__FILE__) )
|
14
|
+
|
15
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter if ci
|
16
|
+
SimpleCov.start { add_filter '/tests/' }
|
17
|
+
|
18
|
+
require 'defcli'
|
19
|
+
|
20
|
+
for t in Dir.glob( File.join( test_dir, '*_tests.rb' ) )
|
21
|
+
require t
|
22
|
+
end
|
23
|
+
|
24
|
+
class DefcliTests < Test::Unit::TestCase
|
25
|
+
|
26
|
+
# == Defcli.version == #
|
27
|
+
|
28
|
+
def test_version
|
29
|
+
assert(Defcli.version =~ /^\d+\.\d+\.\d+/)
|
30
|
+
end
|
31
|
+
|
32
|
+
# == Defcli.open_cmd (private) == #
|
33
|
+
|
34
|
+
def test_open_cmd
|
35
|
+
os = RbConfig::CONFIG["host_os"]
|
36
|
+
|
37
|
+
RbConfig::CONFIG["host_os"] = "darwin"
|
38
|
+
assert_equal "open", Defcli.send(:open_cmd)
|
39
|
+
|
40
|
+
RbConfig::CONFIG["host_os"] = "linux"
|
41
|
+
assert_equal "xdg-open", Defcli.send(:open_cmd)
|
42
|
+
|
43
|
+
RbConfig::CONFIG["host_os"] = "bsd"
|
44
|
+
assert_equal "xdg-open", Defcli.send(:open_cmd)
|
45
|
+
|
46
|
+
RbConfig::CONFIG["host_os"] = "cygwin"
|
47
|
+
assert_equal "start", Defcli.send(:open_cmd)
|
48
|
+
ensure
|
49
|
+
RbConfig::CONFIG["host_os"] = os
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
exit Test::Unit::AutoRunner.run
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: defcli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Baptiste Fontaine
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIID/DCCAmSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAkMSIwIAYDVQQDDBliL0RD
|
14
|
+
PXB0aXN0ZWZvbnRhaW5lL0RDPWZyMB4XDTIwMDMwNDE5MDMyMVoXDTIxMDMwNDE5
|
15
|
+
MDMyMVowJDEiMCAGA1UEAwwZYi9EQz1wdGlzdGVmb250YWluZS9EQz1mcjCCAaIw
|
16
|
+
DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKdjTwN/gnJ3WHxKeusaRN1o902Q
|
17
|
+
BmIRgdtbhpsHtgUruKNujutEBpmhG1fka8+mujhqh885blckeC8hXgqpHGK1MsJU
|
18
|
+
tgsNB2F2Nvof/uGBzi+OZ76HPLmfvJFb/KUiwrh08jTbFftMBCmuekbxBajt2N2F
|
19
|
+
shF6DFEqO2hl/itVt5UeIZhpIZvO7qSZ9FtLRXs0q2O27h4QfAv6XobNDwH5TBs5
|
20
|
+
z+EYufgTtupf26xW0v6z2NDG6z36Eap7QAwoivuPCuXO+IPgxhubtGvFYSo7ygP4
|
21
|
+
RbYsaGucRneCCzezTD+i1LnhGt9TCbQjdvidgM+i616JC/HRXglM0apgBZSjayoI
|
22
|
+
XHoajIajnU+570cu01Wsa+SF9m4stKao0hLnCUMeYybmA/Ilk58nJ2xZJWMULu76
|
23
|
+
7Ttzead1Ah25ZdWefKG5FIGkpezEp4z/YihGEJt+hxS7Aa2xYiIlnYFwUno530/8
|
24
|
+
So5Ibqdd3pMKJDUQJvGIBhsQIXF4Iogk4txoPwIDAQABozkwNzAJBgNVHRMEAjAA
|
25
|
+
MAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUsV1eKnEFtVRwyz6/nTuharH3G+UwDQYJ
|
26
|
+
KoZIhvcNAQELBQADggGBAJz7tbRe/iyMthV7fdqnhFv0SZo1UVWZSaIjB39W4lUi
|
27
|
+
7X1Smag2Fe7IqARUPLn2e49ObyupAmTi0zHoSG/+HsBUqNPPoVW1Y67dtrMM49o7
|
28
|
+
qSN66EogB4nvGdvqJ9eOlioiAX7vczWmQjfSONuk0ihOfaTChD7LwoPptTUu/Q6+
|
29
|
+
aT8zz7TH+sxxx+D09Q9+Ywf1RVnUe+i1PTo8kadnHIQdeBPudKrw5GWcIoLz1V16
|
30
|
+
A+j/SNEUqY1ui8TBX6axkd8vh6C1YcVAFCcdrxTMFTeB1irvL8jns6SulRHM08UC
|
31
|
+
9NR+YthP16QuQzb5R2wIGX6WT11cnIpo0LzTnY/QSZGgwJkuLalBLzUssMiVnoSX
|
32
|
+
rVdmQBLrs38YcJouqHpf0wCGygf5430Bq4nCu0xUaH5umPcwJE9qaF1ZfgSCfZEz
|
33
|
+
Qe5fflfwGHtlmT6SWZoQD48xF/ILJ+cLTpF79ardGYnWT6N7VUAI5lKp7OjZYd+q
|
34
|
+
wwYlmlBW0Femxy5WoxzECQ==
|
35
|
+
-----END CERTIFICATE-----
|
36
|
+
date: 2020-04-02 00:00:00.000000000 Z
|
37
|
+
dependencies:
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: optimist
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - "~>"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '3.0'
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - "~>"
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '3.0'
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: colored
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - "~>"
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '1.2'
|
59
|
+
type: :runtime
|
60
|
+
prerelease: false
|
61
|
+
version_requirements: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - "~>"
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '1.2'
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: simplecov
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - "~>"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0.18'
|
73
|
+
type: :development
|
74
|
+
prerelease: false
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0.18'
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rake
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - "~>"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '12.3'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '12.3'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: test-unit
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '3.3'
|
101
|
+
type: :development
|
102
|
+
prerelease: false
|
103
|
+
version_requirements: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - "~>"
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '3.3'
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: coveralls
|
110
|
+
requirement: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - "~>"
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0.8'
|
115
|
+
type: :development
|
116
|
+
prerelease: false
|
117
|
+
version_requirements: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - "~>"
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0.8'
|
122
|
+
description: Utilities to build simple dictionnary CLI tools.
|
123
|
+
email: b@ptistefontaine.fr
|
124
|
+
executables: []
|
125
|
+
extensions: []
|
126
|
+
extra_rdoc_files: []
|
127
|
+
files:
|
128
|
+
- lib/defcli.rb
|
129
|
+
- lib/defcli/formatting.rb
|
130
|
+
- tests/formatting_tests.rb
|
131
|
+
- tests/tests.rb
|
132
|
+
homepage: https://github.com/bfontaine/defcli
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubygems_version: 3.1.2
|
152
|
+
signing_key:
|
153
|
+
specification_version: 4
|
154
|
+
summary: Dictionnary CLI tools utilities
|
155
|
+
test_files:
|
156
|
+
- tests/tests.rb
|
157
|
+
- tests/formatting_tests.rb
|
metadata.gz.sig
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
H�y�����}^G|��>��ސ�J����>����k.^["O��*�O�-!��<�|�!HH?X�ȟ���,��I�V�Y����W�����mvq�4<<b���� ��y�D��W�#幗E-z��o�k�T���Pn�^�h�jHE�Zs5e������rъ��G8�P��V�֠dŢِ����!r�wF�%���2���5mƔv�{�\����]�8BNQ���V��{��������0W �d�YL��Id��Oo�E=�aC�}Cu���<��ъy
|
2
|
+
e���F� �u��x�u흝�8�9{�T��d�J�e�q�v��5 ����mM��'�C����a���9����20n=�}��|�L�I(<1�����k
|