nis-ruby 0.0.11.1 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/LICENSE +21 -0
- data/README.md +23 -43
- data/{samples/request_account.rb → examples/account.rb} +2 -10
- data/{samples/request_block.rb → examples/block.rb} +0 -0
- data/{samples/request_debug.rb → examples/debug.rb} +0 -8
- data/{samples/request_local.rb → examples/local.rb} +0 -5
- data/{samples/request_namespace.rb → examples/namespace.rb} +0 -3
- data/{samples/request_nis.rb → examples/nis.rb} +0 -0
- data/{samples/request_node.rb → examples/node.rb} +0 -9
- data/examples/shutdown.rb +6 -0
- data/examples/transactions/importance_transfer.rb +22 -0
- data/examples/transactions/mosaic_definition_creation.rb +50 -0
- data/examples/transactions/mosaic_supply_change.rb +24 -0
- data/examples/transactions/multisig.rb +26 -0
- data/examples/transactions/multisig_add_cosignatory.rb +31 -0
- data/examples/transactions/multisig_aggregate_modification.rb +28 -0
- data/examples/transactions/multisig_signature.rb +38 -0
- data/examples/transactions/provision_namespace.rb +19 -0
- data/examples/transactions/transfer.rb +22 -0
- data/lib/nis.rb +8 -4
- data/lib/nis/client.rb +2 -1
- data/lib/nis/endpoint/shutdown.rb +7 -0
- data/lib/nis/endpoint/transaction/announce.rb +1 -1
- data/lib/nis/endpoint/transaction/prepareAnnounce.rb +1 -1
- data/lib/nis/fee.rb +1 -0
- data/lib/nis/fee/importance_transfer.rb +22 -0
- data/lib/nis/fee/mosaic_definition_creation.rb +22 -0
- data/lib/nis/fee/mosaic_supply_change_transfer.rb +22 -0
- data/lib/nis/fee/multisig.rb +22 -0
- data/lib/nis/fee/multisig_aggregation_modification.rb +30 -0
- data/lib/nis/fee/provision_namespace.rb +32 -0
- data/lib/nis/fee/transfer.rb +51 -0
- data/lib/nis/keypair.rb +18 -0
- data/lib/nis/mixin/struct.rb +50 -0
- data/lib/nis/request.rb +1 -0
- data/lib/nis/request/announce.rb +10 -0
- data/lib/nis/request/prepare_announce.rb +48 -0
- data/lib/nis/struct/block.rb +1 -1
- data/lib/nis/struct/mosaic_properties.rb +2 -2
- data/lib/nis/transaction/importance_transfer.rb +25 -28
- data/lib/nis/transaction/mosaic_definition_creation.rb +33 -34
- data/lib/nis/transaction/mosaic_supply_change.rb +30 -30
- data/lib/nis/transaction/multisig.rb +17 -36
- data/lib/nis/transaction/multisig_aggregate_modification.rb +29 -31
- data/lib/nis/transaction/multisig_signature.rb +24 -23
- data/lib/nis/transaction/provision_namespace.rb +53 -33
- data/lib/nis/transaction/transfer.rb +22 -52
- data/lib/nis/util.rb +16 -13
- data/lib/nis/version.rb +1 -1
- data/nis.gemspec +2 -0
- metadata +62 -19
- data/lib/nis/mixin/network.rb +0 -20
- data/samples/request_importance_transfer_transaction.rb +0 -34
- data/samples/request_mosaic_definition_creation_transaction.rb +0 -62
- data/samples/request_mosaic_supply_change_transaction.rb +0 -35
- data/samples/request_multisig_add_cosignatory_transaction.rb +0 -58
- data/samples/request_multisig_aggregate_modification_transaction.rb +0 -45
- data/samples/request_multisig_signature_transaction.rb +0 -53
- data/samples/request_multisig_transaction.rb +0 -54
- data/samples/request_provision_namespace_transaction.rb +0 -31
- data/samples/request_transfer_transaction.rb +0 -47
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'nis'
|
2
|
+
|
3
|
+
# Account A (multisig)
|
4
|
+
A_PUBLIC_KEY = '4b26a75313b747985470977a085ae6f840a0b84ebd96ddf17f4a31a2b580d078'
|
5
|
+
|
6
|
+
# Account B (cosignatory1)
|
7
|
+
B_PRIVATE_KEY = '260206d683962350532408e8774fd14870a173b7fba17f6b504da3dbc5f1cc9f'
|
8
|
+
B_PUBLIC_KEY = 'cc63b4dcdec745417043c3fa0992ec3a1695461a26d90264744648abbd5caa0d'
|
9
|
+
|
10
|
+
# Account C (cosignatory2)
|
11
|
+
C_PUBLIC_KEY = '9fd1e5e886c4006efc715a0e183f2a87f198b8d19c44e7c67925b01aa45a7114'
|
12
|
+
|
13
|
+
# TODO: public key calculated from private key in future version.
|
14
|
+
# it will not need to set public key.
|
15
|
+
kp = Nis::Keypair.new(B_PRIVATE_KEY, public_key: B_PUBLIC_KEY)
|
16
|
+
|
17
|
+
mcm = Nis::Struct::MultisigCosignatoryModification.new(
|
18
|
+
modificationType: 1,
|
19
|
+
cosignatoryAccount: C_PUBLIC_KEY
|
20
|
+
)
|
21
|
+
min_cosigs = 2
|
22
|
+
mtx = Nis::Transaction::MultisigAggregateModification.new([mcm], min_cosigs)
|
23
|
+
|
24
|
+
tx = Nis::Transaction::Multisig.new(mtx, A_PUBLIC_KEY)
|
25
|
+
|
26
|
+
nis = Nis.new
|
27
|
+
req = Nis::Request::PrepareAnnounce.new(tx, kp)
|
28
|
+
res = nis.transaction_prepare_announce(req)
|
29
|
+
|
30
|
+
puts "Message: #{res.message}"
|
31
|
+
puts "TransactionHash: #{res.transaction_hash}"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'nis'
|
2
|
+
|
3
|
+
# multisig
|
4
|
+
A_PRIVATE_KEY = '9bf8e6fd1a178a3cce39840cda34f80f55fe075c15f48eefad8506f4a70c2b47'
|
5
|
+
A_PUBLIC_KEY = '4b26a75313b747985470977a085ae6f840a0b84ebd96ddf17f4a31a2b580d078'
|
6
|
+
|
7
|
+
# cosignatory
|
8
|
+
B_PUBLIC_KEY = 'cc63b4dcdec745417043c3fa0992ec3a1695461a26d90264744648abbd5caa0d'
|
9
|
+
|
10
|
+
# TODO: public key calculated from private key in future version.
|
11
|
+
# it will not need to set public key.
|
12
|
+
kp = Nis::Keypair.new(A_PRIVATE_KEY, public_key: A_PUBLIC_KEY)
|
13
|
+
|
14
|
+
mcm = Nis::Struct::MultisigCosignatoryModification.new(
|
15
|
+
modificationType: 1,
|
16
|
+
cosignatoryAccount: B_PUBLIC_KEY
|
17
|
+
)
|
18
|
+
min_cosigs = 1
|
19
|
+
|
20
|
+
tx = Nis::Transaction::MultisigAggregateModification.new([mcm], min_cosigs)
|
21
|
+
puts "Fee: #{tx.fee.to_i}"
|
22
|
+
|
23
|
+
nis = Nis.new
|
24
|
+
req = Nis::Request::PrepareAnnounce.new(tx, kp)
|
25
|
+
res = nis.transaction_prepare_announce(req)
|
26
|
+
|
27
|
+
puts "Message: #{res.message}"
|
28
|
+
puts "TransactionHash: #{res.transaction_hash}"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'nis'
|
2
|
+
|
3
|
+
# multisig
|
4
|
+
A_PUBLIC_KEY = '4b26a75313b747985470977a085ae6f840a0b84ebd96ddf17f4a31a2b580d078'
|
5
|
+
A_ADDRESS = 'TBAOYZS4FGY5XPQ5OD2VL3SY7GQ5FLH66GRCX5DL'
|
6
|
+
|
7
|
+
# cosignatory1
|
8
|
+
# B_PRIVATE_KEY = '260206d683962350532408e8774fd14870a173b7fba17f6b504da3dbc5f1cc9f'
|
9
|
+
# B_PUBLIC_KEY = 'cc63b4dcdec745417043c3fa0992ec3a1695461a26d90264744648abbd5caa0d'
|
10
|
+
# B_ADDRESS = 'TAWKJTUP4DWKLDKKS534TYP6G324CBNMXKBA4X7B'
|
11
|
+
|
12
|
+
# cosignatory2
|
13
|
+
C_PRIVATE_KEY = '2f6bececfaa81e0ce878be6263df29d11412559132743eebde99f695fbc4e288'
|
14
|
+
C_PUBLIC_KEY = '9fd1e5e886c4006efc715a0e183f2a87f198b8d19c44e7c67925b01aa45a7114'
|
15
|
+
C_ADDRESS = 'TAFPFQOTRYEKMKWWKLLLMYA3I5SCFDGYFACCOFWS'
|
16
|
+
|
17
|
+
# TODO: public key calculated from private key in future version.
|
18
|
+
# it will not need to set public key.
|
19
|
+
kp = Nis::Keypair.new(C_PRIVATE_KEY, public_key: C_PUBLIC_KEY)
|
20
|
+
|
21
|
+
nis = Nis.new
|
22
|
+
txes = nis.account_unconfirmed_transactions(address: C_ADDRESS)
|
23
|
+
|
24
|
+
unless txes.size > 0
|
25
|
+
puts 'There are no transactions to sign.'
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
hash = txes.first.meta.data
|
30
|
+
puts "Unconfirmed Transaction Hash: #{hash}"
|
31
|
+
|
32
|
+
tx = Nis::Transaction::MultisigSignature.new(hash, A_ADDRESS, C_PUBLIC_KEY)
|
33
|
+
|
34
|
+
req = Nis::Request::PrepareAnnounce.new(tx, kp)
|
35
|
+
res = nis.transaction_prepare_announce(req)
|
36
|
+
|
37
|
+
puts "Message: #{res.message}"
|
38
|
+
puts "TransactionHash: #{res.transaction_hash}"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'nis'
|
2
|
+
|
3
|
+
# owner
|
4
|
+
A_PRIVATE_KEY = '260206d683962350532408e8774fd14870a173b7fba17f6b504da3dbc5f1cc9f'
|
5
|
+
A_PUBLIC_KEY = 'cc63b4dcdec745417043c3fa0992ec3a1695461a26d90264744648abbd5caa0d'
|
6
|
+
|
7
|
+
# TODO: public key calculated from private key in future version.
|
8
|
+
# it will not need to set public key.
|
9
|
+
kp = Nis::Keypair.new(A_PRIVATE_KEY, public_key: A_PUBLIC_KEY)
|
10
|
+
|
11
|
+
tx = Nis::Transaction::ProvisionNamespace.new('sushi')
|
12
|
+
puts "Fee: #{tx.fee.to_i}"
|
13
|
+
|
14
|
+
nis = Nis.new
|
15
|
+
req = Nis::Request::PrepareAnnounce.new(tx, kp)
|
16
|
+
res = nis.transaction_prepare_announce(req)
|
17
|
+
|
18
|
+
puts "Message: #{res.message}"
|
19
|
+
puts "TransactionHash: #{res.transaction_hash}"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'nis'
|
2
|
+
|
3
|
+
# sender
|
4
|
+
A_PRIVATE_KEY = '260206d683962350532408e8774fd14870a173b7fba17f6b504da3dbc5f1cc9f'
|
5
|
+
A_PUBLIC_KEY = 'cc63b4dcdec745417043c3fa0992ec3a1695461a26d90264744648abbd5caa0d'
|
6
|
+
|
7
|
+
# receiver
|
8
|
+
B_ADDRESS = 'TAWKJTUP4DWKLDKKS534TYP6G324CBNMXKBA4X7B'
|
9
|
+
|
10
|
+
# TODO: public key calculated from private key in future version.
|
11
|
+
# it will not need to set public key.
|
12
|
+
kp = Nis::Keypair.new(A_PRIVATE_KEY, public_key: A_PUBLIC_KEY)
|
13
|
+
|
14
|
+
tx = Nis::Transaction::Transfer.new(B_ADDRESS, 1_000_000, 'Good luck!')
|
15
|
+
puts "Fee: #{tx.fee.to_i}"
|
16
|
+
|
17
|
+
nis = Nis.new
|
18
|
+
req = Nis::Request::PrepareAnnounce.new(tx, kp)
|
19
|
+
res = nis.transaction_prepare_announce(req)
|
20
|
+
|
21
|
+
puts "Message: #{res.message}"
|
22
|
+
puts "TransactionHash: #{res.transaction_hash}"
|
data/lib/nis.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'nis/version'
|
2
2
|
require 'nis/mixin'
|
3
3
|
require 'nis/util'
|
4
|
+
require 'nis/keypair'
|
5
|
+
require 'nis/fee'
|
4
6
|
require 'nis/client'
|
7
|
+
require 'nis/request'
|
5
8
|
require 'nis/endpoint'
|
6
9
|
require 'nis/struct'
|
7
10
|
require 'nis/transaction'
|
@@ -15,17 +18,18 @@ class Nis
|
|
15
18
|
def_delegators :@client, :request, :request!
|
16
19
|
|
17
20
|
# @param [hash] options HTTP Client connection information
|
18
|
-
# @option options [
|
19
|
-
# @option options [
|
21
|
+
# @option options [String] :url URL
|
22
|
+
# @option options [String] :scheme default http
|
20
23
|
# @option options [Symbol] :host default 127.0.0.1
|
21
|
-
# @option options [
|
22
|
-
# @option options [
|
24
|
+
# @option options [Integer] :port default 7890
|
25
|
+
# @option options [Integer] :timeout default 5
|
23
26
|
def initialize(options = {})
|
24
27
|
@client = Client.new(options)
|
25
28
|
end
|
26
29
|
|
27
30
|
include Nis::Endpoint::Heartbeat
|
28
31
|
include Nis::Endpoint::Status
|
32
|
+
include Nis::Endpoint::Shutdown
|
29
33
|
|
30
34
|
include Nis::Endpoint::Account::Generate
|
31
35
|
include Nis::Endpoint::Account::Get
|
data/lib/nis/client.rb
CHANGED
@@ -3,7 +3,7 @@ module Nis::Endpoint
|
|
3
3
|
# @param [Nis::Struct::RequestAnnounce] request_announce
|
4
4
|
# @return [Nis::Struct::Node]
|
5
5
|
# @see http://bob.nem.ninja/docs/#sending-the-data-to-NIS
|
6
|
-
def transaction_announce(request_announce
|
6
|
+
def transaction_announce(request_announce)
|
7
7
|
Nis::Struct::NemAnnounceResult.build request!(:post,
|
8
8
|
'/transaction/announce',
|
9
9
|
request_announce
|
@@ -3,7 +3,7 @@ module Nis::Endpoint
|
|
3
3
|
# @param [Nis::Struct::RequestPrepareAnnounce] request_prepare_announce
|
4
4
|
# @return [Nis::Struct::Node]
|
5
5
|
# @see http://bob.nem.ninja/docs/#initiating-a-transaction
|
6
|
-
def transaction_prepare_announce(request_prepare_announce
|
6
|
+
def transaction_prepare_announce(request_prepare_announce)
|
7
7
|
Nis::Struct::NemAnnounceResult.build request!(:post,
|
8
8
|
'/transaction/prepare-announce',
|
9
9
|
request_prepare_announce
|
data/lib/nis/fee.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.expand_path('../fee/*.rb', __FILE__)].each { |f| require f }
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class ImportanceTransfer
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
testnet? ? 0.15 * 1_000_000 : 6_000_000
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Integer] fee in micro XEM
|
13
|
+
def to_i
|
14
|
+
value.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
def testnet?
|
19
|
+
@transaction.network == :testnet
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class MosaicDefinitionCreation
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
(testnet? ? 10 : 500) * 1_000_000
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Integer] fee in micro XEM
|
13
|
+
def to_i
|
14
|
+
value.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
def testnet?
|
19
|
+
@transaction.network == :testnet
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class MosaicSupplyChangeTransfer
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
testnet? ? 0.15 * 1_000_000 : 20 * 1_000_000
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Integer] fee in micro XEM
|
13
|
+
def to_i
|
14
|
+
value.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
def testnet?
|
19
|
+
@transaction.network == :testnet
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class Multisig
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
testnet? ? 0.15 * 1_000_000 : 6_000_000
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Integer] fee in micro XEM
|
13
|
+
def to_i
|
14
|
+
value.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
def testnet?
|
19
|
+
@transaction.network == :testnet
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class MultisigAggregateModification
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
if @transaction.minCosignatories == 0
|
10
|
+
testnet? ?
|
11
|
+
0.5 * 1_000_000 :
|
12
|
+
(10 + 6 * @transaction.modifications.length) * 1_000_000
|
13
|
+
else
|
14
|
+
testnet? ?
|
15
|
+
0.5 * 1_000_000 :
|
16
|
+
(10 + 6 * @transaction.modifications.length + 6) * 1_000_000
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Integer] fee in micro XEM
|
21
|
+
def to_i
|
22
|
+
value.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean]
|
26
|
+
def testnet?
|
27
|
+
@transaction.network == :testnet
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class ProvisionNamespace
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
@transaction.root? ? root_fee : sub_fee
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Integer] fee in micro XEM
|
13
|
+
def to_i
|
14
|
+
value.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
def testnet?
|
19
|
+
@transaction.network == :testnet
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def root_fee
|
25
|
+
(testnet? ? 100 : 5_000) * 1_000_000
|
26
|
+
end
|
27
|
+
|
28
|
+
def sub_fee
|
29
|
+
(testnet? ? 10 : 200) * 1_000_000
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Nis::Fee
|
2
|
+
class Transfer
|
3
|
+
def initialize(transaction)
|
4
|
+
@transaction = transaction
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Integer] fee in micro XEM
|
8
|
+
def value
|
9
|
+
tmp = 0
|
10
|
+
|
11
|
+
if @transaction.mosaics.empty?
|
12
|
+
tmp += min_fee
|
13
|
+
else
|
14
|
+
tmp += mosaics_fee
|
15
|
+
end
|
16
|
+
|
17
|
+
if @transaction.message.bytesize > 0
|
18
|
+
tmp += message_fee
|
19
|
+
end
|
20
|
+
|
21
|
+
tmp * 1_000_000
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Integer] fee in micro XEM
|
25
|
+
def to_i
|
26
|
+
value.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Boolean]
|
30
|
+
def testnet?
|
31
|
+
@transaction.network == :testnet
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def min_fee
|
37
|
+
tmp = [1, @transaction.amount / 1_000_000 / 10_000].max
|
38
|
+
tmp = (tmp > 25 ? 25 : tmp)
|
39
|
+
testnet? ? 0.05 * tmp : tmp
|
40
|
+
end
|
41
|
+
|
42
|
+
def message_fee
|
43
|
+
tmp = [1, (@transaction.message.bytesize / 2 / 32) + 1].max
|
44
|
+
testnet? ? 0.05 * tmp : tmp
|
45
|
+
end
|
46
|
+
|
47
|
+
def mosaics_fee
|
48
|
+
raise NotImplementedError, 'not implemented calculation mosaics fee.'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/nis/keypair.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Nis
|
2
|
+
class Keypair
|
3
|
+
attr_reader :private, :public
|
4
|
+
|
5
|
+
def initialize(private_key, public_key: nil)
|
6
|
+
@private = private_key
|
7
|
+
@public = public_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def fix_private_key(key)
|
11
|
+
"#{'0' * 64}#{key.sub(/^00/i, '')}"[-64, 64]
|
12
|
+
end
|
13
|
+
|
14
|
+
def calc_pubkey
|
15
|
+
# TODO: calculate pubkey from privkey
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|