@smartledger/bsv 7.12.0 → 8.0.0

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +38 -38
  3. package/bsv-didweb.min.js +6 -6
  4. package/bsv-gdaf.min.js +66 -66
  5. package/bsv-ltp.min.js +46 -46
  6. package/bsv-mnemonic.min.js +8 -8
  7. package/bsv-smartcontract.min.js +1 -1
  8. package/bsv.bundle.js +66 -66
  9. package/bsv.min.js +66 -66
  10. package/docs/AUDIT_SCOPE.md +29 -21
  11. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  12. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  13. package/docs/getting-started/INSTALLATION.md +23 -23
  14. package/docs/getting-started/QUICK_START.md +7 -7
  15. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  16. package/index.js +10 -2
  17. package/lib/crypto/bn.js +22 -2
  18. package/lib/crypto/hash.browser.js +13 -5
  19. package/lib/crypto/hash.js +58 -2
  20. package/lib/crypto/random.js +72 -15
  21. package/lib/didweb/index.js +88 -9
  22. package/lib/encoding/base58.js +67 -3
  23. package/lib/mnemonic/mnemonic.js +19 -5
  24. package/lib/mnemonic/pbkdf2.js +35 -2
  25. package/lib/script/interpreter.js +420 -58
  26. package/lib/transaction/input/multisig.js +1 -1
  27. package/lib/transaction/input/multisigscripthash.js +1 -1
  28. package/lib/transaction/input/publickey.js +1 -1
  29. package/lib/transaction/input/publickeyhash.js +1 -1
  30. package/lib/transaction/sighash.js +18 -6
  31. package/lib/transaction/signature.js +1 -1
  32. package/lib/util/inherits.js +37 -0
  33. package/package.json +7 -8
  34. package/test/consensus/base58-vectors.js +120 -0
  35. package/test/consensus/sv-script-vectors.js +81 -0
  36. package/test/consensus/sv-sighash-vectors.js +51 -0
  37. package/test/consensus/sv-tx-vectors.js +48 -0
  38. package/test/crypto/backend_selection.js +126 -0
  39. package/test/crypto/random.js +73 -0
  40. package/test/data/bitcoin-sv/README.md +170 -0
  41. package/test/data/bitcoin-sv/base58_encode_decode.json +14 -0
  42. package/test/data/bitcoin-sv/base58_keys_invalid.json +152 -0
  43. package/test/data/bitcoin-sv/base58_keys_valid.json +452 -0
  44. package/test/data/bitcoin-sv/script_tests.json +2591 -0
  45. package/test/data/bitcoin-sv/sighash.json +1003 -0
  46. package/test/data/bitcoin-sv/tx_invalid.json +285 -0
  47. package/test/data/bitcoin-sv/tx_valid.json +367 -0
  48. package/test/didweb/relationships.js +144 -0
  49. package/test/regressions.js +35 -0
  50. package/test/script/chronicle.js +170 -25
  51. package/test/script/defaults.js +93 -0
  52. package/test/script/genesis_limits.js +62 -6
  53. package/test/script/interpreter.js +24 -8
  54. package/test/transaction/sighash.js +21 -1
  55. package/test/transaction/unspentoutput.js +6 -1
  56. package/version.js +1 -1
@@ -28,5 +28,78 @@ describe('Random', function () {
28
28
  }
29
29
  }
30
30
  })
31
+
32
+ // WebCrypto refuses more than 65,536 bytes per call. Before chunking, a request
33
+ // above that limit threw; a naive implementation that ignored the return size
34
+ // instead would hand back a zero-filled tail, which is far worse than throwing.
35
+ it('fills requests larger than the 65536-byte getRandomValues limit', function () {
36
+ var buf = Random.getRandomBuffer(70000)
37
+ buf.length.should.equal(70000)
38
+ // The tail comes from a second call — assert it is real entropy, not zero padding.
39
+ var tail = buf.subarray(65536)
40
+ tail.some(function (b) { return b !== 0 }).should.equal(true)
41
+ buf.subarray(0, 32).toString('hex').should.not.equal(tail.subarray(0, 32).toString('hex'))
42
+ })
43
+
44
+ it('handles the exact limit and one past it', function () {
45
+ Random.getRandomBuffer(65536).length.should.equal(65536)
46
+ Random.getRandomBuffer(65537).length.should.equal(65537)
47
+ })
48
+
49
+ // The backend is chosen by feature detection. This used to branch on
50
+ // `process.browser`, which is undefined in React Native, Deno, Workers and Bun —
51
+ // all of which then fell through to require('crypto').randomBytes. Where a partial
52
+ // crypto shim supplies a weak randomBytes, that produced guessable keys silently.
53
+ it('does not depend on process.browser', function () {
54
+ var saved = process.browser
55
+ try {
56
+ process.browser = undefined
57
+ Random.getRandomBuffer(16).length.should.equal(16)
58
+ process.browser = true
59
+ Random.getRandomBuffer(16).length.should.equal(16)
60
+ } finally {
61
+ process.browser = saved
62
+ }
63
+ })
64
+
65
+ it('prefers globalThis.crypto.getRandomValues when present', function () {
66
+ var calls = 0
67
+ var real = Object.getOwnPropertyDescriptor(globalThis, 'crypto')
68
+ try {
69
+ Object.defineProperty(globalThis, 'crypto', {
70
+ configurable: true,
71
+ value: {
72
+ getRandomValues: function (arr) {
73
+ calls++
74
+ for (var i = 0; i < arr.length; i++) arr[i] = (i * 7 + 3) & 0xff
75
+ return arr
76
+ }
77
+ }
78
+ })
79
+ var buf = Random.getRandomBuffer(4)
80
+ calls.should.equal(1)
81
+ buf.toString('hex').should.equal('030a1118')
82
+ } finally {
83
+ if (real) Object.defineProperty(globalThis, 'crypto', real)
84
+ }
85
+ })
86
+
87
+ // The throw matters as much as the detection: a key library must never return bytes
88
+ // it cannot vouch for. Verified in a child process because it has to remove both
89
+ // backends, which cannot be undone safely in-process.
90
+ it('throws rather than returning bytes when no CSPRNG exists', function () {
91
+ var out = require('child_process').spawnSync(process.execPath, ['-e', [
92
+ 'var Module = require("module"), orig = Module._load',
93
+ 'delete globalThis.crypto',
94
+ 'Module._load = function (r) {',
95
+ ' if (r === "crypto") { var e = new Error("no crypto"); e.code = "MODULE_NOT_FOUND"; throw e }',
96
+ ' return orig.apply(this, arguments)',
97
+ '}',
98
+ 'var R = require(' + JSON.stringify(require.resolve('../../lib/crypto/random.js')) + ')',
99
+ 'try { R.getRandomBuffer(32); console.log("RETURNED") }',
100
+ 'catch (e) { console.log("THREW") }'
101
+ ].join('\n')], { encoding: 'utf8' })
102
+ out.stdout.trim().should.equal('THREW')
103
+ })
31
104
  })
32
105
  })
@@ -0,0 +1,170 @@
1
+ # SV Node consensus vectors
2
+
3
+ Consensus test vectors copied verbatim from the reference node implementation.
4
+ These are the specification this library is measured against — do not hand-edit
5
+ them. To update, re-copy from a node tag and record the new provenance here.
6
+
7
+ | field | value |
8
+ | --- | --- |
9
+ | source | [`bitcoin-sv/bitcoin-sv`](https://github.com/bitcoin-sv/bitcoin-sv) `src/test/data` |
10
+ | tag | `v1.2.0` (Chronicle); byte-identical in `v1.2.2`, the current release |
11
+ | commit | `60dc6a3f2547eeaaa3a605e5a69a9fc8686b0a25` |
12
+ | retrieved | 2026-08-11 |
13
+ | licence | MIT (same as this library) |
14
+
15
+ Genesis activated at block **620,538** on **2020-02-04**; Chronicle at block
16
+ **943,816** on **2026-04-07**.
17
+
18
+ ## Files
19
+
20
+ | file | rows run | covers | gate |
21
+ | --- | --- | --- | --- |
22
+ | `script_tests.json` | 1483 | script evaluation, including Genesis and Chronicle rules | `test/consensus/sv-script-vectors.js` |
23
+ | `sighash.json` | 1000 | transaction digest algorithm | `test/consensus/sv-sighash-vectors.js` |
24
+ | `tx_valid.json` | 93 | transactions that must validate | `test/consensus/sv-tx-vectors.js` |
25
+ | `tx_invalid.json` | 68 | transactions that must be rejected | `test/consensus/sv-tx-vectors.js` |
26
+ | `base58_keys_valid.json` | 50 | address and WIF encoding | `test/consensus/base58-vectors.js` |
27
+ | `base58_keys_invalid.json` | 50 | malformed address rejection | `test/consensus/base58-vectors.js` |
28
+ | `base58_encode_decode.json` | 12 | raw base58 round-trips | `test/consensus/base58-vectors.js` |
29
+
30
+ Every one of these is exercised, and every one passes completely. There is no
31
+ known-failure list and nothing is exempted, so any list added later should read
32
+ as a decision someone made rather than as inherited debt.
33
+
34
+ These supersede the older pre-Genesis vectors in `test/data/bitcoind`, which are
35
+ inherited from the upstream fork and encode consensus rules the network
36
+ abandoned in 2020. Those are retained for now so the two can be diffed, but
37
+ they are **not** a valid consensus reference. Where they disagree with these,
38
+ these win.
39
+
40
+ ## Measuring the gap
41
+
42
+ npm run vectors:sv # script vectors
43
+ npm run vectors:sv-tx # transaction vectors
44
+ npm run vectors:sv-sighash # transaction digest vectors
45
+
46
+ Each takes `-- --verbose` for the full failing list. Every report shares its
47
+ harness with the corresponding gate under `test/consensus`, so the progress
48
+ figure and the regression gate cannot disagree about what passes.
49
+
50
+ The script and transaction reports separate the two directions of failure. A
51
+ **false accept** — accepting a script the node rejects — is the direction that
52
+ can cost money, and is held at zero outright. A false reject only costs a
53
+ transaction. The digest report makes no such distinction: a wrong digest is
54
+ equally bad either way, since it both makes valid signatures unverifiable and
55
+ signs something other than what the caller was shown.
56
+
57
+ ## Row layout, and two columns that are easy to get wrong
58
+
59
+ Defined by `script_json_test` in the node's `src/test/script_tests.cpp`:
60
+
61
+ [ [nValue]?, txnVersion, scriptSig, scriptPubKey, flags, expected, comment? ]
62
+
63
+ - **`nValue`** is present only when a row needs an input amount, and it is
64
+ wrapped in an **array**. It states whole coins; the transaction carries
65
+ satoshis, so multiply by 1e8 (the node's `AmountFromValue`).
66
+ - **`txnVersion`** is the *spending* transaction's version, and is present on
67
+ every row. Chronicle gates its malleability relaxations on version > 1, so
68
+ this column is consensus-relevant — it is not padding, and it is not an
69
+ amount. Mistaking it for one changes the crediting transaction's value, which
70
+ changes its txid, which changes the sighash, which silently breaks every
71
+ signature-checking vector in the corpus.
72
+
73
+ The crediting transaction is always version 1; only the spending transaction
74
+ carries the version under test. Both use locktime 0 and a final sequence, and
75
+ the crediting input's scriptSig is `OP_0 OP_0`.
76
+
77
+ ## Flags, and one place this fork differs
78
+
79
+ Flags are mapped by **name**, never by value. This library assigns
80
+ `MONOLITH_OPCODES` and `MAGNETIC_OPCODES` to bits `1<<18` and `1<<19`, which
81
+ are the bits the node uses for `SCRIPT_GENESIS` and `SCRIPT_UTXO_AFTER_GENESIS`
82
+ — mapping by value would quietly run vectors under the wrong rules while
83
+ appearing to pass.
84
+
85
+ The corpus never names `MONOLITH` or `MAGNETIC`, because the node has no such
86
+ flags: those opcodes were restored on BSV in 2018 and are simply enabled. This
87
+ library still gates them, so the harness enables them for every row; otherwise
88
+ the report would be dominated by that one difference rather than by consensus.
89
+ The gating is itself a divergence from BSV and is worth removing. It is
90
+ compensated for here rather than hidden, so that the figures mean what they
91
+ say.
92
+
93
+ ## Transaction vectors
94
+
95
+ `tx_valid.json` and `tx_invalid.json` go a level above the script corpus: a
96
+ whole transaction is deserialised, each input resolved against the output it
97
+ claims to spend, and every one required to verify — with locktimes, sequence
98
+ numbers and multiple inputs in play.
99
+
100
+ That level is worth having. It found a Genesis rule the script corpus cannot
101
+ reach: `OP_CHECKLOCKTIMEVERIFY` and `OP_CHECKSEQUENCEVERIFY` revert to
102
+ upgradable NOPs after Genesis, and without that, four transactions the network
103
+ accepts were being rejected. The behaviour only appears once a real nLockTime
104
+ and sequence exist, so no single-script vector exercises it.
105
+
106
+ ## Digest vectors
107
+
108
+ Each row of `sighash.json` carries **two** expected digests for the same inputs
109
+ — one with forkid enabled and one without — which pins the routing in
110
+ `SignatureHash()` rather than one branch of it.
111
+
112
+ That second column earned its keep. It found 260 rows where this library
113
+ honoured `SIGHASH_CHRONICLE` only when `SCRIPT_ENABLE_CHRONICLE` was also set,
114
+ where the node routes on the bit alone and instead rejects a signature carrying
115
+ that bit outside Chronicle in `CheckSignatureEncoding`, as
116
+ `SCRIPT_ERR_ILLEGAL_CHRONICLE`. Rejected, not reinterpreted.
117
+
118
+ For a row whose hash type sets `0x20`, both columns are identical — the
119
+ original algorithm is taken either way. 511 of the 1000 rows are of that kind,
120
+ so a gate checking only one column would be blind to half the corpus.
121
+
122
+ ## Base58
123
+
124
+ The key vectors are content-identical to the bitcoind copies already used by
125
+ `test/address.js` and `test/privatekey.js` — same 50 rows, different whitespace
126
+ — but `base58_encode_decode.json` has no counterpart there, and nothing else
127
+ pins the raw codec against the node in both directions.
128
+
129
+ Note what the invalid-key vectors actually claim: that a string is neither a
130
+ valid address nor a valid WIF. Several carry a perfectly good checksum and are
131
+ simply the wrong length or version, so `Base58Check` accepts them and the layer
132
+ above is what refuses. A test asserting the checksum layer rejects them would
133
+ be asserting something the corpus does not say.
134
+
135
+ ## Result codes
136
+
137
+ Matching the node's accept/reject outcome is not the same as failing for the
138
+ node's *reason*, and the gap between the two is where bugs live. Comparing the
139
+ result code of all 600 rejected vectors found four, each of which left the
140
+ script failing — so the outcome check stayed green through every one:
141
+
142
+ - a div-by-zero guard comparing a `BN` against the number `0`, so it never
143
+ fired and bn.js asserted instead
144
+ - script number decoding throwing past the evaluator into a generic catch,
145
+ which is what 78 of the four hundred were
146
+ - a truncated `PUSHDATA` doing the same
147
+ - `OP_NUM2BIN` checking only the upper bound of its size argument, so a
148
+ negative size reported the wrong failure
149
+
150
+ All 600 now match: 491 exactly, and 109 through `ERROR_CODE_ALIASES` in
151
+ `tools/sv-vector-harness.js` — names this library reports more narrowly than
152
+ the node, such as `EVAL_FALSE_IN_STACK` for `EVAL_FALSE`. That table is a short
153
+ statement of intent rather than a list of exempted vectors, and it ratchets
154
+ both ways: an unlisted mismatch fails, and so does an alias no vector produces
155
+ any more, so an exemption cannot outlive its reason. Anything added to it
156
+ should be a name that says *more* than the node's, never a different failure
157
+ wearing its label.
158
+
159
+ ## What the vectors cannot reach
160
+
161
+ Passing this corpus completely is not the same as matching the node. Reading
162
+ the code alongside it found `OP_CAT` capping its result at the static 520-byte
163
+ element size rather than the era-derived one, so after Genesis it rejected
164
+ concatenations the network accepts — built from two 300-byte halves that are
165
+ each legal on their own. It is the one opcode that can grow an element past the
166
+ cap without ever pushing an oversized element, which is why no vector here
167
+ covers it. `test/script/genesis_limits.js` holds it instead.
168
+
169
+ Where a rule has no vector, the test that holds it belongs somewhere that says
170
+ so.
@@ -0,0 +1,14 @@
1
+ [
2
+ ["", ""],
3
+ ["61", "2g"],
4
+ ["626262", "a3gV"],
5
+ ["636363", "aPEr"],
6
+ ["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"],
7
+ ["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"],
8
+ ["516b6fcd0f", "ABnLTmg"],
9
+ ["bf4f89001e670274dd", "3SEo3LWLoPntC"],
10
+ ["572e4794", "3EFU7m"],
11
+ ["ecac89cad93923c02321", "EJDM8drfXA6uyA"],
12
+ ["10c8511e", "Rt5zm"],
13
+ ["00000000000000000000", "1111111111"]
14
+ ]
@@ -0,0 +1,152 @@
1
+ [
2
+ [
3
+ ""
4
+ ],
5
+ [
6
+ "x"
7
+ ],
8
+ [
9
+ "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y"
10
+ ],
11
+ [
12
+ "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv"
13
+ ],
14
+ [
15
+ "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S"
16
+ ],
17
+ [
18
+ "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf"
19
+ ],
20
+ [
21
+ "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq"
22
+ ],
23
+ [
24
+ "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb"
25
+ ],
26
+ [
27
+ "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs"
28
+ ],
29
+ [
30
+ "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3"
31
+ ],
32
+ [
33
+ "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th"
34
+ ],
35
+ [
36
+ "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va"
37
+ ],
38
+ [
39
+ "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk"
40
+ ],
41
+ [
42
+ "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs"
43
+ ],
44
+ [
45
+ "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo"
46
+ ],
47
+ [
48
+ "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso"
49
+ ],
50
+ [
51
+ "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq"
52
+ ],
53
+ [
54
+ "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN"
55
+ ],
56
+ [
57
+ "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i"
58
+ ],
59
+ [
60
+ "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos"
61
+ ],
62
+ [
63
+ "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu"
64
+ ],
65
+ [
66
+ "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb"
67
+ ],
68
+ [
69
+ "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ"
70
+ ],
71
+ [
72
+ "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ"
73
+ ],
74
+ [
75
+ "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu"
76
+ ],
77
+ [
78
+ "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU"
79
+ ],
80
+ [
81
+ "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs"
82
+ ],
83
+ [
84
+ "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn"
85
+ ],
86
+ [
87
+ "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj"
88
+ ],
89
+ [
90
+ "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny"
91
+ ],
92
+ [
93
+ "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc"
94
+ ],
95
+ [
96
+ "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ"
97
+ ],
98
+ [
99
+ "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP"
100
+ ],
101
+ [
102
+ "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw"
103
+ ],
104
+ [
105
+ "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX"
106
+ ],
107
+ [
108
+ "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB"
109
+ ],
110
+ [
111
+ "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ"
112
+ ],
113
+ [
114
+ "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs"
115
+ ],
116
+ [
117
+ "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ"
118
+ ],
119
+ [
120
+ "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4"
121
+ ],
122
+ [
123
+ "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK"
124
+ ],
125
+ [
126
+ "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig"
127
+ ],
128
+ [
129
+ "EsYbG4tWWWY45G31nox838qNdzksbPySWc"
130
+ ],
131
+ [
132
+ "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT"
133
+ ],
134
+ [
135
+ "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx"
136
+ ],
137
+ [
138
+ "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde"
139
+ ],
140
+ [
141
+ "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU"
142
+ ],
143
+ [
144
+ "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf"
145
+ ],
146
+ [
147
+ "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd"
148
+ ],
149
+ [
150
+ "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED"
151
+ ]
152
+ ]