questrade_api 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/Gemfile +1 -0
- data/README.md +11 -4
- data/lib/questrade_api/client.rb +9 -0
- data/lib/questrade_api/rest/symbol.rb +78 -0
- data/lib/questrade_api/version.rb +1 -1
- data/spec/fixtures/json/symbols.json +51 -0
- data/spec/fixtures/json/symbols_search.json +24 -0
- data/spec/questrade_api/rest/activity_spec.rb +2 -2
- data/spec/questrade_api/rest/execution_spec.rb +2 -2
- data/spec/questrade_api/rest/order_spec.rb +1 -1
- data/spec/questrade_api/rest/symbol_spec.rb +157 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28eb22cf9856de8e4e03c5d5b1a3f809a55144c4
|
4
|
+
data.tar.gz: 37db10221ed2dbf2bfba03c5331533da497359ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 128517e2915b03b3d5acfbbe354405f521d8b4f77d9bb1c005154bc9b3966de957e9649af40804c44f2da3f1208d4e2914adc3fa0f4075c8b0b2f0417d413ea5
|
7
|
+
data.tar.gz: f84b81cfb6aae10db6230783a7594cf9f944d282046accb6f3fb8936d7e370081dc365531ce6d43efe62ea52cf5e3de15d259b1501186ddc4b110faaf49c1e0d
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -44,12 +44,18 @@ client.positions('account_id')
|
|
44
44
|
# Activities of an specific period of time for an specific account
|
45
45
|
client.activities('account_id', startTime: DateTime.yesterday.to_s, endTime: DateTime.now.to_s)
|
46
46
|
|
47
|
+
# Symbols by name
|
48
|
+
client.symbols(names: ['AAPL'])
|
49
|
+
|
50
|
+
# Search symbols by prefix
|
51
|
+
client.search_symbols(prefix: 'BMO')
|
52
|
+
|
47
53
|
# In case you already have a valid access token and its respective URL, you can use the QuestradeApi::REST objects. Example:
|
48
54
|
# authorization can be any object that responds to url and access_token
|
49
55
|
authorization = QuestradeApi::Authorization.new(access_token: 'access_token', api_server: 'url')
|
50
56
|
accounts = QuestradeApi::REST::Account.all(accounts)
|
51
57
|
```
|
52
|
-
For more advanced options, check out our [documentation](http://www.rubydoc.info/gems/questrade_api).
|
58
|
+
For more advanced options, check out our [documentation](http://www.rubydoc.info/gems/questrade_api/0.0.2).
|
53
59
|
|
54
60
|
## Current Status
|
55
61
|
|
@@ -72,10 +78,11 @@ Check the tables below for more details.
|
|
72
78
|
|
73
79
|
| Endpoint | Development | Documentation |
|
74
80
|
| --- | --- | --- |
|
75
|
-
| /symbols
|
76
|
-
| /symbols/:
|
81
|
+
| /symbols/ | DONE | |
|
82
|
+
| /symbols/:id | | |
|
83
|
+
| /symbols/search | DONE | |
|
77
84
|
| /symbols/:id/options | | |
|
78
|
-
| /markets |DONE|
|
85
|
+
| /markets | DONE | |
|
79
86
|
| /markets/quotes/:id | | |
|
80
87
|
| /markets/quotes/options | | |
|
81
88
|
| /markets/quotes/strategies | | |
|
data/lib/questrade_api/client.rb
CHANGED
@@ -8,6 +8,7 @@ require 'questrade_api/rest/activity'
|
|
8
8
|
require 'questrade_api/rest/order'
|
9
9
|
|
10
10
|
require 'questrade_api/rest/market'
|
11
|
+
require 'questrade_api/rest/symbol'
|
11
12
|
|
12
13
|
module QuestradeApi
|
13
14
|
# @author Bruno Meira <goesmeira@gmail.com>
|
@@ -77,6 +78,14 @@ module QuestradeApi
|
|
77
78
|
QuestradeApi::REST::Market.all(@authorization)
|
78
79
|
end
|
79
80
|
|
81
|
+
def symbols(params)
|
82
|
+
QuestradeApi::REST::Symbol.all(@authorization, params)
|
83
|
+
end
|
84
|
+
|
85
|
+
def search_symbols(params)
|
86
|
+
QuestradeApi::REST::Symbol.search(@authorization, params)
|
87
|
+
end
|
88
|
+
|
80
89
|
private
|
81
90
|
|
82
91
|
def refresh_token?
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'questrade_api/rest/base'
|
2
|
+
|
3
|
+
module QuestradeApi
|
4
|
+
module REST
|
5
|
+
class Symbol < QuestradeApi::REST::Base
|
6
|
+
attr_accessor :id
|
7
|
+
|
8
|
+
def initialize(authorization, params = {})
|
9
|
+
super(authorization)
|
10
|
+
|
11
|
+
@id = params[:id]
|
12
|
+
|
13
|
+
@raw_body = params[:data]
|
14
|
+
build_data(params[:data]) if @raw_body
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.endpoint(extra = '')
|
18
|
+
"#{BASE_ENDPOINT}/symbols/#{extra}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.search(authorization, params = {})
|
22
|
+
response = superclass.all(access_token: authorization.access_token,
|
23
|
+
endpoint: endpoint('search'),
|
24
|
+
url: authorization.url,
|
25
|
+
params: params)
|
26
|
+
|
27
|
+
if response.status == 200
|
28
|
+
result = OpenStruct.new(symbols: [])
|
29
|
+
result.symbols = parse_symbols(authorization, response.body)
|
30
|
+
response = result
|
31
|
+
end
|
32
|
+
|
33
|
+
response
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.all(authorization, params = {})
|
37
|
+
params[:ids] = params[:ids].join(',') if params[:ids]
|
38
|
+
params[:names] = params[:names].join(',') if params[:names]
|
39
|
+
|
40
|
+
response = super(access_token: authorization.access_token,
|
41
|
+
endpoint: endpoint,
|
42
|
+
url: authorization.url,
|
43
|
+
params: params)
|
44
|
+
|
45
|
+
if response.status == 200
|
46
|
+
result = OpenStruct.new(symbols: [])
|
47
|
+
result.symbols = parse_symbols(authorization, response.body)
|
48
|
+
response = result
|
49
|
+
end
|
50
|
+
|
51
|
+
response
|
52
|
+
end
|
53
|
+
|
54
|
+
# TODO: Review this later
|
55
|
+
def self.parse_symbols(authorization, body)
|
56
|
+
raw = JSON.parse(body)
|
57
|
+
|
58
|
+
symbols = []
|
59
|
+
|
60
|
+
if raw['symbols']
|
61
|
+
raw['symbols'].each do |symbol|
|
62
|
+
symbols << new(authorization, id: symbol['symbolId'], data: symbol)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if raw['symbol']
|
67
|
+
raw['symbol'].each do |symbol|
|
68
|
+
symbols << new(authorization, id: symbol['symbolId'], data: symbol)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
symbols
|
73
|
+
end
|
74
|
+
|
75
|
+
private_class_method :parse_symbols
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
{
|
2
|
+
"symbols": [
|
3
|
+
{
|
4
|
+
"symbol": "AAPL",
|
5
|
+
"symbolId": 8049,
|
6
|
+
"prevDayClosePrice": 102.5,
|
7
|
+
"highPrice52": 102.9,
|
8
|
+
"lowPrice52": 63.89,
|
9
|
+
"averageVol3Months": 43769680,
|
10
|
+
"averageVol20Days": 12860370,
|
11
|
+
"outstandingShares": 5987867000,
|
12
|
+
"eps": 6.2,
|
13
|
+
"pe": 16.54,
|
14
|
+
"dividend": 0.47,
|
15
|
+
"yield": 1.84,
|
16
|
+
"exDate": "2014-08-07T00:00:00.000000-04:00",
|
17
|
+
"marketCap": 613756367500,
|
18
|
+
"tradeUnit": 1,
|
19
|
+
"optionType": null,
|
20
|
+
"optionDurationType": null,
|
21
|
+
"optionRoot": "",
|
22
|
+
"optionContractDeliverables": {
|
23
|
+
"underlyings": [],
|
24
|
+
"cashInLieu": 0
|
25
|
+
},
|
26
|
+
"optionExerciseType": null,
|
27
|
+
"listingExchange": "NASDAQ",
|
28
|
+
"description": "APPLE INC",
|
29
|
+
"securityType": "Stock",
|
30
|
+
"optionExpiryDate": null,
|
31
|
+
"dividendDate": "2014-08-14T00:00:00.000000-04:00",
|
32
|
+
"optionStrikePrice": null,
|
33
|
+
"isTradable": true,
|
34
|
+
"isQuotable": true,
|
35
|
+
"hasOptions": true,
|
36
|
+
"minTicks": [
|
37
|
+
{
|
38
|
+
"pivot": 0,
|
39
|
+
"minTick": 0.0001
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"pivot": 1,
|
43
|
+
"minTick": 0.01
|
44
|
+
}
|
45
|
+
],
|
46
|
+
"industrySector": "BasicMaterials",
|
47
|
+
"industryGroup": "Steel",
|
48
|
+
"industrySubGroup": "Steel"
|
49
|
+
}
|
50
|
+
]
|
51
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"symbol": [
|
3
|
+
{
|
4
|
+
"symbol": "BMO",
|
5
|
+
"symbolId": 9292,
|
6
|
+
"description": "BANK OF MONTREAL",
|
7
|
+
"securityType": "Stock",
|
8
|
+
"listingExchange": "NYSE",
|
9
|
+
"isTradable": true,
|
10
|
+
"isQuotable": true,
|
11
|
+
"currency": "USD"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"symbol": "BMO.PRJ.TO",
|
15
|
+
"symbolId": 9300,
|
16
|
+
"description": "BANK OF MONTREAL CL B SR 13",
|
17
|
+
"securityType": "Stock",
|
18
|
+
"listingExchange": "TSX",
|
19
|
+
"isTradable": true,
|
20
|
+
"isQuotable": true,
|
21
|
+
"currency": "CAD"
|
22
|
+
}
|
23
|
+
]
|
24
|
+
}
|
@@ -12,8 +12,8 @@ describe QuestradeApi::REST::Activity do
|
|
12
12
|
|
13
13
|
context '.all' do
|
14
14
|
it "returns an object that contains a list of all user's activities for the specific period" do
|
15
|
-
start_time =
|
16
|
-
end_time =
|
15
|
+
start_time = '2011-02-16T00:00:00.000000-05:00'
|
16
|
+
end_time = '2011-02-16T00:00:00.000000-05:00'
|
17
17
|
params = "startTime=#{start_time}&endTime=#{end_time}"
|
18
18
|
full_url =
|
19
19
|
url + QuestradeApi::REST::Activity.endpoint(account_id) + "?#{params}"
|
@@ -12,8 +12,8 @@ describe QuestradeApi::REST::Execution do
|
|
12
12
|
|
13
13
|
context '.all' do
|
14
14
|
it "returns an object that contains a list of all user's executions for the specific period" do
|
15
|
-
start_time =
|
16
|
-
end_time =
|
15
|
+
start_time = '2014-03-31T13:38:29-04:00'
|
16
|
+
end_time = '2014-03-31T13:38:29-04:00'
|
17
17
|
params = "startTime=#{start_time}&endTime=#{end_time}"
|
18
18
|
full_url =
|
19
19
|
url + QuestradeApi::REST::Execution.endpoint(account_id) + "?#{params}"
|
@@ -12,7 +12,7 @@ describe QuestradeApi::REST::Order do
|
|
12
12
|
|
13
13
|
context '.all' do
|
14
14
|
it "returns an object that contains a list of all user's orders" do
|
15
|
-
time =
|
15
|
+
time = '2014-03-31T13:38:29-04:00'
|
16
16
|
params = "startTime=#{time}&endTime=#{time}&stateFilter=All"
|
17
17
|
full_url =
|
18
18
|
url + QuestradeApi::REST::Order.endpoint(account_id) + "?#{params}"
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'questrade_api/rest/symbol'
|
4
|
+
|
5
|
+
describe QuestradeApi::REST::Symbol do
|
6
|
+
include JSONFixtures
|
7
|
+
|
8
|
+
let(:access_token) { 'XXXX' }
|
9
|
+
let(:account_id) { '123456' }
|
10
|
+
let(:url) { 'http://test.com'}
|
11
|
+
let(:authorization) { OpenStruct.new(access_token: access_token, url: url) }
|
12
|
+
|
13
|
+
context '.search' do
|
14
|
+
let(:prefix) { 'BMO' }
|
15
|
+
|
16
|
+
it 'calls endpoint passing prefix' do
|
17
|
+
stub_request(:get, "http://test.com/v1/symbols/search?prefix=#{prefix}")
|
18
|
+
.to_return(status: 200, body: '{}').times(1)
|
19
|
+
response = QuestradeApi::REST::Symbol.search(authorization, prefix: prefix)
|
20
|
+
|
21
|
+
expect(response.symbols.size).to be(0)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'calls endpoint passing offset' do
|
25
|
+
stub_request(:get, "http://test.com/v1/symbols/search?offset=2")
|
26
|
+
.to_return(status: 200, body: '{}').times(1)
|
27
|
+
response = QuestradeApi::REST::Symbol.search(authorization, offset: 2)
|
28
|
+
|
29
|
+
expect(response.symbols.size).to be(0)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns an object that contains a list of searched symbols' do
|
33
|
+
stub_request(:get, "http://test.com/v1/symbols/search?prefix=#{prefix}")
|
34
|
+
.to_return(status: 200, body: json_string('symbols_search.json'))
|
35
|
+
response = QuestradeApi::REST::Symbol.search(authorization, prefix: prefix)
|
36
|
+
|
37
|
+
expect(response.symbols.size).to be(2)
|
38
|
+
|
39
|
+
first_symbol = response.symbols.first
|
40
|
+
expect(first_symbol.id).to eq(9292)
|
41
|
+
expect(first_symbol.data.to_h).to eq(
|
42
|
+
symbol: "BMO",
|
43
|
+
symbol_id: 9292,
|
44
|
+
description: "BANK OF MONTREAL",
|
45
|
+
security_type: "Stock",
|
46
|
+
listing_exchange: "NYSE",
|
47
|
+
is_tradable: true,
|
48
|
+
is_quotable: true,
|
49
|
+
currency: "USD"
|
50
|
+
)
|
51
|
+
|
52
|
+
last_symbol = response.symbols.last
|
53
|
+
expect(last_symbol.id).to eq(9300)
|
54
|
+
expect(last_symbol.data.to_h).to eq(
|
55
|
+
symbol: "BMO.PRJ.TO",
|
56
|
+
symbol_id: 9300,
|
57
|
+
description: "BANK OF MONTREAL CL B SR 13",
|
58
|
+
security_type: "Stock",
|
59
|
+
listing_exchange: "TSX",
|
60
|
+
is_tradable: true,
|
61
|
+
is_quotable: true,
|
62
|
+
currency: "CAD"
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context '.all' do
|
68
|
+
let(:ids) { [8049, 8050] }
|
69
|
+
let(:names) { ['AAPL', 'GOOGL'] }
|
70
|
+
|
71
|
+
it 'calls endpoint passing a list of ids' do
|
72
|
+
stub_request(:get, "http://test.com/v1/symbols/?ids=8049,8050")
|
73
|
+
.to_return(status: 200, body: '{}').times(1)
|
74
|
+
response = QuestradeApi::REST::Symbol.all(authorization, ids: ids)
|
75
|
+
|
76
|
+
expect(response.symbols.size).to be(0)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'calls endpoint passing a list of names' do
|
80
|
+
stub_request(:get, "http://test.com/v1/symbols/?names=AAPL,GOOGL")
|
81
|
+
.to_return(status: 200, body: '{}')
|
82
|
+
response = QuestradeApi::REST::Symbol.all(authorization, names: names)
|
83
|
+
|
84
|
+
expect(response.symbols.size).to be(0)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns an object that contains a list of symbols' do
|
88
|
+
stub_request(:get, "http://test.com/v1/symbols/")
|
89
|
+
.to_return(status: 200, body: json_string('symbols.json'))
|
90
|
+
|
91
|
+
response = QuestradeApi::REST::Symbol.all(authorization)
|
92
|
+
|
93
|
+
expect(response.symbols.size).to be(1)
|
94
|
+
|
95
|
+
first_symbol = response.symbols.first
|
96
|
+
expect(first_symbol.id).to eq(8049)
|
97
|
+
expect(first_symbol.data.to_h).to eq(
|
98
|
+
symbol: 'AAPL',
|
99
|
+
symbol_id: 8049,
|
100
|
+
prev_day_close_price: 102.5,
|
101
|
+
high_price52: 102.9,
|
102
|
+
low_price52: 63.89,
|
103
|
+
average_vol3_months: 43769680,
|
104
|
+
average_vol20_days: 12860370,
|
105
|
+
outstanding_shares: 5987867000,
|
106
|
+
eps: 6.2,
|
107
|
+
pe: 16.54,
|
108
|
+
dividend: 0.47,
|
109
|
+
yield: 1.84,
|
110
|
+
ex_date: "2014-08-07T00:00:00.000000-04:00",
|
111
|
+
market_cap: 613756367500,
|
112
|
+
trade_unit: 1,
|
113
|
+
option_type: nil,
|
114
|
+
option_duration_type: nil,
|
115
|
+
option_root: "",
|
116
|
+
option_contract_deliverables: {
|
117
|
+
'underlyings' => [],
|
118
|
+
'cashInLieu' => 0
|
119
|
+
},
|
120
|
+
option_exercise_type: nil,
|
121
|
+
listing_exchange: "NASDAQ",
|
122
|
+
description: "APPLE INC",
|
123
|
+
security_type: "Stock",
|
124
|
+
option_expiry_date: nil,
|
125
|
+
dividend_date: "2014-08-14T00:00:00.000000-04:00",
|
126
|
+
option_strike_price: nil,
|
127
|
+
is_tradable: true,
|
128
|
+
is_quotable: true,
|
129
|
+
has_options: true,
|
130
|
+
min_ticks: [
|
131
|
+
{
|
132
|
+
'pivot' => 0,
|
133
|
+
'minTick' => 0.0001
|
134
|
+
},
|
135
|
+
{
|
136
|
+
'pivot' => 1,
|
137
|
+
'minTick' => 0.01
|
138
|
+
}
|
139
|
+
],
|
140
|
+
industry_sector: "BasicMaterials",
|
141
|
+
industry_group: "Steel",
|
142
|
+
industry_sub_group: "Steel")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context '.endpoint' do
|
147
|
+
it 'calls endpoint with no param passed' do
|
148
|
+
url = "/v1/symbols/"
|
149
|
+
expect(QuestradeApi::REST::Symbol.endpoint).to eq(url)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'calls endpoint with param passed' do
|
153
|
+
url = "/v1/symbols/search"
|
154
|
+
expect(QuestradeApi::REST::Symbol.endpoint('search')).to eq(url)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: questrade_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno Meira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- lib/questrade_api/rest/market.rb
|
95
95
|
- lib/questrade_api/rest/order.rb
|
96
96
|
- lib/questrade_api/rest/position.rb
|
97
|
+
- lib/questrade_api/rest/symbol.rb
|
97
98
|
- lib/questrade_api/rest/time.rb
|
98
99
|
- lib/questrade_api/version.rb
|
99
100
|
- questrade_api.gemspec
|
@@ -104,6 +105,8 @@ files:
|
|
104
105
|
- spec/fixtures/json/markets.json
|
105
106
|
- spec/fixtures/json/orders.json
|
106
107
|
- spec/fixtures/json/positions.json
|
108
|
+
- spec/fixtures/json/symbols.json
|
109
|
+
- spec/fixtures/json/symbols_search.json
|
107
110
|
- spec/fixtures/json/time.json
|
108
111
|
- spec/questrade_api/authorization_spec.rb
|
109
112
|
- spec/questrade_api/client_spec.rb
|
@@ -114,6 +117,7 @@ files:
|
|
114
117
|
- spec/questrade_api/rest/market_spec.rb
|
115
118
|
- spec/questrade_api/rest/order_spec.rb
|
116
119
|
- spec/questrade_api/rest/position_spec.rb
|
120
|
+
- spec/questrade_api/rest/symbol_spec.rb
|
117
121
|
- spec/questrade_api/rest/time_spec.rb
|
118
122
|
- spec/spec_helper.rb
|
119
123
|
- spec/support/json_fixtures.rb
|
@@ -137,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
141
|
version: '0'
|
138
142
|
requirements: []
|
139
143
|
rubyforge_project:
|
140
|
-
rubygems_version: 2.
|
144
|
+
rubygems_version: 2.2.2
|
141
145
|
signing_key:
|
142
146
|
specification_version: 4
|
143
147
|
summary: An elegant Ruby gem to interact with Questrade API
|
@@ -149,6 +153,8 @@ test_files:
|
|
149
153
|
- spec/fixtures/json/markets.json
|
150
154
|
- spec/fixtures/json/orders.json
|
151
155
|
- spec/fixtures/json/positions.json
|
156
|
+
- spec/fixtures/json/symbols.json
|
157
|
+
- spec/fixtures/json/symbols_search.json
|
152
158
|
- spec/fixtures/json/time.json
|
153
159
|
- spec/questrade_api/authorization_spec.rb
|
154
160
|
- spec/questrade_api/client_spec.rb
|
@@ -159,6 +165,7 @@ test_files:
|
|
159
165
|
- spec/questrade_api/rest/market_spec.rb
|
160
166
|
- spec/questrade_api/rest/order_spec.rb
|
161
167
|
- spec/questrade_api/rest/position_spec.rb
|
168
|
+
- spec/questrade_api/rest/symbol_spec.rb
|
162
169
|
- spec/questrade_api/rest/time_spec.rb
|
163
170
|
- spec/spec_helper.rb
|
164
171
|
- spec/support/json_fixtures.rb
|