btcruby 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/RELEASE_NOTES.md +6 -0
- data/lib/btcruby/address.rb +5 -1
- data/lib/btcruby/transaction_input.rb +1 -0
- data/lib/btcruby/transaction_outpoint.rb +11 -1
- data/lib/btcruby/transaction_output.rb +2 -1
- data/lib/btcruby/version.rb +1 -1
- metadata +28 -18
- data/.gitignore +0 -20
- data/FAQ.md +0 -7
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -18
- data/HOWTO.md +0 -17
- data/Rakefile +0 -6
- data/TODO.txt +0 -40
- data/bin/console +0 -19
- data/btcruby.gemspec +0 -20
- data/sample_code/creating_a_p2sh_multisig_address.rb +0 -21
- data/sample_code/creating_a_transaction_manually.rb +0 -44
- data/sample_code/generating_an_address.rb +0 -20
- data/sample_code/using_transaction_builder.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b9b9d085300b3e99129f1512fa8b0b7794a4aa4
|
4
|
+
data.tar.gz: 7fc8e5d75b7518afd548c7c5dbf49b7c98ec7f7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 408fcbdd2fdc406a450382dcce2c86744a7c718f5a4d770a3a7c714f56a28b674d51a450968a2af857bac8c8390f37438efc8db8ef6e5003dc35a4623b3d5204
|
7
|
+
data.tar.gz: 48b073e59fa89922faa469dff926beff3261ef762270efd18de1ba31aabb5506ff84d7297d582192d392d7daee4fec7bb284ee04e0d5445e920dd9df62ead358
|
data/README.md
CHANGED
data/RELEASE_NOTES.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
BTCRuby Release Notes
|
3
3
|
=====================
|
4
4
|
|
5
|
+
1.0.6 (July 13, 2015)
|
6
|
+
--------------------
|
7
|
+
|
8
|
+
* Consistent aliasing between `==` and `eql?`
|
9
|
+
* `TransactionOutpoint` implements `hash` method so it can be used as a key in a dictionary.
|
10
|
+
|
5
11
|
1.0.5 (July 8, 2015)
|
6
12
|
--------------------
|
7
13
|
|
data/lib/btcruby/address.rb
CHANGED
@@ -111,9 +111,13 @@ module BTC
|
|
111
111
|
# Two instances are equal when they have the same contents and versions.
|
112
112
|
def ==(other)
|
113
113
|
return false if !other
|
114
|
-
|
114
|
+
data == other.data && version == other.version
|
115
115
|
end
|
116
116
|
alias_method :eql?, :==
|
117
|
+
|
118
|
+
def hash
|
119
|
+
data.hash
|
120
|
+
end
|
117
121
|
|
118
122
|
# Returns Base58Check representation of an address.
|
119
123
|
def to_s
|
@@ -22,7 +22,17 @@ module BTC
|
|
22
22
|
def outpoint_id
|
23
23
|
%{#{transaction_id}:#{index}}
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
index == other.index &&
|
28
|
+
transaction_hash == other.transaction_hash
|
29
|
+
end
|
30
|
+
alias_method :eql?, :==
|
31
|
+
|
32
|
+
def hash
|
33
|
+
transaction_hash.hash ^ index
|
34
|
+
end
|
35
|
+
|
26
36
|
def to_s
|
27
37
|
outpoint_id
|
28
38
|
end
|
@@ -275,9 +275,10 @@ module BTC
|
|
275
275
|
|
276
276
|
def ==(other)
|
277
277
|
return true if super(other)
|
278
|
-
return true if
|
278
|
+
return true if data == other.data
|
279
279
|
return false
|
280
280
|
end
|
281
|
+
alias_method :eql?, :==
|
281
282
|
|
282
283
|
# Makes a deep copy of a transaction output
|
283
284
|
def dup
|
data/lib/btcruby/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: btcruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Andreev
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
12
|
+
date: 2015-07-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -31,24 +31,15 @@ dependencies:
|
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.9.3
|
34
|
-
description:
|
34
|
+
description: Bitcoin toolkit for Ruby
|
35
35
|
email: oleganza+btcruby@gmail.com
|
36
36
|
executables: []
|
37
37
|
extensions: []
|
38
38
|
extra_rdoc_files: []
|
39
39
|
files:
|
40
|
-
- ".gitignore"
|
41
|
-
- FAQ.md
|
42
|
-
- Gemfile
|
43
|
-
- Gemfile.lock
|
44
|
-
- HOWTO.md
|
45
40
|
- LICENSE
|
46
41
|
- README.md
|
47
42
|
- RELEASE_NOTES.md
|
48
|
-
- Rakefile
|
49
|
-
- TODO.txt
|
50
|
-
- bin/console
|
51
|
-
- btcruby.gemspec
|
52
43
|
- documentation/address.md
|
53
44
|
- documentation/base58.md
|
54
45
|
- documentation/block.md
|
@@ -127,10 +118,6 @@ files:
|
|
127
118
|
- lib/btcruby/version.rb
|
128
119
|
- lib/btcruby/wif.rb
|
129
120
|
- lib/btcruby/wire_format.rb
|
130
|
-
- sample_code/creating_a_p2sh_multisig_address.rb
|
131
|
-
- sample_code/creating_a_transaction_manually.rb
|
132
|
-
- sample_code/generating_an_address.rb
|
133
|
-
- sample_code/using_transaction_builder.rb
|
134
121
|
- spec/address_spec.rb
|
135
122
|
- spec/all.rb
|
136
123
|
- spec/base58_spec.rb
|
@@ -179,5 +166,28 @@ rubyforge_project: btcruby
|
|
179
166
|
rubygems_version: 2.4.5
|
180
167
|
signing_key:
|
181
168
|
specification_version: 4
|
182
|
-
summary:
|
183
|
-
test_files:
|
169
|
+
summary: Rich library for building awesome Bitcoin apps.
|
170
|
+
test_files:
|
171
|
+
- spec/address_spec.rb
|
172
|
+
- spec/base58_spec.rb
|
173
|
+
- spec/block_header_spec.rb
|
174
|
+
- spec/block_spec.rb
|
175
|
+
- spec/currency_formatter_spec.rb
|
176
|
+
- spec/data_spec.rb
|
177
|
+
- spec/diagnostics_spec.rb
|
178
|
+
- spec/key_spec.rb
|
179
|
+
- spec/keychain_spec.rb
|
180
|
+
- spec/merkle_tree_spec.rb
|
181
|
+
- spec/network_spec.rb
|
182
|
+
- spec/open_assets/asset_address_spec.rb
|
183
|
+
- spec/open_assets/asset_id_spec.rb
|
184
|
+
- spec/open_assets/asset_marker_spec.rb
|
185
|
+
- spec/open_assets/asset_processor_spec.rb
|
186
|
+
- spec/open_assets/asset_transaction_builder_spec.rb
|
187
|
+
- spec/open_assets/asset_transaction_spec.rb
|
188
|
+
- spec/open_assets/issuance_id_spec.rb
|
189
|
+
- spec/proof_of_work_spec.rb
|
190
|
+
- spec/script_spec.rb
|
191
|
+
- spec/transaction_builder_spec.rb
|
192
|
+
- spec/transaction_spec.rb
|
193
|
+
- spec/wire_format_spec.rb
|
data/.gitignore
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
build/
|
2
|
-
*.pbxuser
|
3
|
-
!default.pbxuser
|
4
|
-
*.mode1v3
|
5
|
-
!default.mode1v3
|
6
|
-
*.mode2v3
|
7
|
-
!default.mode2v3
|
8
|
-
*.perspectivev3
|
9
|
-
!default.perspectivev3
|
10
|
-
xcuserdata
|
11
|
-
*.xccheckout
|
12
|
-
*.moved-aside
|
13
|
-
DerivedData
|
14
|
-
*.hmap
|
15
|
-
*.ipa
|
16
|
-
*.xcuserstate
|
17
|
-
*.xcodeproj
|
18
|
-
*.xcodeproj/
|
19
|
-
*.gem
|
20
|
-
.ruby-version
|
data/FAQ.md
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
data/HOWTO.md
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# BTCRuby HOWTO
|
2
|
-
|
3
|
-
* [Generating Private/Public Keys](#generating-privatepublic-keys)
|
4
|
-
|
5
|
-
## Generating Private/Public Keys
|
6
|
-
|
7
|
-
```ruby
|
8
|
-
require 'btcruby'
|
9
|
-
require 'btcruby/extensions'
|
10
|
-
|
11
|
-
key = BTC::Key.random
|
12
|
-
|
13
|
-
prv = key.to_wif # => L2yVhzwp5F7NXUmP31j274MPjnWi7WbFs3qRJEcdrjyBZ9jmEdWb
|
14
|
-
pub = key.address.to_s # => 15M8ocGxsWtaenLQy6hDKXeLHqQgG3ebpB
|
15
|
-
|
16
|
-
puts [prv, pub].join(" - ")
|
17
|
-
```
|
data/Rakefile
DELETED
data/TODO.txt
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
|
2
|
-
TODO:
|
3
|
-
|
4
|
-
- verify integrity of the block after reading: hash all txs in a merkle root and compare with the declared merkle root.
|
5
|
-
- add BIP70 payment request support
|
6
|
-
- add convenience methods to handle BIP44 accounts in BTC::Keychain (like in CoreBitcoin)
|
7
|
-
- add Bitcoin URI support to encode and parse `bitcoin:` URIs.
|
8
|
-
|
9
|
-
+ replace factory methods like `C.with_data` or `C.with_key` with initializer since we now throw exceptions instead of returning nil on input errors.
|
10
|
-
+ block and block header classes
|
11
|
-
+ redesigned transaction builder to return a result object like in CoreBitcoin
|
12
|
-
+ data helpers
|
13
|
-
+ tests
|
14
|
-
+ base58
|
15
|
-
+ addresses
|
16
|
-
+ simplify API for addresses: Address.address_with_string() -> Address.with_string()
|
17
|
-
+ add test for private key address
|
18
|
-
+ keys and signatures support
|
19
|
-
+ canonical signature
|
20
|
-
+ deterministic signatures: k = HMAC-SHA256(hash, privkey)
|
21
|
-
+ add ffi to Gemspec as a dependency
|
22
|
-
+ transaction parsing and composing
|
23
|
-
+ script parsing and composing
|
24
|
-
+ tx import/export in bitcoin-QT dictionary format
|
25
|
-
+ add docs for to_wif/from_wif
|
26
|
-
+ add diagnostics to check canonicality of the signature
|
27
|
-
+ BIP32 implementation: Keychain
|
28
|
-
+ base58/base58check mess: untangle
|
29
|
-
+ specs and fixes for zero-padded private keys
|
30
|
-
+ clearer testnet/mainnet API for Script
|
31
|
-
+ fee computation for transactions
|
32
|
-
+ signature_hash for transaction
|
33
|
-
+ transaction builder
|
34
|
-
+ tx ID conversion to/from hash
|
35
|
-
+ helper properties for Transaction and inputs/outputs to hold extra data received from APIs.
|
36
|
-
|
37
|
-
- test tool to detect broken or non-canonical transactions
|
38
|
-
|
39
|
-
- compact signatures support
|
40
|
-
|
data/bin/console
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require_relative '../lib/btcruby.rb'
|
3
|
-
require_relative '../lib/btcruby/extensions.rb'
|
4
|
-
|
5
|
-
include BTC
|
6
|
-
|
7
|
-
require 'irb'
|
8
|
-
require 'irb/completion'
|
9
|
-
|
10
|
-
# IRB.conf[:PROMPT]||={}
|
11
|
-
# IRB.conf[:PROMPT][:BTC_PROMPT] = { # name of prompt mode
|
12
|
-
# :AUTO_INDENT => true, # enables auto-indent mode
|
13
|
-
# :PROMPT_I => %{>>}, # normal prompt
|
14
|
-
# :PROMPT_S => %{">}, # prompt for continuated strings
|
15
|
-
# :PROMPT_C => %{*>}, # prompt for continuated statement
|
16
|
-
# :RETURN => "=>%s\n" # format to return value
|
17
|
-
# }
|
18
|
-
# IRB.conf[:PROMPT_MODE] = :BTC_PROMPT
|
19
|
-
IRB.start
|
data/btcruby.gemspec
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
#encoding: UTF-8
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "btcruby/version"
|
4
|
-
|
5
|
-
files = `git ls-files`.split("\n")
|
6
|
-
|
7
|
-
Gem::Specification.new do |s|
|
8
|
-
s.name = "btcruby"
|
9
|
-
s.email = "oleganza+btcruby@gmail.com"
|
10
|
-
s.version = BTC::VERSION
|
11
|
-
s.description = "Ruby library for interacting with Bitcoin."
|
12
|
-
s.summary = "Ruby library for interacting with Bitcoin."
|
13
|
-
s.authors = ["Oleg Andreev", "Ryan Smith"]
|
14
|
-
s.homepage = "https://github.com/oleganza/btcruby"
|
15
|
-
s.rubyforge_project = "btcruby"
|
16
|
-
s.license = "MIT"
|
17
|
-
s.files = files
|
18
|
-
s.require_paths = ["lib"]
|
19
|
-
s.add_runtime_dependency 'ffi', '~> 1.9', '>= 1.9.3'
|
20
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# Creating a P2SH multisig address
|
2
|
-
# --------------------------------
|
3
|
-
#
|
4
|
-
# To create a P2SH multisig address you will need a set of public keys.
|
5
|
-
# In the example below we generate three random keys and compose 2-of-3 multisig script
|
6
|
-
# which is then transformed into a P2SH address. To redeem from this address you will need
|
7
|
-
# not only two signatures, but also the original multisig script.
|
8
|
-
|
9
|
-
require_relative "../lib/btcruby.rb"
|
10
|
-
|
11
|
-
keys = [BTC::Key.random, BTC::Key.random, BTC::Key.random]
|
12
|
-
pubkeys = keys.map(&:public_key)
|
13
|
-
|
14
|
-
multisig_script = BTC::Script.multisig_script(public_keys: pubkeys, signatures_required: 2)
|
15
|
-
puts multisig_script.to_s # => "OP_2 03e4e14a... 03b4b3f7... 030fa2ec... OP_3 OP_CHECKMULTISIG"
|
16
|
-
|
17
|
-
p2sh_script = multisig_script.p2sh_script
|
18
|
-
puts p2sh_script.to_s # => "OP_HASH160 26f5b7ad4e890c07b8c55fc551e39d6693c5e984 OP_EQUAL"
|
19
|
-
|
20
|
-
address = p2sh_script.standard_address
|
21
|
-
puts address.to_s # => 35F1xaoodzRZUBJHi6TgA85qPjXQcW8XsQ
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# Creating a transaction manually
|
2
|
-
# -------------------------------
|
3
|
-
#
|
4
|
-
# To manually create a transaction, you will need to specify raw inputs,
|
5
|
-
# compute the signature and compose a signature script for each input and
|
6
|
-
# take care of calculating a change amount correctly.
|
7
|
-
|
8
|
-
require_relative "../lib/btcruby.rb"
|
9
|
-
|
10
|
-
include BTC
|
11
|
-
|
12
|
-
tx = Transaction.new
|
13
|
-
|
14
|
-
# 1. Add a raw input with previous transaction ID and output index.
|
15
|
-
tx.add_input(TransactionInput.new(
|
16
|
-
previous_id: "aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31",
|
17
|
-
previous_index: 0))
|
18
|
-
|
19
|
-
# 2. Add a raw output with a script
|
20
|
-
tx.add_output(TransactionOutput.new(
|
21
|
-
value: 100_000,
|
22
|
-
script: PublicKeyAddress.parse("1CBtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAcG").script))
|
23
|
-
|
24
|
-
# 3. Get the private key from WIF
|
25
|
-
key = Key.new(wif: "L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy")
|
26
|
-
|
27
|
-
# 4. Sign the input (assuming it links to an output with address 18oxCAnbuKHDjP7KzLBDj8mLjggDBjE1Q9)
|
28
|
-
hashtype = BTC::SIGHASH_ALL
|
29
|
-
sighash = tx.signature_hash(input_index: 0,
|
30
|
-
output_script: PublicKeyAddress.parse("18oxCAnbuKHDjP7KzLBDj8mLjggDBjE1Q9").script,
|
31
|
-
hash_type: hashtype)
|
32
|
-
tx.inputs[0].signature_script = Script.new << (key.ecdsa_signature(sighash) + WireFormat.encode_uint8(hashtype)) << key.public_key
|
33
|
-
|
34
|
-
# Get transaction data and broadcast it
|
35
|
-
puts "Binary transaction:"
|
36
|
-
puts tx.data # => raw binary data
|
37
|
-
puts "Hex transaction:"
|
38
|
-
puts tx.to_hex # hex-encoded data
|
39
|
-
# => 0100000001313eb630b128102b60241ca895f1d0ffca2170d5a0990e094f2182c102ab94aa
|
40
|
-
# 000000006a473044022039148258144202301221a305adb38ce0a182ecb4055c6015cdd735
|
41
|
-
# 8372d7ad6d022008aa259c87177f0e4e887dd0947c57fd140eb8f8a826f14ef8389dbc26ef
|
42
|
-
# a7b20121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59f
|
43
|
-
# ffffffff01a0860100000000001976a9147ab89f9fae3f8043dcee5f7b5467a0f0a6e2f7e1
|
44
|
-
# 88ac00000000
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# Generating an address
|
2
|
-
# ---------------------
|
3
|
-
#
|
4
|
-
# This example demonstrates how to generate a key and get its address.
|
5
|
-
|
6
|
-
require_relative "../lib/btcruby.rb"
|
7
|
-
|
8
|
-
key = BTC::Key.random
|
9
|
-
|
10
|
-
puts key.to_wif # private key in WIF format
|
11
|
-
# => L4RqZhbn2VsVgy2wCWW8kUPpA4xEkH7WbfPtj1MdFug5MayHzLeT
|
12
|
-
|
13
|
-
puts key.address.to_s # public address
|
14
|
-
# => 1MFqAcAxNsAKj5e6yksZCCyfNukSdDGsEY
|
15
|
-
|
16
|
-
puts key.to_wif(network: BTC::Network.testnet)
|
17
|
-
# => cUnq2cbdTZZkrQWCavKG7ntsnJFeQjDCfhYMqRp8m2L5cL1yHDmc
|
18
|
-
|
19
|
-
puts key.address(network: BTC::Network.testnet).to_s
|
20
|
-
# => n1mnTfFwBtbaWC7ihKqw28BzEuM9YqxRyw
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# Using transaction builder
|
2
|
-
# -------------------------
|
3
|
-
#
|
4
|
-
# Transaction builder helps composing arbitrary transactions using just keys or unspent outputs.
|
5
|
-
# It takes care of computing a proper change amount, adding fees and signing inputs.
|
6
|
-
# It is also highly customizable, so you may use it for very complex transactions.
|
7
|
-
|
8
|
-
require_relative "../lib/btcruby.rb"
|
9
|
-
|
10
|
-
builder = BTC::TransactionBuilder.new
|
11
|
-
|
12
|
-
# 1. Provide a list of address to get unspent outputs from.
|
13
|
-
# If address is a WIF instance, it will be used to sign corresponding input
|
14
|
-
# If address is a public address (or P2SH), its input will remain unsigned.
|
15
|
-
builder.input_addresses = [ BTC::Key.new(wif: "L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy").to_wif_object ]
|
16
|
-
|
17
|
-
# 2. Use external API (e.g. Chain.com) to fetch unspent outputs for the input addresses.
|
18
|
-
# In this example we simply hard-code a single unspent output.
|
19
|
-
# Note: transaction ID and output index must be provided.
|
20
|
-
builder.unspent_outputs_provider_block = lambda do |addresses, outputs_amount, outputs_size, fee|
|
21
|
-
txout = BTC::TransactionOutput.new(
|
22
|
-
value: 50_000,
|
23
|
-
script: BTC::PublicKeyAddress.parse("17XBj6iFEsf8kzDMGQk5ghZipxX49VXuaV").script,
|
24
|
-
transaction_id: "115e8f72f39fad874cfab0deed11a80f24f967a84079fb56ddf53ea02e308986",
|
25
|
-
index: 0
|
26
|
-
)
|
27
|
-
[ txout ]
|
28
|
-
end
|
29
|
-
|
30
|
-
# 3. Specify payment address and amount
|
31
|
-
builder.outputs = [ BTC::TransactionOutput.new(
|
32
|
-
value: 10_000,
|
33
|
-
script: BTC::PublicKeyAddress.parse("17XBj6iFEsf8kzDMGQk5ghZipxX49VXuaV").script) ]
|
34
|
-
|
35
|
-
# 4. Specify the change address
|
36
|
-
builder.change_address = BTC::PublicKeyAddress.parse("1CBtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAcG")
|
37
|
-
|
38
|
-
# 5. Build the transaction and broadcast it.
|
39
|
-
result = builder.build
|
40
|
-
tx = result.transaction
|
41
|
-
puts tx.to_hex
|
42
|
-
|
43
|
-
# => 01000000018689302ea03ef5dd56fb7940a867f9240fa811eddeb0fa4c87ad9ff3728f5e11
|
44
|
-
# 000000006b483045022100e280f71106a84a4a1b1a2035eae70266eb53630beab2b59cc8cf
|
45
|
-
# f40b1a5bdbb902201dcbae9bb12730fe5563dc37e3a33e064f2efa78ba0af5c0179187aece
|
46
|
-
# 180b6c0121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b5
|
47
|
-
# 9fffffffff0210270000000000001976a91447862fe165e6121af80d5dde1ecb478ed17056
|
48
|
-
# 5b88ac30750000000000001976a9147ab89f9fae3f8043dcee5f7b5467a0f0a6e2f7e188ac
|
49
|
-
# 00000000
|