From 643aa1726741fb113874b9152814ade10449e7c2 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 16:17:25 +0000 Subject: [PATCH 1/4] Let a consumer run the bindings over its own build of the concrete `test-harness` feature: the TestDecimalFloat harness (packLossless / unpack) and the log tables LibLogTable ships, read through the harness instead of copied, plus an artifact override. `RAIN_MATH_FLOAT_ARTIFACT` / `RAIN_MATH_FLOAT_TEST_ARTIFACT` name forge artifacts of another build of the same ABI, and `RAIN_MATH_FLOAT_DEPLOY_MODE=create` runs their creation code so a constructor executes. The default build reads no environment. The mirrored-table tests go with the tables: they belong to the library, bound to its source through the harness, not copied into Rust. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- crates/float/Cargo.toml | 7 + crates/float/abi/TestDecimalFloat.json | 82 ++- crates/float/src/evm.rs | 124 ++++- crates/float/src/lib.rs | 21 +- crates/float/src/tables.rs | 663 ++----------------------- test/concrete/TestDecimalFloat.sol | 38 +- 6 files changed, 263 insertions(+), 672 deletions(-) diff --git a/crates/float/Cargo.toml b/crates/float/Cargo.toml index 849020e..b943dfb 100644 --- a/crates/float/Cargo.toml +++ b/crates/float/Cargo.toml @@ -7,6 +7,12 @@ description = "Decimal floating-point arithmetic for Rainlang / DeFi smart contr homepage = "https://github.com/rainlanguage/rain.math.float.deploy" repository = "https://github.com/rainlanguage/rain.math.float.deploy" +[features] +# Exposes the TestDecimalFloat harness (packLossless / unpack / the log tables) +# and the artifact override in `evm.rs` outside `cfg(test)`, for a consumer +# running these bindings' tests over its own build of the concrete. +test-harness = ["dep:serde_json"] + [lib] crate-type = ["rlib"] @@ -17,6 +23,7 @@ alloy = { version = "1.0.9", default-features = false, features = [ "json-abi", ] } thiserror = "2.0.12" +serde_json = { version = "1.0.140", optional = true } serde = "1.0.219" # wasm-bindgen must be a direct dependency: the #[wasm_bindgen] macro emits # `::wasm_bindgen` paths, and without a direct dep on the crate they fail to diff --git a/crates/float/abi/TestDecimalFloat.json b/crates/float/abi/TestDecimalFloat.json index 115936d..999e7ea 100644 --- a/crates/float/abi/TestDecimalFloat.json +++ b/crates/float/abi/TestDecimalFloat.json @@ -1,5 +1,83 @@ { "abi": [ + { + "type": "function", + "name": "altTableFlag", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint16", + "internalType": "uint16" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "antiLogTableDec", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint16[10][100]", + "internalType": "uint16[10][100]" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "antiLogTableDecSmall", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8[10][100]", + "internalType": "uint8[10][100]" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "logTableDec", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint16[10][90]", + "internalType": "uint16[10][90]" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "logTableDecSmall", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8[10][90]", + "internalType": "uint8[10][90]" + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "logTableDecSmallAlt", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint8[10][10]", + "internalType": "uint8[10][10]" + } + ], + "stateMutability": "pure" + }, { "type": "function", "name": "packLossless", @@ -82,9 +160,9 @@ } ], "bytecode": { - "object": "0x6080604052348015600e575f80fd5b506102848061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806371516dd914610038578063b702fecd1461008c575b5f80fd5b61007261004636600461022b565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116601b0b9160e09190911d90565b604080519283526020830191909152015b60405180910390f35b61009f61009a366004610242565b6100ad565b604051908152602001610083565b5f6100be83601b0b8360030b6100c5565b9392505050565b5f805f6100d28585610124565b915091508061011c576040517f22c9f7bb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044015b60405180910390fd5b509392505050565b5f601b83900b8314838382610188577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561016857620186a0860595506005850194505b8586601b0b1461018357600a86059550846001019450610168565b61019e565b855f0361019e57505f9250600191506102249050565b848560030b146101fa575f8512156101be57505f92508291506102249050565b6040517fd556b1110000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610113565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791505b9250929050565b5f6020828403121561023b575f80fd5b5035919050565b5f8060408385031215610253575f80fd5b823580601b0b8114610263575f80fd5b91506020830135600381900b8114610279575f80fd5b80915050925092905056" + "object": "0x6080604052348015600e575f80fd5b50619cdb8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610085575f3560e01c8063b702fecd11610058578063b702fecd14610120578063de78cdfa14610141578063e29cdbe714610151578063fe6597fa14610166575f80fd5b806337a649bd1461008957806370d143cb146100a757806371516dd9146100bc5780639e9333f31461010b575b5f80fd5b61009161017b565b60405161009e9190619b6b565b60405180910390f35b6100af610190565b60405161009e9190619bca565b6100f66100ca366004619bf8565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116601b0b9160e09190911d90565b6040805192835260208301919091520161009e565b6101136101a0565b60405161009e9190619c0f565b61013361012e366004619c3d565b6101b0565b60405190815260200161009e565b604051618000815260200161009e565b6101596101c8565b60405161009e9190619c7f565b61016e6101d8565b60405161009e9190619cad565b610183619a2f565b61018b6101e8565b905090565b610198619a5d565b61018b610673565b6101a8619a8b565b61018b6123be565b5f6101c183601b0b8360030b61444f565b9392505050565b6101d0619ab9565b61018b6144ae565b6101e0619ae7565b61018b61710a565b6101f0619a2f565b6040518061014001604052806040518061014001604052805f60ff168152602001600460ff168152602001600860ff168152602001600c60ff168152602001601060ff168152602001601460ff168152602001601860ff168152602001601c60ff168152602001602060ff168152602001602560ff1681525081526020016040518061014001604052805f60ff168152602001600460ff168152602001600760ff168152602001600b60ff168152602001600f60ff168152602001601360ff168152602001601660ff168152602001601a60ff168152602001601e60ff168152602001602160ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600a60ff168152602001600e60ff168152602001601160ff168152602001601460ff168152602001601860ff168152602001601b60ff168152602001601f60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600a60ff168152602001600c60ff168152602001601060ff168152602001601360ff168152602001601660ff168152602001601960ff168152602001601d60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600660ff168152602001600960ff168152602001600c60ff168152602001600f60ff168152602001601160ff168152602001601460ff168152602001601760ff168152602001601a60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600b60ff168152602001600e60ff168152602001601060ff168152602001601360ff168152602001601660ff168152602001601960ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600a60ff168152602001600d60ff168152602001600f60ff168152602001601260ff168152602001601560ff168152602001601760ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600560ff168152602001600760ff168152602001600a60ff168152602001600c60ff168152602001600f60ff168152602001601160ff168152602001601360ff168152602001601660ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600e60ff168152602001601060ff168152602001601260ff168152602001601560ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601360ff16815250815250905090565b61067b619a5d565b60408051610c80810182525f610b408201908152602b610b608301526056610b808301526080610ba0830181905260aa610bc08401526180d4610be08401526180fd610c00840152618126610c2084015261814e610c40840152618176610c608401529082528251610140808201855261019e82526101c56020808401919091526101ec838701526102136060808501919091526102398486015261825f60a08086019190915261828560c0808701919091526182aa60e0808801919091526182cf610100808901919091526182f3610120808a0191909152868b01989098528a518088018c52610318815261033c81880152610360818d01819052610383828801526103a6828c01526103c9828701526183ec8286015261840e8285015261843082840152618452828b01528b8d01919091528b518089018d526104738152610495818901526104b6818e01526104d7818801526104f7818c015261851781870152618537818601526185578185015261857781840152618596818b0152868c01528b518089018d526105b581526105d4818901526105f3818e015261061181880152618630818c015261864e8187015261866c81860152618689818501526186a7818401526186c4818b01528a8c01528b518089018d526106e181526106fe8189015261071a818e015261073781880152610753818c015261076f8187015261878b818601526187a7818501526187c3818401526187de818b0152858c01528b518089018d526107f981526108148189015261082f818e015261084a81880152610864818c015261887f81870152618899818601526188b3818501526188cd818401526188e7818b0152848c01528b518089018d52610900815261091a81890152610933818e015261094c81880152610965818c015261097e81870152618997818601526189b0818501526189c8818401526189e1818b0152838c01528b518089018d526109f98152610a1181890152610a29818e0152610a4181880152610a58818c0152618a7081870152618a8781860152618a9e81850152618ab681840152618acd818b0152828c01528b518089018d52610ae48152610afa81890152610b11818e0152610b2881880152610b3e818c0152618b5481870152618b6b81860152618b8181850152618b9781840152618bad818b0152898c01528b518089018d52610bc28152610bd881890152610bee818e0152610c0381880152610c18818c0152610c2e81870152610c4381860152610c5881850152610c6d81840152610c81818b0152888c01528b518089018d52610c968152610cab81890152610cbf818e0152610cd481880152610ce8818c0152610cfc81870152610d1181860152610d2581850152610d3981840152610d4c818b01526101608c01528b518089018d52610d608152610d7481890152610d88818e0152610d9b81880152610dae818c0152610dc281870152610dd581860152610de881850152610dfb81840152610e0e818b01526101808c01528b518089018d52610e218152610e3481890152610e47818e0152610e5a81880152610e6c818c0152610e7f81870152610e9181860152610ea381850152610eb681840152610ec8818b01526101a08c01528b518089018d52610eda8152610eec81890152610efe818e0152610f1081880152610f22818c0152610f3481870152610f4581860152610f5781850152610f6981840152610f7a818b01526101c08c01528b518089018d52610f8b8152610f9d81890152610fae818e0152610fbf81880152610fd0818c0152610fe181870152610ff2818601526110038185015261101481840152611025818b01526101e08c01528b518089018d52611036815261104681890152611057818e015261106881880152611078818c015261108881870152611099818601526110a9818501526110b9818401526110ca818b01526102008c01528b518089018d526110da81526110ea818901526110fa818e015261110a8188015261111a818c015261112981870152611139818601526111498185015261115881840152611168818b01526102208c01528b518089018d52611178815261118781890152611196818e01526111a6818801526111b5818c01526111c4818701526111d4818601526111e3818501526111f281840152611201818b01526102408c01528b518089018d52611210815261121f8189015261122e818e015261123d8188015261124b818c015261125a81870152611269818601526112788185015261128681840152611295818b01526102608c01528b518089018d526112a381526112b2818901526112c0818e01526112ce818801526112dd818c01526112eb818701526112f9818601526113078185015261131681840152611324818b01526102808c01528b518089018d5261133281526113408189015261134e818e015261135b81880152611369818c01526113778187015261138581860152611393818501526113a0818401526113ae818b01526102a08c01528b518089018d526113bb81526113c9818901526113d7818e01526113e4818801526113f1818c01526113ff8187015261140c818601526114198185015261142781840152611434818b01526102c08c019081528c51808a018e52611441815261144e818a015261145b818f015261146881890152611475818d01526114828188015261148f8187015261149c818601526114a9818501526114b6818c01526102e08d01528c51808a018e526114c381526114d0818a01526114dc818f01526114e9818901526114f6818d01526115028188015261150f8187015261151b8186015261152881850152611534818c01526103008d01528c51808a018e52611541815261154d818a0152611559818f015261156681890152611572818d015261157e8188015261158a81870152611597818601526115a3818501526115af818c01526103208d01528c51808a018e526115bb81526115c7818a01526115d3818f01526115df818901526115eb818d01526115f7818801526116038187015261160f8186015261161a81850152611626818c01526103408d01528c51808a018e52611632815261163e818a0152611649818f015261165581890152611661818d015261166c81880152611678818701526116838186015261168f8185015261169a818c0152918c01919091528b518089018d526116a681526116b1818901526116bd818e01526116c8818801526116d3818c01526116df818701526116ea818601526116f5818501526117008184015261170b818b01526103808c01528b518089018d5261171781526117228189015261172d818e015261173881880152611743818c015261174e81870152611759818601526117648185015261176f8184015261177a818b01526103a08c01528b518089018d52611785815261178f8189015261179a818e01526117a5818801526117b0818c01526117bb818701526117c5818601526117d0818501526117db818401526117e5818b01526103c08c01528b518089018d526117f081526117fa81890152611805818e01526118108188015261181a818c01526118248187015261182f81860152611839818501526118448184015261184e818b01526103e08c01528b518089018d5261185881529a9b909a929991989697909691949392611863818a015261186d81890152611877818801526118828187015261188c81860152611896818501526118a0818c01526118aa818b01526118b581840152818c0152865180820188526118bf81526118c9818a01526118d3818901526118dd818801526118e7818701526118f1818601526118fb81850152611905818c015261190f818b0152611919818401526101608c015286518082018852611923815261192c818a0152611936818901526119408188015261194a818701526119548186015261195d81850152611967818c0152611971818b015261197a818401526101808c015286518082018852611984815261198e818a0152611997818901526119a1818801526119ab818701526119b4818601526119be818501526119c7818c01526119d1818b01526119da818401526101a08c0152865180820188526119e481526119ed818a01526119f681890152611a0081880152611a0981870152611a1381860152611a1c81850152611a25818c0152611a2e818b0152611a38818401526101c08c015286518082018852611a418152611a4a818a0152611a5381890152611a5d81880152611a6681870152611a6f81860152611a7881850152611a81818c0152611a8a818b0152611a93818401526101e08c015286518082018852611a9c8152611aa5818a0152611aae81890152611ab781880152611ac081870152611ac981860152611ad281850152611adb818c0152611ae4818b0152611aed818401526102008c015286518082018852611af68152611aff818a0152611b0881890152611b1081880152611b1981870152611b2281860152611b2b81850152611b34818c0152611b3c818b0152611b45818401526102208c015286518082018852611b4e8152611b56818a0152611b5f81890152611b6881880152611b7081870152611b7981860152611b8281850152611b8a818c0152611b93818b0152611b9b818401526102408c015286518082018852611ba48152611bac818a0152611bb581890152611bbd81880152611bc681870152611bce81860152611bd681850152611bdf818c0152611be7818b0152611bf0818401526102608c015286518082018852611bf88152611c00818a0152611c0981890152611c1181880152611c1981870152611c2281860152611c2a81850152611c32818c0152611c3a818b0152611c43818401526102808c015286518082018852611c4b8152611c53818a0152611c5b81890152611c6381880152611c6b81870152611c7481860152611c7c81850152611c84818c0152611c8c818b0152611c94818401526102a08c015286518082018852611c9c8152611ca4818a0152611cac81890152611cb481880152611cbc81870152611cc481860152611ccc81850152611cd4818c0152611cdc818b0152611ce4818401526102c08c015286518082018852611cec8152611cf4818a0152611cfb81890152611d0381880152611d0b81870152611d1381860152611d1b81850152611d23818c0152611d2a818b0152611d32818401526102e08c015286519081018752611d3a8152611d4297810197909752611d4995870195909552611d5193860193909352611d5991850191909152611d6090840152611d6890830152611d7093820193909352611d779181019190915261030090920191908101611d7f90528152604080516101408082018352611d878252611d8e602083810191909152611d9683850152611d9e606080850191909152611da5608080860191909152611dad60a080870191909152611db460c080880191909152611dbc60e080890191909152611dc3610100808a0191909152611dcb610120808b0191909152878c019990995289518089018b52611dd28152611dda81890152611de1818c0152611de981880152611df081870152611df881860152611dff81850152611e0681840152611e0e81830152611e15818b01528a8c015289518089018b52611e1d8152611e2481890152611e2b818c0152611e3381880152611e3a81870152611e4181860152611e4881850152611e5081840152611e5781830152611e5e818b0152868c015289518089018b52611e668152611e6d81890152611e74818c0152611e7b81880152611e8281870152611e8a81860152611e9181850152611e9881840152611e9f81830152611ea6818b0152858c015289518089018b52611ead8152611eb481890152611ebc818c0152611ec381880152611eca81870152611ed181860152611ed881850152611edf81840152611ee681830152611eed818b0152848c015289518089018b52611ef48152611efb81890152611f02818c0152611f0981880152611f1081870152611f1781860152611f1e81850152611f2581840152611f2c81830152611f33818b0152838c015289518089018b52611f398152611f4081890152611f47818c0152611f4e81880152611f5581870152611f5c81860152611f6381850152611f6981840152611f7081830152611f77818b0152828c015289518089018b52611f7e8152611f8581890152611f8b818c0152611f9281880152611f9981870152611fa081860152611fa681850152611fad81840152611fb481830152611fba818b0152818c015289518089018b52611fc18152611fc881890152611fce818c0152611fd581880152611fdc81870152611fe281860152611fe981850152611ff081840152611ff681830152611ffd818b0152898c015289518089018b52612003815261200a81890152612011818c01526120178188015261201e818701526120248186015261202b81850152612031818401526120388183015261203e818b0152888c015289518089018b52612045815261204b81890152612052818c01526120588188015261205f818701526120658186015261206b81850152612072818401526120788183015261207f818b01526101608c015289518089018b52612085815261208b81890152612092818c01526120988188015261209f818701526120a5818601526120ab818501526120b2818401526120b8818301526120be818b01526101808c015289518089018b526120c481526120cb818901526120d1818c01526120d7818801526120de818701526120e4818601526120ea818501526120f0818401526120f7818301526120fd818b01526101a08c015289518089018b5261210381526121098189015261210f818c01526121168188015261211c81870152612122818601526121288185015261212e818401526121348183015261213a818b01526101c08c015289518089018b5261214181526121478189015261214d818c0152612153818801526121598187015261215f818601526121658185015261216b8184015261217181830152612177818b01526101e08c015289518089018b5261217d815261218381890152612189818c015261218f818801526121958187015261219b818601526121a1818501526121a7818401526121ad818301526121b3818b01526102008c015289518089018b526121b981526121bf818901526121c5818c01526121cb818801526121d1818701526121d7818601526121dd818501526121e3818401526121e9818301526121ee818b01526102208c015289518089018b526121f481526121fa81890152612200818c01526122068188015261220c81870152612212818601526122178185015261221d8184015261222381830152612229818b01526102408c015289518089018b5261222f81526122348189015261223a818c0152612240818801526122468187015261224b81860152612251818501526122578184015261225d81830152612262818b01526102608c015289518089018b52612268815261226e81890152612274818c01526122798188015261227f818701526122858186015261228a81850152612290818401526122968183015261229b818b01526102808c015289518089018b526122a181526122a7818901526122ac818c01526122b2818801526122b7818701526122bd818601526122c3818501526122c8818401526122ce818301526122d3818b01526102a08c015289518089018b526122d981526122df818901526122e4818c01526122ea818801526122ef818701526122f5818601526122fa81850152612300818401526123058183015261230b818b01526102c08c015289518089018b5261231081526123168189015261231b818c0152612321818801526123268187015261232c81860152612331818501526123378184015261233c81830152612341818b01526102e08c015289518089018b52612347815261234c81890152612352818c01526123578188015261235d81870152612362818601526123679381019390935261236d9183019190915261237290820152612377968101969096526103008801959095528551938401865261237d8452612382848401526123889584019590955261238d9083015261239293820193909352612398918101918252610320909301929161239d91019081526123a26020808301919091526123a86040808401919091526123ad606093840152928452825161014080820185526123b282526123b7828401526123bd828601526123c2828501526123c76080808401919091526123cd60a0808501919091526123d260c0808601919091526123d760e0808701919091526123dc610100808801919091526123e2610120808901919091528b89019790975289518087018b526123e781526123ec818a01526123f1818c01526123f6818b01526123fc81870152612401818601526124068185015261240b8184015261241081830152612416818901528b8b015289518087018b5261241b8152612420818a0152612425818c015261242a818b015261242f818701526124358186015261243a8185015261243f8184015261244481830152612449818901528b8a015289518087018b5261244e8152612453818a0152612458818c015261245d818b0152612463818701526124688186015261246d81850152612472818401526124778183015261247c81890152858c015289518087018b526124818152612486818a015261248b818c0152612490818b01526124958187015261249a8186015261249f818501526124a4818401526124a9818301526124ae81890152848c015289518087018b526124b381526124b8818a01526124bd818c01526124c2818b01526124c7818701526124cc818601526124d1818501526124d6818401526124db818301526124e081890152838c015289518087018b526124e581526124ea818a01526124ef818c01526124f4818b01526124f9818701526124fd81860152612502818501526125078184015261250c8183015261251181890152828c015289518087018b52612516815261251b818a0152612520818c0152612525818b01526125298187015261252e81860152612533818501526125388184015261253d8183015261254281890152818c015289518087018b52612546815261254b818a0152612550818c0152612555818b015261255a8187015261255e81860152612563818501526125688184015261256d8183015261257281890152878c015289518087018b52612576815261257b818a0152612580818c0152612585818b01526125898187015261258e81860152612593818501526125988184015261259c818301526125a181890152868c015289518087018b526125a681526125ab818a01526125af818c01526125b4818b01526125b9818701526125bd818601526125c2818501526125c7818401526125cb818301526125d0818901526101608c015289518087018b526125d581526125d9818a01526125de818c01526125e3818b01526125e7818701526125ec818601526125f1818501526125f5818401526125fa818301526125ff818901526101808c015289518087018b526126038152612608818a015261260d818c0152612611818b01526126168187015261261a8186015261261f81850152612623818401526126288183015261262d818901526101a08c015289518087018b526126318152612636818a015261263a818c015261263f818b0152612643818701526126488186015261264d81850152612651818401526126568183015261265a818901526101c08c015289518087018b5261265f8152612663818a0152612668818c015261266c818b0152612671818701526126758186015261267a8185015261267e8184015261268381830152612687818901526101e08c015289518087018b5261268c8152612690818a0152612695818c0152612699818b015261269e818701526126a2818601526126a6818501526126ab818401526126af818301526126b4818901526102008c015289518087018b526126b881526126bd818a01526126c1818c01526126c6818b01526126ca818701526126ce818601526126d3818501526126d7818401526126dc818301526126e0818901526102208c015289519586018a526126e486526126e9978601979097526126ed988501989098526126f1968401969096526126f6918301919091526126fa908201526126ff93810193909352612703938301939093526127079082015261270c9181019190915261024090910152919050565b6123c6619a8b565b60408051610dc0810182526103e8610c8082019081526103ea610ca08301526103ed610cc08301526103ef610ce08301526103f1610d008301526103f4610d208301526103f6610d408301526103f8610d608301526103fb610d808301526103fd610da08301528152815161014080820184526103ff82526104026020808401919091526104048386015261040660608085019190915261040960808086019190915261040b60a08087019190915261040e60c08088019190915261041060e080890191909152610412610100808a0191909152610415610120808b0191909152878b01999099528a518089018c52610417815261041a8189015261041c818d015261041e818801526104218187015261042381860152610426818501526104288184015261042b8183015261042d818b01528a8c01528a518089018c52610430815261043281890152610434818d0152610437818801526104398187015261043c8186015261043e818501526104418184015261044381830152610446818b0152868b01528a518089018c52610448815261044b8189015261044e818d01526104508188015261045381870152610455818601526104588185015261045a8184015261045d8183015261045f818b0152858b01528a518089018c52610462815261046581890152610467818d015261046a8188015261046c8187015261046f8186015261047281850152610474818401526104778183015261047a818b0152848b01528a518089018c5261047c815261047f81890152610481818d015261048481880152610487818701526104898186015261048c8185015261048f8184015261049181830152610494818b0152838b01528a518089018c52610497815261049a8189015261049c818d015261049f818801526104a2818701526104a5818601526104a7818501526104aa818401526104ad818301526104af818b0152828b01528a518089018c526104b281526104b5818901526104b8818d01526104bb818801526104bd818701526104c0818601526104c3818501526104c6818401526104c9818301526104cb818b0152818b01528a518089018c526104ce81526104d1818901526104d4818d01526104d7818801526104da818701526104dd818601526104df818501526104e2818401526104e5818301526104e8818b0152898b01528a518089018c526104eb81526104ee818901526104f1818d01526104f4818801526104f7818701526104fa818601526104fc818501526104ff8184015261050281830152610505818b0152888b01528a518089018c52610508815261050b8189015261050e818d015261051181880152610514818701526105178186015261051a8185015261051d8184015261052081830152610523818b01526101608b01528a518089018c5261052681526105298189015261052c818d015261052f8188015261053281870152610536818601526105398185015261053c8184015261053f81830152610542818b01526101808b01528a518089018c5261054581526105488189015261054b818d015261054e8188015261055181870152610555818601526105588185015261055b8184015261055e81830152610561818b01526101a08b01528a518089018c5261056481526105688189015261056b818d015261056e8188015261057181870152610574818601526105788185015261057b8184015261057e81830152610581818b01526101c08b01528a518089018c5261058581526105888189015261058b818d015261058e8188015261059281870152610595818601526105988185015261059b8184015261059f818301526105a2818b01526101e08b01528a518089018c526105a581526105a9818901526105ac818d01526105af818801526105b3818701526105b6818601526105ba818501526105bd818401526105c0818301526105c4818b01526102008b01528a518089018c526105c781526105cb818901526105ce818d01526105d1818801526105d5818701526105d8818601526105dc818501526105df818401526105e3818301526105e6818b01526102208b01528a518089018c526105ea81526105ed818901526105f1818d01526105f4818801526105f8818701526105fb818601526105ff818501526106028184015261060681830152610609818b01526102408b01528a518089018c5261060d815261061081890152610614818d01526106188188015261061b8187015261061f81860152610622818501526106268184015261062a8183015261062d818b01526102608b01528a518089018c52610631815261063581890152610638818d015261063c8188015261064081870152610643818601526106478185015261064b8184015261064e81830152610652818b01526102808b01528a518089018c52610656815261065a8189015261065d818d015261066181880152610665818701526106698186015261066c818501526106708184015261067481830152610678818b01526102a08b01528a518089018c5261067c815261067f81890152610683818d01526106878188015261068b8187015261068f81860152610693818501526106978184015261069a8183015261069e818b01526102c08b01528a518089018c526106a281526106a6818901526106aa818d01526106ae818801526106b2818701526106b6818601526106ba818501526106be818401526106c2818301526106c6818b01526102e08b01528a518089018c526106ca81526106ce818901526106d2818d01526106d6818801526106da818701526106de818601526106e2818501526106e6818401526106ea818301526106ee818b01526103008b019081528b51808a018d526106f281526106f6818a01526106fa818e01526106ff81890152610703818801526107078187015261070b8186015261070f8185015261071381840152610718818c01526103208c01528b51808a018d5261071c8152610720818a0152610724818e01526107288189015261072d8188015261073181870152610735818601526107398185015261073e81840152610742818c01526103408c01528b51808a018d52610746815261074a818a015261074f818e0152610753818901526107578188015261075c8187015261076081860152610764818501526107698184015261076d818c01526103608c01528b51808a018d526107718152610776818a015261077a818e015261077f81890152610783818801526107888187015261078c818601526107908185015261079581840152610799818c01526103808c01528b51808a018d5261079e81526107a2818a01526107a7818e01526107ab818901526107b0818801526107b4818701526107b9818601526107be818501526107c2818401526107c7818c01526103a08c01528b51808a018d526107cb81526107d0818a01526107d4818e01526107d9818901526107de818801526107e2818701526107e7818601526107ec818501526107f0818401526107f5818c01526103c08c01528b51808a018d526107fa81526107fe818a0152610803818e01526108088189015261080d81880152610811818701526108168186015261081b8185015261082081840152610824818c01526103e08c01528b519a9b909a9699959890969094939291908086018852610829815261082e818a015261083381890152610838818c015261083d818b0152610841818601526108468185015261084b818401526108508183015261085581880152818c01528651808601885261085a815261085f818a015261086481890152610869818c015261086e818b0152610873818601526108788185015261087d818401526108828183015261088781880152868c01528651808601885261088c8152610891818a01526108968189015261089b818c01526108a0818b01526108a5818601526108aa818501526108af818401526108b4818301526108ba81880152858c0152865180860188526108bf81526108c4818a01526108c9818901526108ce818c01526108d3818b01526108d9818601526108de818501526108e3818401526108e8818301526108ee818801526101608c0152865180860188526108f381526108f8818a01526108fd81890152610903818c0152610908818b015261090d81860152610913818501526109188184015261091d81830152610923818801526101808c015286518086018852610928815261092e818a015261093381890152610938818c015261093e818b0152610943818601526109498185015261094e8184015261095481830152610959818801526101a08c01528651808601885261095f8152610964818a015261096a8189015261096f818c0152610975818b015261097b81860152610980818501526109868184015261098b81830152610991818801526101c08c015286518086018852610997815261099c818a01526109a2818901526109a8818c01526109ad818b01526109b3818601526109b9818501526109bf818401526109c4818301526109ca818801526101e08c0152865180860188526109d081526109d6818a01526109db818901526109e1818c01526109e7818b01526109ed818601526109f3818501526109f9818401526109ff81830152610a04818801526102008c015286518086018852610a0a8152610a10818a0152610a1681890152610a1c818c0152610a22818b0152610a2881860152610a2e81850152610a3481840152610a3a81830152610a40818801526102208c015286518086018852610a468152610a4c818a0152610a5281890152610a59818c0152610a5f818b0152610a6581860152610a6b81850152610a7181840152610a7781830152610a7d818801526102408c015286518086018852610a848152610a8a818a0152610a9081890152610a96818c0152610a9c818b0152610aa381860152610aa981850152610aaf81840152610ab681830152610abc818801526102608c015286518086018852610ac28152610ac9818a0152610acf81890152610ad5818c0152610adc818b0152610ae281860152610ae981850152610aef81840152610af581830152610afc818801526102808c015286518086018852610b028152610b09818a0152610b0f81890152610b16818c0152610b1c818b0152610b2381860152610b2a81850152610b3081840152610b3781830152610b3d818801526102a08c015286518086018852610b448152610b4b818a0152610b5181890152610b58818c0152610b5f818b0152610b6581860152610b6c81850152610b7381840152610b7a81830152610b80818801526102c08c015286518086018852610b878152610b8e818a0152610b9581890152610b9c818c0152610ba3818b0152610ba981860152610bb081850152610bb781840152610bbe81830152610bc5818801526102e08c015286518086018852610bcc8152610bd3818a0152610bda81890152610be19a81019a909a52610be8988a0198909852610bef92890192909252610bf690880152610bfd90870152610c0494860194909452610c0b9085015261030085019390935282519182018352610c128252610c199082015261032090920191908101610c2161ffff168152610c28602080830191909152610c2f604080840191909152610c36606080850191909152610c3d608080860191909152610c4560a080870191909152610c4c60c080880191909152610c5360e09788015296885283516101408082018652610c5a8252610c6282880152610c6982870152610c7082860152610c7882850152610c7f82840152610c86828a0152610c8e82890152610c9561010080840191909152610c9c610120808501919091528b89019390935286518083018852610ca48152610cab818a0152610cb381890152610cba81880152610cc281870152610cc981860152610cd1818c0152610cd9818b0152610ce081830152610ce8818501528b88015286518083018852610cef8152610cf7818a0152610cff81890152610d0681880152610d0e81870152610d1681860152610d1d818c0152610d25818b0152610d2d81830152610d35818501528b87015286518083018852610d3c8152610d44818a0152610d4c81890152610d5481880152610d5c81870152610d6481860152610d6c818c0152610d73818b0152610d7b81830152610d83818501528b86015286518083018852610d8b8152610d93818a0152610d9b81890152610da381880152610dab81870152610db481860152610dbc818c0152610dc4818b0152610dcc81830152610dd4818501528b85015286518083018852610ddc8152610de4818a0152610ded81890152610df581880152610dfd81870152610e0581860152610e0d818c0152610e16818b0152610e1e81830152610e26818501528b8b015286518083018852610e2f8152610e37818a0152610e4081890152610e4881880152610e5081870152610e5981860152610e61818c0152610e6a818b0152610e7281830152610e7b818501528b8a015286518083018852610e838152610e8c818a0152610e9581890152610e9d81880152610ea681870152610eae81860152610eb7818c0152610ec0818b0152610ec881830152610ed181850152818c015286518083018852610eda8152610ee3818a0152610eeb81890152610ef481880152610efd81870152610f0681860152610f0f818c0152610f18818b0152610f2181830152610f2a81850152838c015286518083018852610f328152610f3b818a0152610f4481890152610f4d81880152610f5681870152610f6081860152610f69818c0152610f72818b0152610f7b81830152610f8481850152828c015286518083018852610f8d8152610f96818a0152610f9f81890152610fa981880152610fb281870152610fbb81860152610fc4818c0152610fce818b0152610fd781830152610fe0818501526101608c015286518083018852610fea8152610ff3818a0152610ffd818901526110068188015261100f8187015261101981860152611022818c015261102c818b01526110368183015261103f818501526101808c0152865180830188526110498152611052818a015261105c818901526110668188015261106f8187015261107981860152611083818c015261108c818b0152611096818301526110a0818501526101a08c0152865180830188526110aa81526110b4818a01526110bd818901526110c7818801526110d1818701526110db818601526110e5818c01526110ef818b01526110f981830152611103818501526101c08c01528651808301885261110d8152611117818a01526111218189015261112b81880152611136818701526111408186015261114a818c0152611154818b015261115e81830152611169818501526101e08c015286518083018852611173815261117d818a0152611187818901526111928188015261119c818701526111a7818601526111b1818c01526111bb818b01526111c6818301526111d0818501526102008c0152865180830188526111db81526111e5818a01526111f0818901526111fb81880152611205818701526112108186015261121a818c0152611225818b01526112308183015261123b818501526102208c0152865180830188526112458152611250818a015261125b81890152611266818801526112718187015261127c81860152611286818c0152611291818b015261129c818301526112a7818501526102408c0152865180830188526112b281526112bd818a01526112c8818901526112d3818801526112df818701526112ea818601526112f5818c0152611300818b015261130b81830152611317818501526102608c015286518083018852611322815261132d818a0152611338818901526113448188015261134f8187015261135b81860152611366818c0152611371818b015261137d81830152611388818501526102808c015286518083018852611394815261139f818a01526113ab818901526113b7818801526113c2818701526113ce818601526113da818c01526113e5818b01526113f1818301526113fd818501526102a08c0152865180830188526114098152611414818a01526114208189015261142c818801526114388187015261144481860152611450818c015261145c818b015261146881830152611474818501526102c08c015286518083018852611480815261148c818a0152611498818901526114a4818801526114b1818701526114bd818601526114c9818c01526114d5818b01526114e2818301526114ee818501526102e08c0152865191820187526114fa825261150797820197909752611513958101959095526115209385019390935261152c9184019190915261153990830152611545948201949094526115529281019290925261155e9082015261156b9181019190915261030090910190815260408051610140808201835261157782526115846020838101919091526115918385015261159e6060808501919091526115aa6080808601919091526115b760a0808701919091526115c460c0808801919091526115d160e0808901919091526115de610100808a01919091526115ea610120808b01919091528b88019990995289518089018b526115f7815261160481890152611611818c015261161e8188015261162b818701526116398186015261164681850152611653818401526116608183015261166d818b01528a8c015289518089018b5261167a815261168881890152611695818c01526116a2818801526116b0818701526116bd818601526116ca818501526116d8818401526116e5818301526116f3818b0152868c015289518089018b52611700815261170e8189015261171c818c0152611729818801526117378187015261174581860152611752818501526117608184015261176e8183015261177c818b0152858c015289518089018b5261178a8152611797818901526117a5818c01526117b3818801526117c1818701526117cf818601526117dd818501526117ec818401526117fa81830152611808818b0152848c015289518089018b52611816815261182481890152611832818c01526118418188015261184f8187015261185d8186015261186c8185015261187a8184015261188981830152611897818b0152838c015289518089018b526118a681526118b4818901526118c3818c01526118d1818801526118e0818701526118ef818601526118fd8185015261190c8184015261191b8183015261192a818b0152828c015289518089018b52611939815261194781890152611956818c0152611965818801526119748187015261198381860152611992818501526119a1818401526119b1818301526119c0818b0152818c015289518089018b526119cf81526119de818901526119ed818c01526119fd81880152611a0c81870152611a1b81860152611a2b81850152611a3a81840152611a4a81830152611a59818b0152898c015289518089018b52611a698152611a7881890152611a88818c0152611a9881880152611aa781870152611ab781860152611ac781850152611ad781840152611ae781830152611af6818b0152888c015289518089018b52611b068152611b1681890152611b26818c0152611b3681880152611b4681870152611b5681860152611b6781850152611b7781840152611b8781830152611b97818b01526101608c015289518089018b52611ba78152611bb881890152611bc8818c0152611bd981880152611be981870152611bf981860152611c0a81850152611c1a81840152611c2b81830152611c3c818b01526101808c015289518089018b52611c4c8152611c5d81890152611c6e818c0152611c7f81880152611c8f81870152611ca081860152611cb181850152611cc281840152611cd381830152611ce4818b01526101a08c015289518089018b52611cf58152611d0681890152611d17818c0152611d2881880152611d3a81870152611d4b81860152611d5c81850152611d6e81840152611d7f81830152611d90818b01526101c08c015289518089018b52611da28152611db381890152611dc5818c0152611dd681880152611de881870152611dfa81860152611e0b81850152611e1d81840152611e2f81830152611e41818b01526101e08c015289518089018b52611e528152611e6481890152611e76818c0152611e8881880152611e9a81870152611eac81860152611ebe81850152611ed181840152611ee381830152611ef5818b01526102008c015289518089018b52611f078152611f1a81890152611f2c818c0152611f3e81880152611f5181870152611f6381860152611f7681850152611f8881840152611f9b81830152611fae818b01526102208c015289518089018b52611fc08152611fd381890152611fe6818c0152611ff98188015261200c8187015261201e8186015261203181850152612044818401526120578183015261206b818b01526102408c015289518089018b5261207e8152612091818901526120a4818c01526120b7818801526120cb818701526120de818601526120f181850152612105818401526121188183015261212c818b01526102608c015289518089018b5261213f815261215381890152612167818c015261217a8188015261218e818701526121a2818601526121b6818501526121ca818401526121de818301526121f2818b01526102808c015289518089018b52612206815261221a8189015261222e818c0152612242818801526122568187015261226a8186015261227f81850152612293818401526122a8818301526122bc818b01526102a08c015289518089018b526122d181526122e5818901526122fa818c015261230e81880152612323818701526123388186015261234c81850152612361818401526123768183015261238b818b01526102c08c015289518089018b526123a081526123b5818901526123ca818c01526123df818801526123f48187015261240a8186015261241f818501526124348184015261244a8183015261245f818b01526102e08c015289518089018b52612475815261248a818901526124a0818c01526124b5818801526124cb818701526124e1818601526124f68185015261250c9281019290925261252290820152612538978101979097526103008901969096528651948501875261254e85526125649385019390935261257a95840195909552612590908301526125a6938201939093526125bd928101929092526103209092019181016125d381526125e96020828101919091526125ff60408084019190915261261660609384015292845282516101408101845261262c8152612643818301526126599381019390935261267091830191909152612687608083015261269e60a08301526126b460c08301526126cb60e08301526126e26101008301526126f96101208301529190910152919050565b5f805f61445c8585619928565b91509150806144a6576040517f22c9f7bb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044015b60405180910390fd5b509392505050565b6144b6619ab9565b60405180610c8001604052806040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601260ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601260ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600f60ff168152602001601160ff168152602001601360ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601360ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601460ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff1681526010602082810182905260126040808501829052601460609586018190529587528051610140810182525f815260028185015260059181019190915260079481019490945260096080850152600b60a0850152600e60c085015260e0840192909252610100830191909152610120820192909252910152919050565b617112619ae7565b60405180610b4001604052806040518061014001604052805f60ff168152602001600460ff168152602001600960ff168152602001600d60ff168152602001601160ff168152602001601560ff168152602001601a60ff168152602001601e60ff168152602001602260ff168152602001602660ff1681525081526020016040518061014001604052805f60ff168152602001600460ff168152602001600860ff168152602001600c60ff168152602001600f60ff168152602001601360ff168152602001601760ff168152602001601b60ff168152602001601f60ff168152602001602360ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600b60ff168152602001600e60ff168152602001601260ff168152602001601560ff168152602001601960ff168152602001601c60ff168152602001602060ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600a60ff168152602001600d60ff168152602001601060ff168152602001601460ff168152602001601760ff168152602001601a60ff168152602001601e60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600660ff168152602001600960ff168152602001600c60ff168152602001600f60ff168152602001601260ff168152602001601560ff168152602001601860ff168152602001601c60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600660ff168152602001600960ff168152602001600b60ff168152602001600e60ff168152602001601160ff168152602001601460ff168152602001601760ff168152602001601a60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600b60ff168152602001600e60ff168152602001601060ff168152602001601360ff168152602001601660ff168152602001601860ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600a60ff168152602001600d60ff168152602001600f60ff168152602001601260ff168152602001601460ff168152602001601760ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601360ff168152602001601560ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001601060ff168152602001601260ff168152602001601460ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601360ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601260ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff16815250815250905090565b5f601b83900b831483838261998c577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561996c57620186a0860595506005850194505b8586601b0b1461998757600a8605955084600101945061996c565b6199a2565b855f036199a257505f925060019150619a289050565b848560030b146199fe575f8512156199c257505f9250829150619a289050565b6040517fd556b111000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161449d565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791505b9250929050565b604051806101400160405280600a905b619a47619b15565b815260200190600190039081619a3f5790505090565b60405180610b400160405280605a905b619a75619b15565b815260200190600190039081619a6d5790505090565b60405180610c8001604052806064905b619aa3619b15565b815260200190600190039081619a9b5790505090565b60405180610c8001604052806064905b619ad1619b15565b815260200190600190039081619ac95790505090565b60405180610b400160405280605a905b619aff619b15565b815260200190600190039081619af75790505090565b604051806101400160405280600a906020820280368337509192915050565b5f8282825b600a811015619b5b57815160ff16835260209283019290910190600101619b39565b5050506101408301905092915050565b610c80810181835f5b600a811015619b9957619b88838351619b34565b925060209190910190600101619b74565b50505092915050565b5f8282825b600a811015619b5b57815161ffff16835260209283019290910190600101619ba7565b617080810181835f5b605a811015619b9957619be7838351619ba2565b925060209190910190600101619bd3565b5f60208284031215619c08575f80fd5b5035919050565b617d00810181835f5b6064811015619b9957619c2c838351619ba2565b925060209190910190600101619c18565b5f8060408385031215619c4e575f80fd5b823580601b0b8114619c5e575f80fd5b91506020830135600381900b8114619c74575f80fd5b809150509250929050565b617d00810181835f5b6064811015619b9957619c9c838351619b34565b925060209190910190600101619c88565b617080810181835f5b605a811015619b9957619cca838351619b34565b925060209190910190600101619cb656" }, "deployedBytecode": { - "object": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c806371516dd914610038578063b702fecd1461008c575b5f80fd5b61007261004636600461022b565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116601b0b9160e09190911d90565b604080519283526020830191909152015b60405180910390f35b61009f61009a366004610242565b6100ad565b604051908152602001610083565b5f6100be83601b0b8360030b6100c5565b9392505050565b5f805f6100d28585610124565b915091508061011c576040517f22c9f7bb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044015b60405180910390fd5b509392505050565b5f601b83900b8314838382610188577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561016857620186a0860595506005850194505b8586601b0b1461018357600a86059550846001019450610168565b61019e565b855f0361019e57505f9250600191506102249050565b848560030b146101fa575f8512156101be57505f92508291506102249050565b6040517fd556b1110000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610113565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791505b9250929050565b5f6020828403121561023b575f80fd5b5035919050565b5f8060408385031215610253575f80fd5b823580601b0b8114610263575f80fd5b91506020830135600381900b8114610279575f80fd5b80915050925092905056" + "object": "0x608060405234801561000f575f80fd5b5060043610610085575f3560e01c8063b702fecd11610058578063b702fecd14610120578063de78cdfa14610141578063e29cdbe714610151578063fe6597fa14610166575f80fd5b806337a649bd1461008957806370d143cb146100a757806371516dd9146100bc5780639e9333f31461010b575b5f80fd5b61009161017b565b60405161009e9190619b6b565b60405180910390f35b6100af610190565b60405161009e9190619bca565b6100f66100ca366004619bf8565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116601b0b9160e09190911d90565b6040805192835260208301919091520161009e565b6101136101a0565b60405161009e9190619c0f565b61013361012e366004619c3d565b6101b0565b60405190815260200161009e565b604051618000815260200161009e565b6101596101c8565b60405161009e9190619c7f565b61016e6101d8565b60405161009e9190619cad565b610183619a2f565b61018b6101e8565b905090565b610198619a5d565b61018b610673565b6101a8619a8b565b61018b6123be565b5f6101c183601b0b8360030b61444f565b9392505050565b6101d0619ab9565b61018b6144ae565b6101e0619ae7565b61018b61710a565b6101f0619a2f565b6040518061014001604052806040518061014001604052805f60ff168152602001600460ff168152602001600860ff168152602001600c60ff168152602001601060ff168152602001601460ff168152602001601860ff168152602001601c60ff168152602001602060ff168152602001602560ff1681525081526020016040518061014001604052805f60ff168152602001600460ff168152602001600760ff168152602001600b60ff168152602001600f60ff168152602001601360ff168152602001601660ff168152602001601a60ff168152602001601e60ff168152602001602160ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600a60ff168152602001600e60ff168152602001601160ff168152602001601460ff168152602001601860ff168152602001601b60ff168152602001601f60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600a60ff168152602001600c60ff168152602001601060ff168152602001601360ff168152602001601660ff168152602001601960ff168152602001601d60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600660ff168152602001600960ff168152602001600c60ff168152602001600f60ff168152602001601160ff168152602001601460ff168152602001601760ff168152602001601a60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600b60ff168152602001600e60ff168152602001601060ff168152602001601360ff168152602001601660ff168152602001601960ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600a60ff168152602001600d60ff168152602001600f60ff168152602001601260ff168152602001601560ff168152602001601760ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600560ff168152602001600760ff168152602001600a60ff168152602001600c60ff168152602001600f60ff168152602001601160ff168152602001601360ff168152602001601660ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600e60ff168152602001601060ff168152602001601260ff168152602001601560ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601360ff16815250815250905090565b61067b619a5d565b60408051610c80810182525f610b408201908152602b610b608301526056610b808301526080610ba0830181905260aa610bc08401526180d4610be08401526180fd610c00840152618126610c2084015261814e610c40840152618176610c608401529082528251610140808201855261019e82526101c56020808401919091526101ec838701526102136060808501919091526102398486015261825f60a08086019190915261828560c0808701919091526182aa60e0808801919091526182cf610100808901919091526182f3610120808a0191909152868b01989098528a518088018c52610318815261033c81880152610360818d01819052610383828801526103a6828c01526103c9828701526183ec8286015261840e8285015261843082840152618452828b01528b8d01919091528b518089018d526104738152610495818901526104b6818e01526104d7818801526104f7818c015261851781870152618537818601526185578185015261857781840152618596818b0152868c01528b518089018d526105b581526105d4818901526105f3818e015261061181880152618630818c015261864e8187015261866c81860152618689818501526186a7818401526186c4818b01528a8c01528b518089018d526106e181526106fe8189015261071a818e015261073781880152610753818c015261076f8187015261878b818601526187a7818501526187c3818401526187de818b0152858c01528b518089018d526107f981526108148189015261082f818e015261084a81880152610864818c015261887f81870152618899818601526188b3818501526188cd818401526188e7818b0152848c01528b518089018d52610900815261091a81890152610933818e015261094c81880152610965818c015261097e81870152618997818601526189b0818501526189c8818401526189e1818b0152838c01528b518089018d526109f98152610a1181890152610a29818e0152610a4181880152610a58818c0152618a7081870152618a8781860152618a9e81850152618ab681840152618acd818b0152828c01528b518089018d52610ae48152610afa81890152610b11818e0152610b2881880152610b3e818c0152618b5481870152618b6b81860152618b8181850152618b9781840152618bad818b0152898c01528b518089018d52610bc28152610bd881890152610bee818e0152610c0381880152610c18818c0152610c2e81870152610c4381860152610c5881850152610c6d81840152610c81818b0152888c01528b518089018d52610c968152610cab81890152610cbf818e0152610cd481880152610ce8818c0152610cfc81870152610d1181860152610d2581850152610d3981840152610d4c818b01526101608c01528b518089018d52610d608152610d7481890152610d88818e0152610d9b81880152610dae818c0152610dc281870152610dd581860152610de881850152610dfb81840152610e0e818b01526101808c01528b518089018d52610e218152610e3481890152610e47818e0152610e5a81880152610e6c818c0152610e7f81870152610e9181860152610ea381850152610eb681840152610ec8818b01526101a08c01528b518089018d52610eda8152610eec81890152610efe818e0152610f1081880152610f22818c0152610f3481870152610f4581860152610f5781850152610f6981840152610f7a818b01526101c08c01528b518089018d52610f8b8152610f9d81890152610fae818e0152610fbf81880152610fd0818c0152610fe181870152610ff2818601526110038185015261101481840152611025818b01526101e08c01528b518089018d52611036815261104681890152611057818e015261106881880152611078818c015261108881870152611099818601526110a9818501526110b9818401526110ca818b01526102008c01528b518089018d526110da81526110ea818901526110fa818e015261110a8188015261111a818c015261112981870152611139818601526111498185015261115881840152611168818b01526102208c01528b518089018d52611178815261118781890152611196818e01526111a6818801526111b5818c01526111c4818701526111d4818601526111e3818501526111f281840152611201818b01526102408c01528b518089018d52611210815261121f8189015261122e818e015261123d8188015261124b818c015261125a81870152611269818601526112788185015261128681840152611295818b01526102608c01528b518089018d526112a381526112b2818901526112c0818e01526112ce818801526112dd818c01526112eb818701526112f9818601526113078185015261131681840152611324818b01526102808c01528b518089018d5261133281526113408189015261134e818e015261135b81880152611369818c01526113778187015261138581860152611393818501526113a0818401526113ae818b01526102a08c01528b518089018d526113bb81526113c9818901526113d7818e01526113e4818801526113f1818c01526113ff8187015261140c818601526114198185015261142781840152611434818b01526102c08c019081528c51808a018e52611441815261144e818a015261145b818f015261146881890152611475818d01526114828188015261148f8187015261149c818601526114a9818501526114b6818c01526102e08d01528c51808a018e526114c381526114d0818a01526114dc818f01526114e9818901526114f6818d01526115028188015261150f8187015261151b8186015261152881850152611534818c01526103008d01528c51808a018e52611541815261154d818a0152611559818f015261156681890152611572818d015261157e8188015261158a81870152611597818601526115a3818501526115af818c01526103208d01528c51808a018e526115bb81526115c7818a01526115d3818f01526115df818901526115eb818d01526115f7818801526116038187015261160f8186015261161a81850152611626818c01526103408d01528c51808a018e52611632815261163e818a0152611649818f015261165581890152611661818d015261166c81880152611678818701526116838186015261168f8185015261169a818c0152918c01919091528b518089018d526116a681526116b1818901526116bd818e01526116c8818801526116d3818c01526116df818701526116ea818601526116f5818501526117008184015261170b818b01526103808c01528b518089018d5261171781526117228189015261172d818e015261173881880152611743818c015261174e81870152611759818601526117648185015261176f8184015261177a818b01526103a08c01528b518089018d52611785815261178f8189015261179a818e01526117a5818801526117b0818c01526117bb818701526117c5818601526117d0818501526117db818401526117e5818b01526103c08c01528b518089018d526117f081526117fa81890152611805818e01526118108188015261181a818c01526118248187015261182f81860152611839818501526118448184015261184e818b01526103e08c01528b518089018d5261185881529a9b909a929991989697909691949392611863818a015261186d81890152611877818801526118828187015261188c81860152611896818501526118a0818c01526118aa818b01526118b581840152818c0152865180820188526118bf81526118c9818a01526118d3818901526118dd818801526118e7818701526118f1818601526118fb81850152611905818c015261190f818b0152611919818401526101608c015286518082018852611923815261192c818a0152611936818901526119408188015261194a818701526119548186015261195d81850152611967818c0152611971818b015261197a818401526101808c015286518082018852611984815261198e818a0152611997818901526119a1818801526119ab818701526119b4818601526119be818501526119c7818c01526119d1818b01526119da818401526101a08c0152865180820188526119e481526119ed818a01526119f681890152611a0081880152611a0981870152611a1381860152611a1c81850152611a25818c0152611a2e818b0152611a38818401526101c08c015286518082018852611a418152611a4a818a0152611a5381890152611a5d81880152611a6681870152611a6f81860152611a7881850152611a81818c0152611a8a818b0152611a93818401526101e08c015286518082018852611a9c8152611aa5818a0152611aae81890152611ab781880152611ac081870152611ac981860152611ad281850152611adb818c0152611ae4818b0152611aed818401526102008c015286518082018852611af68152611aff818a0152611b0881890152611b1081880152611b1981870152611b2281860152611b2b81850152611b34818c0152611b3c818b0152611b45818401526102208c015286518082018852611b4e8152611b56818a0152611b5f81890152611b6881880152611b7081870152611b7981860152611b8281850152611b8a818c0152611b93818b0152611b9b818401526102408c015286518082018852611ba48152611bac818a0152611bb581890152611bbd81880152611bc681870152611bce81860152611bd681850152611bdf818c0152611be7818b0152611bf0818401526102608c015286518082018852611bf88152611c00818a0152611c0981890152611c1181880152611c1981870152611c2281860152611c2a81850152611c32818c0152611c3a818b0152611c43818401526102808c015286518082018852611c4b8152611c53818a0152611c5b81890152611c6381880152611c6b81870152611c7481860152611c7c81850152611c84818c0152611c8c818b0152611c94818401526102a08c015286518082018852611c9c8152611ca4818a0152611cac81890152611cb481880152611cbc81870152611cc481860152611ccc81850152611cd4818c0152611cdc818b0152611ce4818401526102c08c015286518082018852611cec8152611cf4818a0152611cfb81890152611d0381880152611d0b81870152611d1381860152611d1b81850152611d23818c0152611d2a818b0152611d32818401526102e08c015286519081018752611d3a8152611d4297810197909752611d4995870195909552611d5193860193909352611d5991850191909152611d6090840152611d6890830152611d7093820193909352611d779181019190915261030090920191908101611d7f90528152604080516101408082018352611d878252611d8e602083810191909152611d9683850152611d9e606080850191909152611da5608080860191909152611dad60a080870191909152611db460c080880191909152611dbc60e080890191909152611dc3610100808a0191909152611dcb610120808b0191909152878c019990995289518089018b52611dd28152611dda81890152611de1818c0152611de981880152611df081870152611df881860152611dff81850152611e0681840152611e0e81830152611e15818b01528a8c015289518089018b52611e1d8152611e2481890152611e2b818c0152611e3381880152611e3a81870152611e4181860152611e4881850152611e5081840152611e5781830152611e5e818b0152868c015289518089018b52611e668152611e6d81890152611e74818c0152611e7b81880152611e8281870152611e8a81860152611e9181850152611e9881840152611e9f81830152611ea6818b0152858c015289518089018b52611ead8152611eb481890152611ebc818c0152611ec381880152611eca81870152611ed181860152611ed881850152611edf81840152611ee681830152611eed818b0152848c015289518089018b52611ef48152611efb81890152611f02818c0152611f0981880152611f1081870152611f1781860152611f1e81850152611f2581840152611f2c81830152611f33818b0152838c015289518089018b52611f398152611f4081890152611f47818c0152611f4e81880152611f5581870152611f5c81860152611f6381850152611f6981840152611f7081830152611f77818b0152828c015289518089018b52611f7e8152611f8581890152611f8b818c0152611f9281880152611f9981870152611fa081860152611fa681850152611fad81840152611fb481830152611fba818b0152818c015289518089018b52611fc18152611fc881890152611fce818c0152611fd581880152611fdc81870152611fe281860152611fe981850152611ff081840152611ff681830152611ffd818b0152898c015289518089018b52612003815261200a81890152612011818c01526120178188015261201e818701526120248186015261202b81850152612031818401526120388183015261203e818b0152888c015289518089018b52612045815261204b81890152612052818c01526120588188015261205f818701526120658186015261206b81850152612072818401526120788183015261207f818b01526101608c015289518089018b52612085815261208b81890152612092818c01526120988188015261209f818701526120a5818601526120ab818501526120b2818401526120b8818301526120be818b01526101808c015289518089018b526120c481526120cb818901526120d1818c01526120d7818801526120de818701526120e4818601526120ea818501526120f0818401526120f7818301526120fd818b01526101a08c015289518089018b5261210381526121098189015261210f818c01526121168188015261211c81870152612122818601526121288185015261212e818401526121348183015261213a818b01526101c08c015289518089018b5261214181526121478189015261214d818c0152612153818801526121598187015261215f818601526121658185015261216b8184015261217181830152612177818b01526101e08c015289518089018b5261217d815261218381890152612189818c015261218f818801526121958187015261219b818601526121a1818501526121a7818401526121ad818301526121b3818b01526102008c015289518089018b526121b981526121bf818901526121c5818c01526121cb818801526121d1818701526121d7818601526121dd818501526121e3818401526121e9818301526121ee818b01526102208c015289518089018b526121f481526121fa81890152612200818c01526122068188015261220c81870152612212818601526122178185015261221d8184015261222381830152612229818b01526102408c015289518089018b5261222f81526122348189015261223a818c0152612240818801526122468187015261224b81860152612251818501526122578184015261225d81830152612262818b01526102608c015289518089018b52612268815261226e81890152612274818c01526122798188015261227f818701526122858186015261228a81850152612290818401526122968183015261229b818b01526102808c015289518089018b526122a181526122a7818901526122ac818c01526122b2818801526122b7818701526122bd818601526122c3818501526122c8818401526122ce818301526122d3818b01526102a08c015289518089018b526122d981526122df818901526122e4818c01526122ea818801526122ef818701526122f5818601526122fa81850152612300818401526123058183015261230b818b01526102c08c015289518089018b5261231081526123168189015261231b818c0152612321818801526123268187015261232c81860152612331818501526123378184015261233c81830152612341818b01526102e08c015289518089018b52612347815261234c81890152612352818c01526123578188015261235d81870152612362818601526123679381019390935261236d9183019190915261237290820152612377968101969096526103008801959095528551938401865261237d8452612382848401526123889584019590955261238d9083015261239293820193909352612398918101918252610320909301929161239d91019081526123a26020808301919091526123a86040808401919091526123ad606093840152928452825161014080820185526123b282526123b7828401526123bd828601526123c2828501526123c76080808401919091526123cd60a0808501919091526123d260c0808601919091526123d760e0808701919091526123dc610100808801919091526123e2610120808901919091528b89019790975289518087018b526123e781526123ec818a01526123f1818c01526123f6818b01526123fc81870152612401818601526124068185015261240b8184015261241081830152612416818901528b8b015289518087018b5261241b8152612420818a0152612425818c015261242a818b015261242f818701526124358186015261243a8185015261243f8184015261244481830152612449818901528b8a015289518087018b5261244e8152612453818a0152612458818c015261245d818b0152612463818701526124688186015261246d81850152612472818401526124778183015261247c81890152858c015289518087018b526124818152612486818a015261248b818c0152612490818b01526124958187015261249a8186015261249f818501526124a4818401526124a9818301526124ae81890152848c015289518087018b526124b381526124b8818a01526124bd818c01526124c2818b01526124c7818701526124cc818601526124d1818501526124d6818401526124db818301526124e081890152838c015289518087018b526124e581526124ea818a01526124ef818c01526124f4818b01526124f9818701526124fd81860152612502818501526125078184015261250c8183015261251181890152828c015289518087018b52612516815261251b818a0152612520818c0152612525818b01526125298187015261252e81860152612533818501526125388184015261253d8183015261254281890152818c015289518087018b52612546815261254b818a0152612550818c0152612555818b015261255a8187015261255e81860152612563818501526125688184015261256d8183015261257281890152878c015289518087018b52612576815261257b818a0152612580818c0152612585818b01526125898187015261258e81860152612593818501526125988184015261259c818301526125a181890152868c015289518087018b526125a681526125ab818a01526125af818c01526125b4818b01526125b9818701526125bd818601526125c2818501526125c7818401526125cb818301526125d0818901526101608c015289518087018b526125d581526125d9818a01526125de818c01526125e3818b01526125e7818701526125ec818601526125f1818501526125f5818401526125fa818301526125ff818901526101808c015289518087018b526126038152612608818a015261260d818c0152612611818b01526126168187015261261a8186015261261f81850152612623818401526126288183015261262d818901526101a08c015289518087018b526126318152612636818a015261263a818c015261263f818b0152612643818701526126488186015261264d81850152612651818401526126568183015261265a818901526101c08c015289518087018b5261265f8152612663818a0152612668818c015261266c818b0152612671818701526126758186015261267a8185015261267e8184015261268381830152612687818901526101e08c015289518087018b5261268c8152612690818a0152612695818c0152612699818b015261269e818701526126a2818601526126a6818501526126ab818401526126af818301526126b4818901526102008c015289518087018b526126b881526126bd818a01526126c1818c01526126c6818b01526126ca818701526126ce818601526126d3818501526126d7818401526126dc818301526126e0818901526102208c015289519586018a526126e486526126e9978601979097526126ed988501989098526126f1968401969096526126f6918301919091526126fa908201526126ff93810193909352612703938301939093526127079082015261270c9181019190915261024090910152919050565b6123c6619a8b565b60408051610dc0810182526103e8610c8082019081526103ea610ca08301526103ed610cc08301526103ef610ce08301526103f1610d008301526103f4610d208301526103f6610d408301526103f8610d608301526103fb610d808301526103fd610da08301528152815161014080820184526103ff82526104026020808401919091526104048386015261040660608085019190915261040960808086019190915261040b60a08087019190915261040e60c08088019190915261041060e080890191909152610412610100808a0191909152610415610120808b0191909152878b01999099528a518089018c52610417815261041a8189015261041c818d015261041e818801526104218187015261042381860152610426818501526104288184015261042b8183015261042d818b01528a8c01528a518089018c52610430815261043281890152610434818d0152610437818801526104398187015261043c8186015261043e818501526104418184015261044381830152610446818b0152868b01528a518089018c52610448815261044b8189015261044e818d01526104508188015261045381870152610455818601526104588185015261045a8184015261045d8183015261045f818b0152858b01528a518089018c52610462815261046581890152610467818d015261046a8188015261046c8187015261046f8186015261047281850152610474818401526104778183015261047a818b0152848b01528a518089018c5261047c815261047f81890152610481818d015261048481880152610487818701526104898186015261048c8185015261048f8184015261049181830152610494818b0152838b01528a518089018c52610497815261049a8189015261049c818d015261049f818801526104a2818701526104a5818601526104a7818501526104aa818401526104ad818301526104af818b0152828b01528a518089018c526104b281526104b5818901526104b8818d01526104bb818801526104bd818701526104c0818601526104c3818501526104c6818401526104c9818301526104cb818b0152818b01528a518089018c526104ce81526104d1818901526104d4818d01526104d7818801526104da818701526104dd818601526104df818501526104e2818401526104e5818301526104e8818b0152898b01528a518089018c526104eb81526104ee818901526104f1818d01526104f4818801526104f7818701526104fa818601526104fc818501526104ff8184015261050281830152610505818b0152888b01528a518089018c52610508815261050b8189015261050e818d015261051181880152610514818701526105178186015261051a8185015261051d8184015261052081830152610523818b01526101608b01528a518089018c5261052681526105298189015261052c818d015261052f8188015261053281870152610536818601526105398185015261053c8184015261053f81830152610542818b01526101808b01528a518089018c5261054581526105488189015261054b818d015261054e8188015261055181870152610555818601526105588185015261055b8184015261055e81830152610561818b01526101a08b01528a518089018c5261056481526105688189015261056b818d015261056e8188015261057181870152610574818601526105788185015261057b8184015261057e81830152610581818b01526101c08b01528a518089018c5261058581526105888189015261058b818d015261058e8188015261059281870152610595818601526105988185015261059b8184015261059f818301526105a2818b01526101e08b01528a518089018c526105a581526105a9818901526105ac818d01526105af818801526105b3818701526105b6818601526105ba818501526105bd818401526105c0818301526105c4818b01526102008b01528a518089018c526105c781526105cb818901526105ce818d01526105d1818801526105d5818701526105d8818601526105dc818501526105df818401526105e3818301526105e6818b01526102208b01528a518089018c526105ea81526105ed818901526105f1818d01526105f4818801526105f8818701526105fb818601526105ff818501526106028184015261060681830152610609818b01526102408b01528a518089018c5261060d815261061081890152610614818d01526106188188015261061b8187015261061f81860152610622818501526106268184015261062a8183015261062d818b01526102608b01528a518089018c52610631815261063581890152610638818d015261063c8188015261064081870152610643818601526106478185015261064b8184015261064e81830152610652818b01526102808b01528a518089018c52610656815261065a8189015261065d818d015261066181880152610665818701526106698186015261066c818501526106708184015261067481830152610678818b01526102a08b01528a518089018c5261067c815261067f81890152610683818d01526106878188015261068b8187015261068f81860152610693818501526106978184015261069a8183015261069e818b01526102c08b01528a518089018c526106a281526106a6818901526106aa818d01526106ae818801526106b2818701526106b6818601526106ba818501526106be818401526106c2818301526106c6818b01526102e08b01528a518089018c526106ca81526106ce818901526106d2818d01526106d6818801526106da818701526106de818601526106e2818501526106e6818401526106ea818301526106ee818b01526103008b019081528b51808a018d526106f281526106f6818a01526106fa818e01526106ff81890152610703818801526107078187015261070b8186015261070f8185015261071381840152610718818c01526103208c01528b51808a018d5261071c8152610720818a0152610724818e01526107288189015261072d8188015261073181870152610735818601526107398185015261073e81840152610742818c01526103408c01528b51808a018d52610746815261074a818a015261074f818e0152610753818901526107578188015261075c8187015261076081860152610764818501526107698184015261076d818c01526103608c01528b51808a018d526107718152610776818a015261077a818e015261077f81890152610783818801526107888187015261078c818601526107908185015261079581840152610799818c01526103808c01528b51808a018d5261079e81526107a2818a01526107a7818e01526107ab818901526107b0818801526107b4818701526107b9818601526107be818501526107c2818401526107c7818c01526103a08c01528b51808a018d526107cb81526107d0818a01526107d4818e01526107d9818901526107de818801526107e2818701526107e7818601526107ec818501526107f0818401526107f5818c01526103c08c01528b51808a018d526107fa81526107fe818a0152610803818e01526108088189015261080d81880152610811818701526108168186015261081b8185015261082081840152610824818c01526103e08c01528b519a9b909a9699959890969094939291908086018852610829815261082e818a015261083381890152610838818c015261083d818b0152610841818601526108468185015261084b818401526108508183015261085581880152818c01528651808601885261085a815261085f818a015261086481890152610869818c015261086e818b0152610873818601526108788185015261087d818401526108828183015261088781880152868c01528651808601885261088c8152610891818a01526108968189015261089b818c01526108a0818b01526108a5818601526108aa818501526108af818401526108b4818301526108ba81880152858c0152865180860188526108bf81526108c4818a01526108c9818901526108ce818c01526108d3818b01526108d9818601526108de818501526108e3818401526108e8818301526108ee818801526101608c0152865180860188526108f381526108f8818a01526108fd81890152610903818c0152610908818b015261090d81860152610913818501526109188184015261091d81830152610923818801526101808c015286518086018852610928815261092e818a015261093381890152610938818c015261093e818b0152610943818601526109498185015261094e8184015261095481830152610959818801526101a08c01528651808601885261095f8152610964818a015261096a8189015261096f818c0152610975818b015261097b81860152610980818501526109868184015261098b81830152610991818801526101c08c015286518086018852610997815261099c818a01526109a2818901526109a8818c01526109ad818b01526109b3818601526109b9818501526109bf818401526109c4818301526109ca818801526101e08c0152865180860188526109d081526109d6818a01526109db818901526109e1818c01526109e7818b01526109ed818601526109f3818501526109f9818401526109ff81830152610a04818801526102008c015286518086018852610a0a8152610a10818a0152610a1681890152610a1c818c0152610a22818b0152610a2881860152610a2e81850152610a3481840152610a3a81830152610a40818801526102208c015286518086018852610a468152610a4c818a0152610a5281890152610a59818c0152610a5f818b0152610a6581860152610a6b81850152610a7181840152610a7781830152610a7d818801526102408c015286518086018852610a848152610a8a818a0152610a9081890152610a96818c0152610a9c818b0152610aa381860152610aa981850152610aaf81840152610ab681830152610abc818801526102608c015286518086018852610ac28152610ac9818a0152610acf81890152610ad5818c0152610adc818b0152610ae281860152610ae981850152610aef81840152610af581830152610afc818801526102808c015286518086018852610b028152610b09818a0152610b0f81890152610b16818c0152610b1c818b0152610b2381860152610b2a81850152610b3081840152610b3781830152610b3d818801526102a08c015286518086018852610b448152610b4b818a0152610b5181890152610b58818c0152610b5f818b0152610b6581860152610b6c81850152610b7381840152610b7a81830152610b80818801526102c08c015286518086018852610b878152610b8e818a0152610b9581890152610b9c818c0152610ba3818b0152610ba981860152610bb081850152610bb781840152610bbe81830152610bc5818801526102e08c015286518086018852610bcc8152610bd3818a0152610bda81890152610be19a81019a909a52610be8988a0198909852610bef92890192909252610bf690880152610bfd90870152610c0494860194909452610c0b9085015261030085019390935282519182018352610c128252610c199082015261032090920191908101610c2161ffff168152610c28602080830191909152610c2f604080840191909152610c36606080850191909152610c3d608080860191909152610c4560a080870191909152610c4c60c080880191909152610c5360e09788015296885283516101408082018652610c5a8252610c6282880152610c6982870152610c7082860152610c7882850152610c7f82840152610c86828a0152610c8e82890152610c9561010080840191909152610c9c610120808501919091528b89019390935286518083018852610ca48152610cab818a0152610cb381890152610cba81880152610cc281870152610cc981860152610cd1818c0152610cd9818b0152610ce081830152610ce8818501528b88015286518083018852610cef8152610cf7818a0152610cff81890152610d0681880152610d0e81870152610d1681860152610d1d818c0152610d25818b0152610d2d81830152610d35818501528b87015286518083018852610d3c8152610d44818a0152610d4c81890152610d5481880152610d5c81870152610d6481860152610d6c818c0152610d73818b0152610d7b81830152610d83818501528b86015286518083018852610d8b8152610d93818a0152610d9b81890152610da381880152610dab81870152610db481860152610dbc818c0152610dc4818b0152610dcc81830152610dd4818501528b85015286518083018852610ddc8152610de4818a0152610ded81890152610df581880152610dfd81870152610e0581860152610e0d818c0152610e16818b0152610e1e81830152610e26818501528b8b015286518083018852610e2f8152610e37818a0152610e4081890152610e4881880152610e5081870152610e5981860152610e61818c0152610e6a818b0152610e7281830152610e7b818501528b8a015286518083018852610e838152610e8c818a0152610e9581890152610e9d81880152610ea681870152610eae81860152610eb7818c0152610ec0818b0152610ec881830152610ed181850152818c015286518083018852610eda8152610ee3818a0152610eeb81890152610ef481880152610efd81870152610f0681860152610f0f818c0152610f18818b0152610f2181830152610f2a81850152838c015286518083018852610f328152610f3b818a0152610f4481890152610f4d81880152610f5681870152610f6081860152610f69818c0152610f72818b0152610f7b81830152610f8481850152828c015286518083018852610f8d8152610f96818a0152610f9f81890152610fa981880152610fb281870152610fbb81860152610fc4818c0152610fce818b0152610fd781830152610fe0818501526101608c015286518083018852610fea8152610ff3818a0152610ffd818901526110068188015261100f8187015261101981860152611022818c015261102c818b01526110368183015261103f818501526101808c0152865180830188526110498152611052818a015261105c818901526110668188015261106f8187015261107981860152611083818c015261108c818b0152611096818301526110a0818501526101a08c0152865180830188526110aa81526110b4818a01526110bd818901526110c7818801526110d1818701526110db818601526110e5818c01526110ef818b01526110f981830152611103818501526101c08c01528651808301885261110d8152611117818a01526111218189015261112b81880152611136818701526111408186015261114a818c0152611154818b015261115e81830152611169818501526101e08c015286518083018852611173815261117d818a0152611187818901526111928188015261119c818701526111a7818601526111b1818c01526111bb818b01526111c6818301526111d0818501526102008c0152865180830188526111db81526111e5818a01526111f0818901526111fb81880152611205818701526112108186015261121a818c0152611225818b01526112308183015261123b818501526102208c0152865180830188526112458152611250818a015261125b81890152611266818801526112718187015261127c81860152611286818c0152611291818b015261129c818301526112a7818501526102408c0152865180830188526112b281526112bd818a01526112c8818901526112d3818801526112df818701526112ea818601526112f5818c0152611300818b015261130b81830152611317818501526102608c015286518083018852611322815261132d818a0152611338818901526113448188015261134f8187015261135b81860152611366818c0152611371818b015261137d81830152611388818501526102808c015286518083018852611394815261139f818a01526113ab818901526113b7818801526113c2818701526113ce818601526113da818c01526113e5818b01526113f1818301526113fd818501526102a08c0152865180830188526114098152611414818a01526114208189015261142c818801526114388187015261144481860152611450818c015261145c818b015261146881830152611474818501526102c08c015286518083018852611480815261148c818a0152611498818901526114a4818801526114b1818701526114bd818601526114c9818c01526114d5818b01526114e2818301526114ee818501526102e08c0152865191820187526114fa825261150797820197909752611513958101959095526115209385019390935261152c9184019190915261153990830152611545948201949094526115529281019290925261155e9082015261156b9181019190915261030090910190815260408051610140808201835261157782526115846020838101919091526115918385015261159e6060808501919091526115aa6080808601919091526115b760a0808701919091526115c460c0808801919091526115d160e0808901919091526115de610100808a01919091526115ea610120808b01919091528b88019990995289518089018b526115f7815261160481890152611611818c015261161e8188015261162b818701526116398186015261164681850152611653818401526116608183015261166d818b01528a8c015289518089018b5261167a815261168881890152611695818c01526116a2818801526116b0818701526116bd818601526116ca818501526116d8818401526116e5818301526116f3818b0152868c015289518089018b52611700815261170e8189015261171c818c0152611729818801526117378187015261174581860152611752818501526117608184015261176e8183015261177c818b0152858c015289518089018b5261178a8152611797818901526117a5818c01526117b3818801526117c1818701526117cf818601526117dd818501526117ec818401526117fa81830152611808818b0152848c015289518089018b52611816815261182481890152611832818c01526118418188015261184f8187015261185d8186015261186c8185015261187a8184015261188981830152611897818b0152838c015289518089018b526118a681526118b4818901526118c3818c01526118d1818801526118e0818701526118ef818601526118fd8185015261190c8184015261191b8183015261192a818b0152828c015289518089018b52611939815261194781890152611956818c0152611965818801526119748187015261198381860152611992818501526119a1818401526119b1818301526119c0818b0152818c015289518089018b526119cf81526119de818901526119ed818c01526119fd81880152611a0c81870152611a1b81860152611a2b81850152611a3a81840152611a4a81830152611a59818b0152898c015289518089018b52611a698152611a7881890152611a88818c0152611a9881880152611aa781870152611ab781860152611ac781850152611ad781840152611ae781830152611af6818b0152888c015289518089018b52611b068152611b1681890152611b26818c0152611b3681880152611b4681870152611b5681860152611b6781850152611b7781840152611b8781830152611b97818b01526101608c015289518089018b52611ba78152611bb881890152611bc8818c0152611bd981880152611be981870152611bf981860152611c0a81850152611c1a81840152611c2b81830152611c3c818b01526101808c015289518089018b52611c4c8152611c5d81890152611c6e818c0152611c7f81880152611c8f81870152611ca081860152611cb181850152611cc281840152611cd381830152611ce4818b01526101a08c015289518089018b52611cf58152611d0681890152611d17818c0152611d2881880152611d3a81870152611d4b81860152611d5c81850152611d6e81840152611d7f81830152611d90818b01526101c08c015289518089018b52611da28152611db381890152611dc5818c0152611dd681880152611de881870152611dfa81860152611e0b81850152611e1d81840152611e2f81830152611e41818b01526101e08c015289518089018b52611e528152611e6481890152611e76818c0152611e8881880152611e9a81870152611eac81860152611ebe81850152611ed181840152611ee381830152611ef5818b01526102008c015289518089018b52611f078152611f1a81890152611f2c818c0152611f3e81880152611f5181870152611f6381860152611f7681850152611f8881840152611f9b81830152611fae818b01526102208c015289518089018b52611fc08152611fd381890152611fe6818c0152611ff98188015261200c8187015261201e8186015261203181850152612044818401526120578183015261206b818b01526102408c015289518089018b5261207e8152612091818901526120a4818c01526120b7818801526120cb818701526120de818601526120f181850152612105818401526121188183015261212c818b01526102608c015289518089018b5261213f815261215381890152612167818c015261217a8188015261218e818701526121a2818601526121b6818501526121ca818401526121de818301526121f2818b01526102808c015289518089018b52612206815261221a8189015261222e818c0152612242818801526122568187015261226a8186015261227f81850152612293818401526122a8818301526122bc818b01526102a08c015289518089018b526122d181526122e5818901526122fa818c015261230e81880152612323818701526123388186015261234c81850152612361818401526123768183015261238b818b01526102c08c015289518089018b526123a081526123b5818901526123ca818c01526123df818801526123f48187015261240a8186015261241f818501526124348184015261244a8183015261245f818b01526102e08c015289518089018b52612475815261248a818901526124a0818c01526124b5818801526124cb818701526124e1818601526124f68185015261250c9281019290925261252290820152612538978101979097526103008901969096528651948501875261254e85526125649385019390935261257a95840195909552612590908301526125a6938201939093526125bd928101929092526103209092019181016125d381526125e96020828101919091526125ff60408084019190915261261660609384015292845282516101408101845261262c8152612643818301526126599381019390935261267091830191909152612687608083015261269e60a08301526126b460c08301526126cb60e08301526126e26101008301526126f96101208301529190910152919050565b5f805f61445c8585619928565b91509150806144a6576040517f22c9f7bb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044015b60405180910390fd5b509392505050565b6144b6619ab9565b60405180610c8001604052806040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601260ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601260ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600f60ff168152602001601160ff168152602001601360ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601360ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601460ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff1681526010602082810182905260126040808501829052601460609586018190529587528051610140810182525f815260028185015260059181019190915260079481019490945260096080850152600b60a0850152600e60c085015260e0840192909252610100830191909152610120820192909252910152919050565b617112619ae7565b60405180610b4001604052806040518061014001604052805f60ff168152602001600460ff168152602001600960ff168152602001600d60ff168152602001601160ff168152602001601560ff168152602001601a60ff168152602001601e60ff168152602001602260ff168152602001602660ff1681525081526020016040518061014001604052805f60ff168152602001600460ff168152602001600860ff168152602001600c60ff168152602001600f60ff168152602001601360ff168152602001601760ff168152602001601b60ff168152602001601f60ff168152602001602360ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600b60ff168152602001600e60ff168152602001601260ff168152602001601560ff168152602001601960ff168152602001601c60ff168152602001602060ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600760ff168152602001600a60ff168152602001600d60ff168152602001601060ff168152602001601460ff168152602001601760ff168152602001601a60ff168152602001601e60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600660ff168152602001600960ff168152602001600c60ff168152602001600f60ff168152602001601260ff168152602001601560ff168152602001601860ff168152602001601c60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600660ff168152602001600960ff168152602001600b60ff168152602001600e60ff168152602001601160ff168152602001601460ff168152602001601760ff168152602001601a60ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600b60ff168152602001600e60ff168152602001601060ff168152602001601360ff168152602001601660ff168152602001601860ff1681525081526020016040518061014001604052805f60ff168152602001600360ff168152602001600560ff168152602001600860ff168152602001600a60ff168152602001600d60ff168152602001600f60ff168152602001601260ff168152602001601460ff168152602001601760ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601360ff168152602001601560ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001601060ff168152602001601260ff168152602001601460ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff168152602001601360ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001601060ff168152602001601260ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600860ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600f60ff168152602001601160ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff168152602001601060ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600e60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600d60ff168152602001600f60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600d60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff168152602001600e60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600c60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff168152602001600d60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600b60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600c60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600960ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600a60ff168152602001600b60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600760ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600860ff168152602001600960ff168152602001600a60ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff168152602001600960ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600860ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600760ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600660ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600660ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600560ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff168152602001600560ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600460ff168152602001600460ff1681525081526020016040518061014001604052805f60ff1681526020015f60ff168152602001600160ff168152602001600160ff168152602001600260ff168152602001600260ff168152602001600360ff168152602001600360ff168152602001600360ff168152602001600460ff16815250815250905090565b5f601b83900b831483838261998c577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561996c57620186a0860595506005850194505b8586601b0b1461998757600a8605955084600101945061996c565b6199a2565b855f036199a257505f925060019150619a289050565b848560030b146199fe575f8512156199c257505f9250829150619a289050565b6040517fd556b111000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260440161449d565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791505b9250929050565b604051806101400160405280600a905b619a47619b15565b815260200190600190039081619a3f5790505090565b60405180610b400160405280605a905b619a75619b15565b815260200190600190039081619a6d5790505090565b60405180610c8001604052806064905b619aa3619b15565b815260200190600190039081619a9b5790505090565b60405180610c8001604052806064905b619ad1619b15565b815260200190600190039081619ac95790505090565b60405180610b400160405280605a905b619aff619b15565b815260200190600190039081619af75790505090565b604051806101400160405280600a906020820280368337509192915050565b5f8282825b600a811015619b5b57815160ff16835260209283019290910190600101619b39565b5050506101408301905092915050565b610c80810181835f5b600a811015619b9957619b88838351619b34565b925060209190910190600101619b74565b50505092915050565b5f8282825b600a811015619b5b57815161ffff16835260209283019290910190600101619ba7565b617080810181835f5b605a811015619b9957619be7838351619ba2565b925060209190910190600101619bd3565b5f60208284031215619c08575f80fd5b5035919050565b617d00810181835f5b6064811015619b9957619c2c838351619ba2565b925060209190910190600101619c18565b5f8060408385031215619c4e575f80fd5b823580601b0b8114619c5e575f80fd5b91506020830135600381900b8114619c74575f80fd5b809150509250929050565b617d00810181835f5b6064811015619b9957619c9c838351619b34565b925060209190910190600101619c88565b617080810181835f5b605a811015619b9957619cca838351619b34565b925060209190910190600101619cb656" } } \ No newline at end of file diff --git a/crates/float/src/evm.rs b/crates/float/src/evm.rs index 6c7179f..d0474b4 100644 --- a/crates/float/src/evm.rs +++ b/crates/float/src/evm.rs @@ -4,19 +4,20 @@ use revm::context::result::{ExecutionResult, Output, SuccessReason}; use revm::context::{BlockEnv, CfgEnv, TxEnv}; use revm::database::InMemoryDB; use revm::primitives::address; +use revm::state::{AccountInfo, Bytecode}; use revm::{Context, MainBuilder, MainContext, MainnetEvm, SystemCallEvm}; use std::cell::RefCell; use crate::{DecimalFloat, FloatError}; -#[cfg(test)] +#[cfg(any(test, feature = "test-harness"))] use crate::TestDecimalFloat; /// Fixed address where the DecimalFloat contract is deployed in the in-memory EVM. /// This arbitrary address is used consistently across all Calculator instances. pub(crate) const FLOAT_ADDRESS: Address = address!("00000000000000000000000000000000000f10a2"); -#[cfg(test)] +#[cfg(any(test, feature = "test-harness"))] /// Fixed address where the TestDecimalFloat contract is deployed in the in-memory EVM. pub(crate) const TEST_FLOAT_ADDRESS: Address = address!("00000000000000000000000000000000000f10a3"); @@ -24,25 +25,110 @@ type EvmContext = Context; type LocalEvm = MainnetEvm; thread_local! { - pub(crate) static LOCAL_EVM: RefCell = { - let mut db = InMemoryDB::default(); - - // Deploy DecimalFloat contract - let bytecode = revm::state::Bytecode::new_legacy(DecimalFloat::DEPLOYED_BYTECODE.clone()); - let account_info = revm::state::AccountInfo::default().with_code(bytecode); - db.insert_account_info(FLOAT_ADDRESS, account_info); - - #[cfg(test)] - { - // Deploy TestDecimalFloat contract for testing - let test_bytecode = revm::state::Bytecode::new_legacy(TestDecimalFloat::DEPLOYED_BYTECODE.clone()); - let test_account_info = revm::state::AccountInfo::default().with_code(test_bytecode); - db.insert_account_info(TEST_FLOAT_ADDRESS, test_account_info); + pub(crate) static LOCAL_EVM: RefCell = RefCell::new(build_evm()); +} + +/// The in-memory EVM every call runs against, with the contracts in place. +fn build_evm() -> LocalEvm { + let mut db = InMemoryDB::default(); + place( + &mut db, + FLOAT_ADDRESS, + "RAIN_MATH_FLOAT_ARTIFACT", + &DecimalFloat::BYTECODE, + &DecimalFloat::DEPLOYED_BYTECODE, + ); + #[cfg(any(test, feature = "test-harness"))] + place( + &mut db, + TEST_FLOAT_ADDRESS, + "RAIN_MATH_FLOAT_TEST_ARTIFACT", + &TestDecimalFloat::BYTECODE, + &TestDecimalFloat::DEPLOYED_BYTECODE, + ); + Context::mainnet().with_db(db).build_mainnet() +} + +/// Places the contract compiled into this crate at `address`, as deployed. +#[cfg(not(feature = "test-harness"))] +fn place( + db: &mut InMemoryDB, + address: Address, + _artifact_var: &str, + _creation: &Bytes, + runtime: &Bytes, +) { + put(db, address, runtime.clone()); +} + +/// Places a contract at `address`. The bytecode is the one compiled into this +/// crate unless the environment variable named by `artifact_var` points at a +/// forge artifact of another build of the same ABI, such as a test concrete +/// compiled from the library source. `RAIN_MATH_FLOAT_DEPLOY_MODE=create` +/// runs the creation bytecode instead of placing the runtime bytecode, for a +/// concrete whose constructor sets immutables or deploys what it depends on. +#[cfg(feature = "test-harness")] +fn place( + db: &mut InMemoryDB, + address: Address, + artifact_var: &str, + creation: &Bytes, + runtime: &Bytes, +) { + let (creation, runtime) = match std::env::var_os(artifact_var) { + Some(path) => { + let path = std::path::PathBuf::from(path); + let json = std::fs::read_to_string(&path) + .unwrap_or_else(|e| panic!("{artifact_var}={}: {e}", path.display())); + let artifact: alloy::json_abi::ContractObject = serde_json::from_str(&json) + .unwrap_or_else(|e| panic!("{artifact_var}={}: {e}", path.display())); + ( + artifact + .bytecode + .unwrap_or_else(|| panic!("{artifact_var}={}: no bytecode", path.display())), + artifact.deployed_bytecode.unwrap_or_else(|| { + panic!("{artifact_var}={}: no deployedBytecode", path.display()) + }), + ) } + None => (creation.clone(), runtime.clone()), + }; + match std::env::var("RAIN_MATH_FLOAT_DEPLOY_MODE") { + Ok(mode) if mode == "create" => create(db, address, creation), + Ok(mode) if mode == "runtime" => put(db, address, runtime), + Err(std::env::VarError::NotPresent) => put(db, address, runtime), + other => panic!("RAIN_MATH_FLOAT_DEPLOY_MODE must be `runtime` or `create`: {other:?}"), + } +} + +/// Writes `runtime` as the code at `address`. +fn put(db: &mut InMemoryDB, address: Address, runtime: Bytes) { + db.insert_account_info( + address, + AccountInfo::default().with_code(Bytecode::new_legacy(runtime)), + ); +} - let evm = Context::mainnet().with_db(db).build_mainnet(); - RefCell::new(evm) +/// Runs `creation` as `address` so its constructor executes, keeps whatever +/// state that produced, and writes the runtime code it returned at `address`. +#[cfg(feature = "test-harness")] +fn create(db: &mut InMemoryDB, address: Address, creation: Bytes) { + use revm::DatabaseCommit; + + put(db, address, creation); + let mut evm = Context::mainnet().with_db(db.clone()).build_mainnet(); + let result_and_state = evm + .system_call(address, Bytes::new()) + .expect("creation code ran"); + let runtime = match result_and_state.result { + ExecutionResult::Success { + output: Output::Call(output), + .. + } => output, + other => panic!("creation code at {address} did not return runtime code: {other:?}"), }; + db.commit(result_and_state.state); + put(db, address, runtime); } pub(crate) fn execute_call(calldata: Bytes, process_output: F) -> Result @@ -52,7 +138,7 @@ where execute_call_at_address(FLOAT_ADDRESS, calldata, process_output) } -#[cfg(test)] +#[cfg(any(test, feature = "test-harness"))] pub(crate) fn execute_test_call(calldata: Bytes, process_output: F) -> Result where F: FnOnce(Bytes) -> Result, diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 994b8fd..6b283f5 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -6,32 +6,33 @@ use serde::{Deserialize, Serialize}; use std::ops::{Add, Div, Mul, Neg, Sub}; use wasm_bindgen_utils::prelude::*; -#[cfg(test)] +#[cfg(any(test, feature = "test-harness"))] use alloy::primitives::aliases::I224; pub mod error; mod evm; mod fuzz_ops; pub mod js_api; +#[cfg(any(test, feature = "test-harness"))] pub mod tables; use error::DecimalFloatErrorSelector; pub use error::FloatError; use evm::execute_call; -#[cfg(test)] +#[cfg(any(test, feature = "test-harness"))] use evm::execute_test_call; sol!( #![sol(all_derives)] DecimalFloat, - concat!(env!("CARGO_MANIFEST_DIR"), "/abi/DecimalFloat.json") + "abi/DecimalFloat.json" ); -#[cfg(test)] +#[cfg(any(test, feature = "test-harness"))] sol!( #![sol(all_derives)] TestDecimalFloat, - concat!(env!("CARGO_MANIFEST_DIR"), "/abi/TestDecimalFloat.json") + "abi/TestDecimalFloat.json" ); #[derive(Debug, Copy, Clone, Default, Serialize, Deserialize, Hash)] @@ -224,7 +225,7 @@ impl Float { /// /// anyhow::Ok(()) /// ``` - #[cfg(test)] + #[cfg(any(test, feature = "test-harness"))] pub fn pack_lossless(coefficient: I224, exponent: i32) -> Result { let calldata = TestDecimalFloat::packLosslessCall { coefficient, @@ -238,8 +239,8 @@ impl Float { }) } - #[cfg(test)] - fn unpack(self) -> Result<(alloy::primitives::I256, alloy::primitives::I256), FloatError> { + #[cfg(any(test, feature = "test-harness"))] + pub fn unpack(self) -> Result<(alloy::primitives::I256, alloy::primitives::I256), FloatError> { let Float(float) = self; let calldata = TestDecimalFloat::unpackCall { float }.abi_encode(); @@ -253,8 +254,8 @@ impl Float { }) } - #[cfg(test)] - fn show_unpacked(self) -> Result { + #[cfg(any(test, feature = "test-harness"))] + pub fn show_unpacked(self) -> Result { let (coefficient, exponent) = self.unpack()?; Ok(format!("{coefficient}e{exponent}")) } diff --git a/crates/float/src/tables.rs b/crates/float/src/tables.rs index 8f52889..d061640 100644 --- a/crates/float/src/tables.rs +++ b/crates/float/src/tables.rs @@ -1,644 +1,45 @@ -/// Independent generation of log/antilog lookup tables from f64 math. -/// Used to verify the hardcoded Solidity tables in LibLogTable.sol. -/// -/// ALT_TABLE_FLAG as used in LibLogTable.sol — bit 15 of a uint16. -pub const ALT_TABLE_FLAG: u16 = 0x8000; +//! The log tables `LibLogTable` ships, read from the harness contract so a +//! test can check them against an independent derivation without copying +//! them. -/// Generate the main log table: uint16[10][90]. -/// -/// Standard 4-figure log table layout. Row r (0-89) and column c (0-9) -/// represent the 3-digit mantissa prefix (10+r) and third digit c, so -/// the looked-up number is n = (10+r)*100 + c*10, ranging from 1000 to -/// 9990. The stored value is the fractional part of log10(n) scaled by -/// 10000: round((log10(n) - 3) * 10000). -/// -/// ALT_TABLE_FLAG is set on entries where the small alt table provides -/// different (more precise) mean differences than the regular small table. -pub fn generate_log_table(small: &[[u8; 10]; 90], small_alt: &[[u8; 10]; 10]) -> [[u16; 10]; 90] { - let mut table = [[0u16; 10]; 90]; - for (row, table_row) in table.iter_mut().enumerate() { - for (col, entry) in table_row.iter_mut().enumerate() { - let n = ((10 + row) * 100 + col * 10) as f64; - let base = ((n.log10() - 3.0) * 10000.0).round() as u16; - let needs_alt = row < 10 && small[row][col] != small_alt[row][col]; - *entry = if needs_alt { - base | ALT_TABLE_FLAG - } else { - base - }; - } - } - table -} +use alloy::primitives::Bytes; +use alloy::sol_types::SolCall; -/// Generate the small log table: uint8[10][90]. -/// -/// Mean differences for the 4th digit. Each entry is the rounded -/// difference in scaled log10 between the 4-digit number and the base -/// 3-digit number for that row. -pub fn generate_log_table_small() -> [[u8; 10]; 90] { - let mut table = [[0u8; 10]; 90]; - for (row, table_row) in table.iter_mut().enumerate() { - let base_n = (10 + row) * 100; - let base_log = (base_n as f64).log10(); - for (col, entry) in table_row.iter_mut().enumerate() { - let diff = ((base_n + col) as f64).log10() - base_log; - *entry = (diff * 10000.0).round() as u8; - } - } - table -} +use crate::{execute_test_call, FloatError, TestDecimalFloat}; -/// Generate the small alt log table: uint8[10][10]. -/// -/// Higher-precision mean differences for the first 10 rows (mantissa -/// 100-199). Uses floor of scaled values then takes the difference. -pub fn generate_log_table_small_alt() -> [[u8; 10]; 10] { - let mut table = [[0u8; 10]; 10]; - for (row, table_row) in table.iter_mut().enumerate() { - let base_n = (10 + row) * 100; - let base_log = (base_n as f64).log10(); - for (col, entry) in table_row.iter_mut().enumerate() { - let diff = ((base_n + col) as f64).log10() - base_log; - *entry = (diff * 10000.0).round() as u8; - } - } - table +fn read(call: C) -> Result { + execute_test_call(Bytes::from(call.abi_encode()), |output| { + Ok(C::abi_decode_returns(output.as_ref())?) + }) } -/// Generate the antilog table: uint16[10][100]. -/// -/// The full antilog index range is 0-9999 (ANTILOG_IDX_CARDINALITY). -/// The main table has 1000 entries (100 rows × 10 cols), one per group -/// of 10 consecutive indices. Flattened entry k corresponds to indices -/// k*10 through k*10+9. Value = round(10^(k*10/10000) * 1000). -pub fn generate_antilog_table() -> [[u16; 10]; 100] { - let mut table = [[0u16; 10]; 100]; - for (row, table_row) in table.iter_mut().enumerate() { - for (col, entry) in table_row.iter_mut().enumerate() { - let k = row * 10 + col; - *entry = (10.0_f64.powf((k * 10) as f64 / 10000.0) * 1000.0).round() as u16; - } - } - table +/// `ALT_TABLE_FLAG`: the bit a main log table entry sets to select the +/// alternative small table. +pub fn alt_table_flag() -> Result { + read(TestDecimalFloat::altTableFlagCall {}) } -/// Generate the small antilog table: uint8[10][100]. -/// -/// Indexed by [idx/100][idx%10] where idx is the full index (0-9999). -/// The value is the correction to add to the main table entry. -/// For a given idx: main covers idx rounded down to nearest 10, -/// small adds the sub-10 correction. -/// -/// Value = round(10^(idx/10000) * 1000) - main_table[idx/10] -/// But since many indices share the same [row][col], the table stores -/// a representative value. In practice it's computed for the first -/// occurrence (tens digit = 0). -pub fn generate_antilog_table_small() -> [[u8; 10]; 100] { - let mut table = [[0u8; 10]; 100]; - for (row, table_row) in table.iter_mut().enumerate() { - for (col, entry) in table_row.iter_mut().enumerate() { - let idx = row * 100 + col; - let main_k = idx / 10; - let main_val = (10.0_f64.powf((main_k * 10) as f64 / 10000.0) * 1000.0).round(); - let exact_val = (10.0_f64.powf(idx as f64 / 10000.0) * 1000.0).round(); - *entry = (exact_val - main_val).round() as u8; - } - } - table +/// `LibLogTable.logTableDec()`. +pub fn log_table_dec() -> Result<[[u16; 10]; 90], FloatError> { + read(TestDecimalFloat::logTableDecCall {}) } -#[cfg(test)] -#[allow(clippy::needless_range_loop)] -mod tests { - use super::*; - - /// Verify the main log table entries are within ±1 of the true value. - /// The Solidity tables are transcribed from a published 4-figure log - /// table reference and may use rounding conventions that differ from - /// IEEE 754 f64, so we check proximity rather than exact equality. - #[test] - fn test_log_table_accuracy() { - let table = solidity_log_table(); - for row in 0..90 { - for col in 0..10 { - let n = ((10 + row) * 100 + col * 10) as f64; - let expected = ((n.log10() - 3.0) * 10000.0).round() as i32; - let actual = (table[row][col] & !ALT_TABLE_FLAG) as i32; - assert!( - (actual - expected).abs() <= 1, - "log table [{row}][{col}]: n={n}, expected={expected}, actual={actual}, diff={}", - actual - expected - ); - } - } - } - - /// Verify the main antilog table entries are within ±1 of the true value. - #[test] - fn test_antilog_table_accuracy() { - let table = solidity_antilog_table(); - for row in 0..100 { - for col in 0..10 { - let k = row * 10 + col; - let expected = (10.0_f64.powf((k * 10) as f64 / 10000.0) * 1000.0).round() as i32; - let actual = table[row][col] as i32; - assert!( - (actual - expected).abs() <= 1, - "antilog table [{row}][{col}]: k={k}, expected={expected}, actual={actual}, diff={}", - actual - expected - ); - } - } - } - - /// Verify that main + small gives a value close to the true log10 - /// for every 4-digit number 1000-9999. - #[test] - fn test_log_lookup_accuracy() { - let main = solidity_log_table(); - let small = solidity_log_table_small(); - let small_alt = solidity_log_table_small_alt(); - for n in 1000..10000_usize { - let row = n / 10 - 100; - let _col = (n / 10) % 10; - let d = n % 10; - let main_row = row / 10; - let main_col = row % 10; - - let main_entry = main[main_row][main_col]; - let main_val = (main_entry & !ALT_TABLE_FLAG) as i32; - let use_alt = main_entry & ALT_TABLE_FLAG != 0; - let small_val = if use_alt { - small_alt[main_row][d] as i32 - } else { - small[main_row][d] as i32 - }; - let table_result = main_val + small_val; - let true_val = ((n as f64).log10() - 3.0) * 10000.0; - - // The lookup should be within 2 of the true value (main has - // ±1 error, small has ±1 error). - assert!( - (table_result as f64 - true_val).abs() < 2.5, - "log lookup for n={n}: table={table_result}, true={true_val:.2}, diff={:.2}", - table_result as f64 - true_val - ); - } - } - - /// Verify that main + small gives a value close to the true antilog - /// for every index 0-9999. - #[test] - fn test_antilog_lookup_accuracy() { - let main = solidity_antilog_table(); - let small = solidity_antilog_table_small(); - for idx in 0..10000_usize { - let main_k = idx / 10; - let main_row = main_k / 10; - let main_col = main_k % 10; - let main_val = main[main_row][main_col] as i32; - - let small_row = idx / 100; - let small_col = idx % 10; - let small_val = small[small_row][small_col] as i32; - - let table_result = main_val + small_val; - let true_val = 10.0_f64.powf(idx as f64 / 10000.0) * 1000.0; - - assert!( - (table_result as f64 - true_val).abs() < 2.5, - "antilog lookup for idx={idx}: table={table_result}, true={true_val:.2}, diff={:.2}", - table_result as f64 - true_val - ); - } - } - - /// Verify that the main antilog table entries exactly match - /// round(10^(k*10/10000) * 1000). - #[test] - fn test_antilog_table_exact() { - let generated = generate_antilog_table(); - let solidity = solidity_antilog_table(); - for row in 0..100 { - for col in 0..10 { - assert_eq!( - generated[row][col], solidity[row][col], - "antilog table mismatch at [{row}][{col}]: generated={}, solidity={}", - generated[row][col], solidity[row][col] - ); - } - } - } - - /// Verify the small log table — generated values are either exact or - /// at most 1 above the Solidity value. The published reference table - /// uses rounding conventions that floor certain values where IEEE 754 - /// round-half-up produces the next integer. The direction is always - /// generated >= solidity. - #[test] - fn test_log_table_small_generation() { - let generated = generate_log_table_small(); - let solidity = solidity_log_table_small(); - for row in 0..90 { - for col in 0..10 { - let diff = generated[row][col] as i16 - solidity[row][col] as i16; - assert!( - diff.abs() <= 1, - "log small [{row}][{col}]: generated={}, solidity={}, diff={diff}", - generated[row][col], - solidity[row][col] - ); - } - } - } - - /// Verify the small alt log table — allows ±2 because the published - /// table uses interpolation conventions that differ from per-entry - /// floor differences by up to 2 units. - #[test] - fn test_log_table_small_alt_generation() { - let generated = generate_log_table_small_alt(); - let solidity = solidity_log_table_small_alt(); - for row in 0..10 { - for col in 0..10 { - let diff = generated[row][col] as i16 - solidity[row][col] as i16; - assert!( - diff.abs() <= 3, - "log small alt [{row}][{col}]: generated={}, solidity={}, diff={diff}", - generated[row][col], - solidity[row][col] - ); - } - } - } - - /// Verify the small antilog table — same +1 tolerance. - #[test] - fn test_antilog_table_small_generation() { - let generated = generate_antilog_table_small(); - let solidity = solidity_antilog_table_small(); - for row in 0..100 { - for col in 0..10 { - let diff = generated[row][col] as i16 - solidity[row][col] as i16; - assert!( - diff.abs() <= 1, - "antilog small [{row}][{col}]: generated={}, solidity={}, diff={diff}", - generated[row][col], - solidity[row][col] - ); - } - } - } - - /// Verify the main log table — the base values (without ALT flag) - /// match exactly. ALT flags depend on the small table generation - /// so they get +1 tolerance via the ALT flag being set or not. - #[test] - fn test_log_table_generation() { - let small = generate_log_table_small(); - let small_alt = generate_log_table_small_alt(); - let generated = generate_log_table(&small, &small_alt); - let solidity = solidity_log_table(); - for row in 0..90 { - for col in 0..10 { - let gen_base = generated[row][col] & !ALT_TABLE_FLAG; - let sol_base = solidity[row][col] & !ALT_TABLE_FLAG; - assert_eq!( - gen_base, sol_base, - "log [{row}][{col}] base: generated={gen_base}, solidity={sol_base}", - ); - } - } - } - - // The Solidity reference tables follow. These are copied verbatim from - // LibLogTable.sol so the Rust-generated values can be compared against - // the exact on-chain constants. - - #[rustfmt::skip] - fn solidity_log_table() -> [[u16; 10]; 90] { - [ - [0, 43, 86, 128, 170, 212|ALT_TABLE_FLAG, 253|ALT_TABLE_FLAG, 294|ALT_TABLE_FLAG, 334|ALT_TABLE_FLAG, 374|ALT_TABLE_FLAG], - [414, 453, 492, 531, 569, 607|ALT_TABLE_FLAG, 645|ALT_TABLE_FLAG, 682|ALT_TABLE_FLAG, 719|ALT_TABLE_FLAG, 755|ALT_TABLE_FLAG], - [792, 828, 864, 899, 934, 969, 1004|ALT_TABLE_FLAG, 1038|ALT_TABLE_FLAG, 1072|ALT_TABLE_FLAG, 1106|ALT_TABLE_FLAG], - [1139, 1173, 1206, 1239, 1271, 1303|ALT_TABLE_FLAG, 1335|ALT_TABLE_FLAG, 1367|ALT_TABLE_FLAG, 1399|ALT_TABLE_FLAG, 1430|ALT_TABLE_FLAG], - [1461, 1492, 1523, 1553, 1584|ALT_TABLE_FLAG, 1614|ALT_TABLE_FLAG, 1644|ALT_TABLE_FLAG, 1673|ALT_TABLE_FLAG, 1703|ALT_TABLE_FLAG, 1732|ALT_TABLE_FLAG], - [1761, 1790, 1818, 1847, 1875, 1903, 1931|ALT_TABLE_FLAG, 1959|ALT_TABLE_FLAG, 1987|ALT_TABLE_FLAG, 2014|ALT_TABLE_FLAG], - [2041, 2068, 2095, 2122, 2148, 2175|ALT_TABLE_FLAG, 2201|ALT_TABLE_FLAG, 2227|ALT_TABLE_FLAG, 2253|ALT_TABLE_FLAG, 2279|ALT_TABLE_FLAG], - [2304, 2330, 2355, 2380, 2405, 2430, 2455|ALT_TABLE_FLAG, 2480|ALT_TABLE_FLAG, 2504|ALT_TABLE_FLAG, 2529|ALT_TABLE_FLAG], - [2553, 2577, 2601, 2625, 2648, 2672|ALT_TABLE_FLAG, 2695|ALT_TABLE_FLAG, 2718|ALT_TABLE_FLAG, 2742|ALT_TABLE_FLAG, 2765|ALT_TABLE_FLAG], - [2788, 2810, 2833, 2856, 2878, 2900|ALT_TABLE_FLAG, 2923|ALT_TABLE_FLAG, 2945|ALT_TABLE_FLAG, 2967|ALT_TABLE_FLAG, 2989|ALT_TABLE_FLAG], - [3010, 3032, 3054, 3075, 3096, 3118, 3139, 3160, 3181, 3201], - [3222, 3243, 3263, 3284, 3304, 3324, 3345, 3365, 3385, 3404], - [3424, 3444, 3464, 3483, 3502, 3522, 3541, 3560, 3579, 3598], - [3617, 3636, 3655, 3674, 3692, 3711, 3729, 3747, 3766, 3784], - [3802, 3820, 3838, 3856, 3874, 3892, 3909, 3927, 3945, 3962], - [3979, 3997, 4014, 4031, 4048, 4065, 4082, 4099, 4116, 4133], - [4150, 4166, 4183, 4200, 4216, 4232, 4249, 4265, 4281, 4298], - [4314, 4330, 4346, 4362, 4378, 4393, 4409, 4425, 4440, 4456], - [4472, 4487, 4502, 4518, 4533, 4548, 4564, 4579, 4594, 4609], - [4624, 4639, 4654, 4669, 4683, 4698, 4713, 4728, 4742, 4757], - [4771, 4786, 4800, 4814, 4829, 4843, 4857, 4871, 4886, 4900], - [4914, 4928, 4942, 4955, 4969, 4983, 4997, 5011, 5024, 5038], - [5051, 5065, 5079, 5092, 5105, 5119, 5132, 5145, 5159, 5172], - [5185, 5198, 5211, 5224, 5237, 5250, 5263, 5276, 5289, 5302], - [5315, 5328, 5340, 5353, 5366, 5378, 5391, 5403, 5416, 5428], - [5441, 5453, 5465, 5478, 5490, 5502, 5514, 5527, 5539, 5551], - [5563, 5575, 5587, 5599, 5611, 5623, 5635, 5647, 5658, 5670], - [5682, 5694, 5705, 5717, 5729, 5740, 5752, 5763, 5775, 5786], - [5798, 5809, 5821, 5832, 5843, 5855, 5866, 5877, 5888, 5899], - [5911, 5922, 5933, 5944, 5955, 5966, 5977, 5988, 5999, 6010], - [6021, 6031, 6042, 6053, 6064, 6075, 6085, 6096, 6107, 6117], - [6128, 6138, 6149, 6160, 6170, 6180, 6191, 6201, 6212, 6222], - [6232, 6243, 6253, 6263, 6274, 6284, 6294, 6304, 6314, 6325], - [6335, 6345, 6355, 6365, 6375, 6385, 6395, 6405, 6415, 6425], - [6435, 6444, 6454, 6464, 6474, 6484, 6493, 6503, 6513, 6522], - [6532, 6542, 6551, 6561, 6571, 6580, 6590, 6599, 6609, 6618], - [6628, 6637, 6646, 6656, 6665, 6675, 6684, 6693, 6702, 6712], - [6721, 6730, 6739, 6749, 6758, 6767, 6776, 6785, 6794, 6803], - [6812, 6821, 6830, 6839, 6848, 6857, 6866, 6875, 6884, 6893], - [6902, 6911, 6920, 6928, 6937, 6946, 6955, 6964, 6972, 6981], - [6990, 6998, 7007, 7016, 7024, 7033, 7042, 7050, 7059, 7067], - [7076, 7084, 7093, 7101, 7110, 7118, 7126, 7135, 7143, 7152], - [7160, 7168, 7177, 7185, 7193, 7202, 7210, 7218, 7226, 7235], - [7243, 7251, 7259, 7267, 7275, 7284, 7292, 7300, 7308, 7316], - [7324, 7332, 7340, 7348, 7356, 7364, 7372, 7380, 7388, 7396], - [7404, 7412, 7419, 7427, 7435, 7443, 7451, 7459, 7466, 7474], - [7482, 7490, 7497, 7505, 7513, 7520, 7528, 7536, 7543, 7551], - [7559, 7566, 7574, 7582, 7589, 7597, 7604, 7612, 7619, 7627], - [7634, 7642, 7649, 7657, 7664, 7672, 7679, 7686, 7694, 7701], - [7709, 7716, 7723, 7731, 7738, 7745, 7752, 7760, 7767, 7774], - [7782, 7789, 7796, 7803, 7810, 7818, 7825, 7832, 7839, 7846], - [7853, 7860, 7868, 7875, 7882, 7889, 7896, 7903, 7910, 7917], - [7924, 7931, 7938, 7945, 7952, 7959, 7966, 7973, 7980, 7987], - [7993, 8000, 8007, 8014, 8021, 8028, 8035, 8041, 8048, 8055], - [8062, 8069, 8075, 8082, 8089, 8096, 8102, 8109, 8116, 8122], - [8129, 8136, 8142, 8149, 8156, 8162, 8169, 8176, 8182, 8189], - [8195, 8202, 8209, 8215, 8222, 8228, 8235, 8241, 8248, 8254], - [8261, 8267, 8274, 8280, 8287, 8293, 8299, 8306, 8312, 8319], - [8325, 8331, 8338, 8344, 8351, 8357, 8363, 8370, 8376, 8382], - [8388, 8395, 8401, 8407, 8414, 8420, 8426, 8432, 8439, 8445], - [8451, 8457, 8463, 8470, 8476, 8482, 8488, 8494, 8500, 8506], - [8513, 8519, 8525, 8531, 8537, 8543, 8549, 8555, 8561, 8567], - [8573, 8579, 8585, 8591, 8597, 8603, 8609, 8615, 8621, 8627], - [8633, 8639, 8645, 8651, 8657, 8663, 8669, 8675, 8681, 8686], - [8692, 8698, 8704, 8710, 8716, 8722, 8727, 8733, 8739, 8745], - [8751, 8756, 8762, 8768, 8774, 8779, 8785, 8791, 8797, 8802], - [8808, 8814, 8820, 8825, 8831, 8837, 8842, 8848, 8854, 8859], - [8865, 8871, 8876, 8882, 8887, 8893, 8899, 8904, 8910, 8915], - [8921, 8927, 8932, 8938, 8943, 8949, 8954, 8960, 8965, 8971], - [8976, 8982, 8987, 8993, 8998, 9004, 9009, 9015, 9020, 9025], - [9031, 9036, 9042, 9047, 9053, 9058, 9063, 9069, 9074, 9079], - [9085, 9090, 9096, 9101, 9106, 9112, 9117, 9122, 9128, 9133], - [9138, 9143, 9149, 9154, 9159, 9165, 9170, 9175, 9180, 9186], - [9191, 9196, 9201, 9206, 9212, 9217, 9222, 9227, 9232, 9238], - [9243, 9248, 9253, 9258, 9263, 9269, 9274, 9279, 9284, 9289], - [9294, 9299, 9304, 9309, 9315, 9320, 9325, 9330, 9335, 9340], - [9345, 9350, 9355, 9360, 9365, 9370, 9375, 9380, 9385, 9390], - [9395, 9400, 9405, 9410, 9415, 9420, 9425, 9430, 9435, 9440], - [9445, 9450, 9455, 9460, 9465, 9469, 9474, 9479, 9484, 9489], - [9494, 9499, 9504, 9509, 9513, 9518, 9523, 9528, 9533, 9538], - [9542, 9547, 9552, 9557, 9562, 9566, 9571, 9576, 9581, 9586], - [9590, 9595, 9600, 9605, 9609, 9614, 9619, 9624, 9628, 9633], - [9638, 9643, 9647, 9652, 9657, 9661, 9666, 9671, 9675, 9680], - [9685, 9689, 9694, 9699, 9703, 9708, 9713, 9717, 9722, 9727], - [9731, 9736, 9741, 9745, 9750, 9754, 9759, 9763, 9768, 9773], - [9777, 9782, 9786, 9791, 9795, 9800, 9805, 9809, 9814, 9818], - [9823, 9827, 9832, 9836, 9841, 9845, 9850, 9854, 9859, 9863], - [9868, 9872, 9877, 9881, 9886, 9890, 9894, 9899, 9903, 9908], - [9912, 9917, 9921, 9926, 9930, 9934, 9939, 9943, 9948, 9952], - [9956, 9961, 9965, 9969, 9974, 9978, 9983, 9987, 9991, 9996], - ] - } - - #[rustfmt::skip] - fn solidity_log_table_small() -> [[u8; 10]; 90] { - [ - [0, 4, 9, 13, 17, 21, 26, 30, 34, 38], [0, 4, 8, 12, 15, 19, 23, 27, 31, 35], - [0, 3, 7, 11, 14, 18, 21, 25, 28, 32], [0, 3, 7, 10, 13, 16, 20, 23, 26, 30], - [0, 3, 6, 9, 12, 15, 18, 21, 24, 28], [0, 3, 6, 9, 11, 14, 17, 20, 23, 26], - [0, 3, 5, 8, 11, 14, 16, 19, 22, 24], [0, 3, 5, 8, 10, 13, 15, 18, 20, 23], - [0, 2, 5, 7, 9, 12, 14, 16, 19, 21], [0, 2, 4, 7, 9, 11, 13, 16, 18, 20], - [0, 2, 4, 6, 8, 11, 13, 15, 17, 19], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18], - [0, 2, 4, 6, 8, 10, 12, 14, 15, 17], [0, 2, 4, 6, 7, 9, 11, 13, 15, 17], - [0, 2, 4, 5, 7, 9, 11, 12, 14, 16], [0, 2, 3, 5, 7, 9, 10, 12, 14, 15], - [0, 2, 3, 5, 7, 8, 10, 11, 13, 15], [0, 2, 3, 5, 6, 8, 9, 11, 13, 14], - [0, 2, 3, 5, 6, 8, 9, 11, 12, 14], [0, 1, 3, 4, 6, 7, 9, 10, 12, 13], - [0, 1, 3, 4, 6, 7, 9, 10, 11, 13], [0, 1, 3, 4, 6, 7, 8, 10, 11, 12], - [0, 1, 3, 4, 5, 7, 8, 9, 11, 12], [0, 1, 3, 4, 5, 6, 8, 9, 10, 12], - [0, 1, 3, 4, 5, 6, 8, 9, 10, 11], [0, 1, 2, 4, 5, 6, 7, 9, 10, 11], - [0, 1, 2, 4, 5, 6, 7, 8, 10, 11], [0, 1, 2, 3, 5, 6, 7, 8, 9, 10], - [0, 1, 2, 3, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 7, 8, 9, 10], - [0, 1, 2, 3, 4, 5, 6, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 7, 8], [0, 1, 2, 3, 4, 5, 5, 6, 7, 8], - [0, 1, 2, 3, 4, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 4, 5, 6, 7, 8], - [0, 1, 2, 3, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 3, 4, 5, 6, 7, 8], - [0, 1, 2, 2, 3, 4, 5, 6, 7, 7], [0, 1, 2, 2, 3, 4, 5, 6, 6, 7], - [0, 1, 2, 2, 3, 4, 5, 6, 6, 7], [0, 1, 2, 2, 3, 4, 5, 5, 6, 7], - [0, 1, 2, 2, 3, 4, 5, 5, 6, 7], [0, 1, 2, 2, 3, 4, 5, 5, 6, 7], - [0, 1, 1, 2, 3, 4, 4, 5, 6, 7], [0, 1, 1, 2, 3, 4, 4, 5, 6, 7], - [0, 1, 1, 2, 3, 4, 4, 5, 6, 6], [0, 1, 1, 2, 3, 4, 4, 5, 6, 6], - [0, 1, 1, 2, 3, 3, 4, 5, 6, 6], [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], - [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], - [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], - [0, 1, 1, 2, 3, 3, 4, 4, 5, 6], [0, 1, 1, 2, 2, 3, 4, 4, 5, 6], - [0, 1, 1, 2, 2, 3, 4, 4, 5, 6], [0, 1, 1, 2, 2, 3, 4, 4, 5, 5], - [0, 1, 1, 2, 2, 3, 4, 4, 5, 5], [0, 1, 1, 2, 2, 3, 4, 4, 5, 5], - [0, 1, 1, 2, 2, 3, 4, 4, 5, 5], [0, 1, 1, 2, 2, 3, 3, 4, 5, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 5, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 3, 4], - ] - } +/// `LibLogTable.logTableDecSmall()`. +pub fn log_table_dec_small() -> Result<[[u8; 10]; 90], FloatError> { + read(TestDecimalFloat::logTableDecSmallCall {}) +} - #[rustfmt::skip] - fn solidity_log_table_small_alt() -> [[u8; 10]; 10] { - [ - [0, 4, 8, 12, 16, 20, 24, 28, 32, 37], - [0, 4, 7, 11, 15, 19, 22, 26, 30, 33], - [0, 3, 7, 10, 14, 17, 20, 24, 27, 31], - [0, 3, 7, 10, 12, 16, 19, 22, 25, 29], - [0, 3, 6, 9, 12, 15, 17, 20, 23, 26], - [0, 3, 5, 8, 11, 14, 16, 19, 22, 25], - [0, 3, 5, 8, 10, 13, 15, 18, 21, 23], - [0, 2, 5, 7, 10, 12, 15, 17, 19, 22], - [0, 2, 5, 7, 9, 11, 14, 16, 18, 21], - [0, 2, 4, 6, 8, 11, 13, 15, 17, 19], - ] - } +/// `LibLogTable.logTableDecSmallAlt()`. +pub fn log_table_dec_small_alt() -> Result<[[u8; 10]; 10], FloatError> { + read(TestDecimalFloat::logTableDecSmallAltCall {}) +} - #[rustfmt::skip] - fn solidity_antilog_table() -> [[u16; 10]; 100] { - [ - [1000, 1002, 1005, 1007, 1009, 1012, 1014, 1016, 1019, 1021], - [1023, 1026, 1028, 1030, 1033, 1035, 1038, 1040, 1042, 1045], - [1047, 1050, 1052, 1054, 1057, 1059, 1062, 1064, 1067, 1069], - [1072, 1074, 1076, 1079, 1081, 1084, 1086, 1089, 1091, 1094], - [1096, 1099, 1102, 1104, 1107, 1109, 1112, 1114, 1117, 1119], - [1122, 1125, 1127, 1130, 1132, 1135, 1138, 1140, 1143, 1146], - [1148, 1151, 1153, 1156, 1159, 1161, 1164, 1167, 1169, 1172], - [1175, 1178, 1180, 1183, 1186, 1189, 1191, 1194, 1197, 1199], - [1202, 1205, 1208, 1211, 1213, 1216, 1219, 1222, 1225, 1227], - [1230, 1233, 1236, 1239, 1242, 1245, 1247, 1250, 1253, 1256], - [1259, 1262, 1265, 1268, 1271, 1274, 1276, 1279, 1282, 1285], - [1288, 1291, 1294, 1297, 1300, 1303, 1306, 1309, 1312, 1315], - [1318, 1321, 1324, 1327, 1330, 1334, 1337, 1340, 1343, 1346], - [1349, 1352, 1355, 1358, 1361, 1365, 1368, 1371, 1374, 1377], - [1380, 1384, 1387, 1390, 1393, 1396, 1400, 1403, 1406, 1409], - [1413, 1416, 1419, 1422, 1426, 1429, 1432, 1435, 1439, 1442], - [1445, 1449, 1452, 1455, 1459, 1462, 1466, 1469, 1472, 1476], - [1479, 1483, 1486, 1489, 1493, 1496, 1500, 1503, 1507, 1510], - [1514, 1517, 1521, 1524, 1528, 1531, 1535, 1538, 1542, 1545], - [1549, 1552, 1556, 1560, 1563, 1567, 1570, 1574, 1578, 1581], - [1585, 1589, 1592, 1596, 1600, 1603, 1607, 1611, 1614, 1618], - [1622, 1626, 1629, 1633, 1637, 1641, 1644, 1648, 1652, 1656], - [1660, 1663, 1667, 1671, 1675, 1679, 1683, 1687, 1690, 1694], - [1698, 1702, 1706, 1710, 1714, 1718, 1722, 1726, 1730, 1734], - [1738, 1742, 1746, 1750, 1754, 1758, 1762, 1766, 1770, 1774], - [1778, 1782, 1786, 1791, 1795, 1799, 1803, 1807, 1811, 1816], - [1820, 1824, 1828, 1832, 1837, 1841, 1845, 1849, 1854, 1858], - [1862, 1866, 1871, 1875, 1879, 1884, 1888, 1892, 1897, 1901], - [1905, 1910, 1914, 1919, 1923, 1928, 1932, 1936, 1941, 1945], - [1950, 1954, 1959, 1963, 1968, 1972, 1977, 1982, 1986, 1991], - [1995, 2000, 2004, 2009, 2014, 2018, 2023, 2028, 2032, 2037], - [2042, 2046, 2051, 2056, 2061, 2065, 2070, 2075, 2080, 2084], - [2089, 2094, 2099, 2104, 2109, 2113, 2118, 2123, 2128, 2133], - [2138, 2143, 2148, 2153, 2158, 2163, 2168, 2173, 2178, 2183], - [2188, 2193, 2198, 2203, 2208, 2213, 2218, 2223, 2228, 2234], - [2239, 2244, 2249, 2254, 2259, 2265, 2270, 2275, 2280, 2286], - [2291, 2296, 2301, 2307, 2312, 2317, 2323, 2328, 2333, 2339], - [2344, 2350, 2355, 2360, 2366, 2371, 2377, 2382, 2388, 2393], - [2399, 2404, 2410, 2415, 2421, 2427, 2432, 2438, 2443, 2449], - [2455, 2460, 2466, 2472, 2477, 2483, 2489, 2495, 2500, 2506], - [2512, 2518, 2523, 2529, 2535, 2541, 2547, 2553, 2559, 2564], - [2570, 2576, 2582, 2588, 2594, 2600, 2606, 2612, 2618, 2624], - [2630, 2636, 2642, 2649, 2655, 2661, 2667, 2673, 2679, 2685], - [2692, 2698, 2704, 2710, 2716, 2723, 2729, 2735, 2742, 2748], - [2754, 2761, 2767, 2773, 2780, 2786, 2793, 2799, 2805, 2812], - [2818, 2825, 2831, 2838, 2844, 2851, 2858, 2864, 2871, 2877], - [2884, 2891, 2897, 2904, 2911, 2917, 2924, 2931, 2938, 2944], - [2951, 2958, 2965, 2972, 2979, 2985, 2992, 2999, 3006, 3013], - [3020, 3027, 3034, 3041, 3048, 3055, 3062, 3069, 3076, 3083], - [3090, 3097, 3105, 3112, 3119, 3126, 3133, 3141, 3148, 3155], - [3162, 3170, 3177, 3184, 3192, 3199, 3206, 3214, 3221, 3228], - [3236, 3243, 3251, 3258, 3266, 3273, 3281, 3289, 3296, 3304], - [3311, 3319, 3327, 3334, 3342, 3350, 3357, 3365, 3373, 3381], - [3388, 3396, 3404, 3412, 3420, 3428, 3436, 3443, 3451, 3459], - [3467, 3475, 3483, 3491, 3499, 3508, 3516, 3524, 3532, 3540], - [3548, 3556, 3565, 3573, 3581, 3589, 3597, 3606, 3614, 3622], - [3631, 3639, 3648, 3656, 3664, 3673, 3681, 3690, 3698, 3707], - [3715, 3724, 3733, 3741, 3750, 3758, 3767, 3776, 3784, 3793], - [3802, 3811, 3819, 3828, 3837, 3846, 3855, 3864, 3873, 3882], - [3890, 3899, 3908, 3917, 3926, 3936, 3945, 3954, 3963, 3972], - [3981, 3990, 3999, 4009, 4018, 4027, 4036, 4046, 4055, 4064], - [4074, 4083, 4093, 4102, 4111, 4121, 4130, 4140, 4150, 4159], - [4169, 4178, 4188, 4198, 4207, 4217, 4227, 4236, 4246, 4256], - [4266, 4276, 4285, 4295, 4305, 4315, 4325, 4335, 4345, 4355], - [4365, 4375, 4385, 4395, 4406, 4416, 4426, 4436, 4446, 4457], - [4467, 4477, 4487, 4498, 4508, 4519, 4529, 4539, 4550, 4560], - [4571, 4581, 4592, 4603, 4613, 4624, 4634, 4645, 4656, 4667], - [4677, 4688, 4699, 4710, 4721, 4732, 4742, 4753, 4764, 4775], - [4786, 4797, 4808, 4819, 4831, 4842, 4853, 4864, 4875, 4887], - [4898, 4909, 4920, 4932, 4943, 4955, 4966, 4977, 4989, 5000], - [5012, 5023, 5035, 5047, 5058, 5070, 5082, 5093, 5105, 5117], - [5129, 5140, 5152, 5164, 5176, 5188, 5200, 5212, 5224, 5236], - [5248, 5260, 5272, 5284, 5297, 5309, 5321, 5333, 5346, 5358], - [5370, 5383, 5395, 5408, 5420, 5433, 5445, 5458, 5470, 5483], - [5495, 5508, 5521, 5534, 5546, 5559, 5572, 5585, 5598, 5610], - [5623, 5636, 5649, 5662, 5675, 5689, 5702, 5715, 5728, 5741], - [5754, 5768, 5781, 5794, 5808, 5821, 5834, 5848, 5861, 5875], - [5888, 5902, 5916, 5929, 5943, 5957, 5970, 5984, 5998, 6012], - [6026, 6039, 6053, 6067, 6081, 6095, 6109, 6124, 6138, 6152], - [6166, 6180, 6194, 6209, 6223, 6237, 6252, 6266, 6281, 6295], - [6310, 6324, 6339, 6353, 6368, 6383, 6397, 6412, 6427, 6442], - [6457, 6471, 6486, 6501, 6516, 6531, 6546, 6561, 6577, 6592], - [6607, 6622, 6637, 6653, 6668, 6683, 6699, 6714, 6730, 6745], - [6761, 6776, 6792, 6808, 6823, 6839, 6855, 6871, 6887, 6902], - [6918, 6934, 6950, 6966, 6982, 6998, 7015, 7031, 7047, 7063], - [7079, 7096, 7112, 7129, 7145, 7161, 7178, 7194, 7211, 7228], - [7244, 7261, 7278, 7295, 7311, 7328, 7345, 7362, 7379, 7396], - [7413, 7430, 7447, 7464, 7482, 7499, 7516, 7534, 7551, 7568], - [7586, 7603, 7621, 7638, 7656, 7674, 7691, 7709, 7727, 7745], - [7762, 7780, 7798, 7816, 7834, 7852, 7870, 7889, 7907, 7925], - [7943, 7962, 7980, 7998, 8017, 8035, 8054, 8072, 8091, 8110], - [8128, 8147, 8166, 8185, 8204, 8222, 8241, 8260, 8279, 8299], - [8318, 8337, 8356, 8375, 8395, 8414, 8433, 8453, 8472, 8492], - [8511, 8531, 8551, 8570, 8590, 8610, 8630, 8650, 8670, 8690], - [8710, 8730, 8750, 8770, 8790, 8810, 8831, 8851, 8872, 8892], - [8913, 8933, 8954, 8974, 8995, 9016, 9036, 9057, 9078, 9099], - [9120, 9141, 9162, 9183, 9204, 9226, 9247, 9268, 9290, 9311], - [9333, 9354, 9376, 9397, 9419, 9441, 9462, 9484, 9506, 9528], - [9550, 9572, 9594, 9616, 9638, 9661, 9683, 9705, 9727, 9750], - [9772, 9795, 9817, 9840, 9863, 9886, 9908, 9931, 9954, 9977], - ] - } +/// `LibLogTable.antiLogTableDec()`. +pub fn anti_log_table_dec() -> Result<[[u16; 10]; 100], FloatError> { + read(TestDecimalFloat::antiLogTableDecCall {}) +} - #[rustfmt::skip] - fn solidity_antilog_table_small() -> [[u8; 10]; 100] { - [ - [0, 0, 0, 1, 1, 1, 1, 2, 2, 2], [0, 0, 0, 1, 1, 1, 1, 2, 2, 2], - [0, 0, 0, 1, 1, 1, 1, 2, 2, 2], [0, 0, 0, 1, 1, 1, 1, 2, 2, 2], - [0, 0, 1, 1, 1, 1, 2, 2, 2, 2], [0, 0, 1, 1, 1, 1, 2, 2, 2, 2], - [0, 0, 1, 1, 1, 1, 2, 2, 2, 2], [0, 0, 1, 1, 1, 1, 2, 2, 2, 2], - [0, 0, 1, 1, 1, 1, 2, 2, 2, 3], [0, 0, 1, 1, 1, 1, 2, 2, 2, 3], - [0, 0, 1, 1, 1, 1, 2, 2, 2, 3], [0, 0, 1, 1, 1, 2, 2, 2, 2, 3], - [0, 0, 1, 1, 1, 2, 2, 2, 2, 3], [0, 0, 1, 1, 1, 2, 2, 2, 3, 3], - [0, 0, 1, 1, 1, 2, 2, 2, 3, 3], [0, 0, 1, 1, 1, 2, 2, 2, 3, 3], - [0, 0, 1, 1, 1, 2, 2, 2, 3, 3], [0, 0, 1, 1, 1, 2, 2, 2, 3, 3], - [0, 0, 1, 1, 1, 2, 2, 2, 3, 3], [0, 0, 1, 1, 1, 2, 2, 3, 3, 3], - [0, 0, 1, 1, 1, 2, 2, 3, 3, 3], [0, 0, 1, 1, 2, 2, 2, 3, 3, 3], - [0, 0, 1, 1, 2, 2, 2, 3, 3, 3], [0, 0, 1, 1, 2, 2, 2, 3, 3, 4], - [0, 0, 1, 1, 2, 2, 2, 3, 3, 4], [0, 0, 1, 1, 2, 2, 2, 3, 3, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 3, 4], [0, 0, 1, 1, 2, 2, 3, 3, 3, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], - [0, 1, 1, 2, 2, 3, 3, 4, 4, 5], [0, 1, 1, 2, 2, 3, 3, 4, 5, 5], - [0, 1, 1, 2, 2, 3, 4, 4, 5, 5], [0, 1, 1, 2, 2, 3, 4, 4, 5, 5], - [0, 1, 1, 2, 2, 3, 4, 4, 5, 6], [0, 1, 1, 2, 3, 3, 4, 4, 5, 6], - [0, 1, 1, 2, 3, 3, 4, 4, 5, 6], [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], - [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], [0, 1, 1, 2, 3, 3, 4, 5, 5, 6], - [0, 1, 1, 2, 3, 4, 4, 5, 6, 6], [0, 1, 1, 2, 3, 4, 4, 5, 6, 6], - [0, 1, 1, 2, 3, 4, 4, 5, 6, 7], [0, 1, 2, 2, 3, 4, 5, 5, 6, 7], - [0, 1, 2, 2, 3, 4, 5, 5, 6, 7], [0, 1, 2, 2, 3, 4, 5, 6, 6, 7], - [0, 1, 2, 2, 3, 4, 5, 6, 6, 7], [0, 1, 2, 2, 3, 4, 5, 6, 7, 7], - [0, 1, 2, 3, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 3, 4, 5, 6, 7, 8], - [0, 1, 2, 3, 4, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 5, 6, 7, 8], - [0, 1, 2, 3, 4, 5, 6, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 9, 10], [0, 1, 2, 3, 4, 5, 7, 8, 9, 10], - [0, 1, 2, 3, 4, 6, 7, 8, 9, 10], [0, 1, 2, 3, 5, 6, 7, 8, 9, 10], - [0, 1, 2, 4, 5, 6, 7, 8, 9, 11], - [0, 1, 2, 4, 5, 6, 7, 8, 10, 11], [0, 1, 2, 4, 5, 6, 7, 9, 10, 11], - [0, 1, 3, 4, 5, 6, 8, 9, 10, 11], [0, 1, 3, 4, 5, 6, 8, 9, 10, 12], - [0, 1, 3, 4, 5, 7, 8, 9, 10, 12], [0, 1, 3, 4, 5, 7, 8, 9, 11, 12], - [0, 1, 3, 4, 5, 7, 8, 10, 11, 12], [0, 1, 3, 4, 6, 7, 8, 10, 11, 13], - [0, 1, 3, 4, 6, 7, 9, 10, 11, 13], [0, 1, 3, 4, 6, 7, 9, 10, 12, 13], - [0, 2, 3, 5, 6, 8, 9, 11, 12, 14], [0, 2, 3, 5, 6, 8, 9, 11, 12, 14], - [0, 2, 3, 5, 6, 8, 9, 11, 13, 14], [0, 2, 3, 5, 6, 8, 10, 11, 13, 15], - [0, 2, 3, 5, 7, 8, 10, 12, 13, 15], [0, 2, 3, 5, 7, 8, 10, 12, 13, 15], - [0, 2, 3, 5, 7, 9, 10, 12, 14, 16], [0, 2, 4, 5, 7, 9, 11, 12, 14, 16], - [0, 2, 4, 5, 7, 9, 11, 13, 14, 16], [0, 2, 4, 6, 7, 9, 11, 13, 15, 17], - [0, 2, 4, 6, 8, 9, 11, 13, 15, 17], [0, 2, 4, 6, 8, 10, 12, 14, 15, 17], - [0, 2, 4, 6, 8, 10, 12, 14, 16, 18], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18], - [0, 2, 4, 6, 8, 10, 12, 15, 17, 19], [0, 2, 4, 6, 8, 11, 13, 15, 17, 19], - [0, 2, 4, 7, 9, 11, 13, 15, 17, 20], [0, 2, 4, 7, 9, 11, 13, 16, 18, 20], - [0, 2, 5, 7, 9, 11, 14, 16, 18, 20], - ] - } +/// `LibLogTable.antiLogTableDecSmall()`. +pub fn anti_log_table_dec_small() -> Result<[[u8; 10]; 100], FloatError> { + read(TestDecimalFloat::antiLogTableDecSmallCall {}) } diff --git a/test/concrete/TestDecimalFloat.sol b/test/concrete/TestDecimalFloat.sol index 3ca81bd..5b3f7c5 100644 --- a/test/concrete/TestDecimalFloat.sol +++ b/test/concrete/TestDecimalFloat.sol @@ -3,25 +3,43 @@ pragma solidity =0.8.25; import {LibDecimalFloat, Float} from "rain-math-float-0.1.7/src/lib/LibDecimalFloat.sol"; +import {LibLogTable, ALT_TABLE_FLAG} from "rain-math-float-0.1.7/src/lib/table/LibLogTable.sol"; -/// Additional exposed functions for testing the internals of floats -/// from downstream environments, e.g. rust. +/// Exposes the library internals the Rust bindings' tests need beside the +/// `DecimalFloat` ABI: packing, and the log tables as `LibLogTable` ships +/// them. contract TestDecimalFloat { using LibDecimalFloat for Float; - /// Exposes `LibDecimalFloat.packLossless` for offchain use. - /// @param coefficient The coefficient to pack. - /// @param exponent The exponent to pack. - /// @return The packed float. function packLossless(int224 coefficient, int32 exponent) external pure returns (Float) { return LibDecimalFloat.packLossless(coefficient, exponent); } - /// Exposes `LibDecimalFloat.unpack` for offchain use. - /// @param float The float to unpack. - /// @return coefficient The coefficient of the float. - /// @return exponent The exponent of the float. function unpack(Float float) external pure returns (int256, int256) { return LibDecimalFloat.unpack(float); } + + function altTableFlag() external pure returns (uint16) { + return ALT_TABLE_FLAG; + } + + function logTableDec() external pure returns (uint16[10][90] memory) { + return LibLogTable.logTableDec(); + } + + function logTableDecSmall() external pure returns (uint8[10][90] memory) { + return LibLogTable.logTableDecSmall(); + } + + function logTableDecSmallAlt() external pure returns (uint8[10][10] memory) { + return LibLogTable.logTableDecSmallAlt(); + } + + function antiLogTableDec() external pure returns (uint16[10][100] memory) { + return LibLogTable.antiLogTableDec(); + } + + function antiLogTableDecSmall() external pure returns (uint8[10][100] memory) { + return LibLogTable.antiLogTableDecSmall(); + } } From 940ba9991c91a9831c8248ffe60c1647ef6012f9 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 16:28:48 +0000 Subject: [PATCH 2/4] Drop the library-logic tests that now run in rain.math.float The crate keeps the tests of its own Rust API: Default, serde, the hex round-trip and error rendering. The proptest seeds went with the tests. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- .../float/proptest-regressions/fuzz_ops.txt | 8 - crates/float/proptest-regressions/lib.txt | 8 - crates/float/src/fuzz_ops.rs | 306 ------------------ 3 files changed, 322 deletions(-) delete mode 100644 crates/float/proptest-regressions/fuzz_ops.txt delete mode 100644 crates/float/proptest-regressions/lib.txt delete mode 100644 crates/float/src/fuzz_ops.rs diff --git a/crates/float/proptest-regressions/fuzz_ops.txt b/crates/float/proptest-regressions/fuzz_ops.txt deleted file mode 100644 index 6ecefab..0000000 --- a/crates/float/proptest-regressions/fuzz_ops.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 285e4d87fcb0e9c1757a0ddf5aa8199fbd17d38208bd0b5ef2288d059eb3934e # shrinks to a = Float(0xffffffff000000000000000000000000000000000000000000009a9939ef8c94) -cc cb8c50af037a017c4a91ac6dede4b4fc2e1372a1de1290ac8fafc546772613d0 # shrinks to a = Float(0xfffffffeffffffffffffffffffffffffffffffffffffffffffffba63064a71d9) diff --git a/crates/float/proptest-regressions/lib.txt b/crates/float/proptest-regressions/lib.txt deleted file mode 100644 index 7070cb9..0000000 --- a/crates/float/proptest-regressions/lib.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 664cbb4a3416dcc12fe1196bdf33bdf3f9e1403c6446f0516dc704da23be5723 # shrinks to a = Float(0x0000000000000000000000000000000000000000000000000000000000000000), b = Float(0xffffffff00000000000000000000000000000000000000000000000000000001) -cc 3fd2457aad2f1f4960353eb70458c7806f645c48898d3d336369b396c6cd13e1 # shrinks to a = Float(0x000000000000000000000000000000000000000000000000534a0c3580000000), b = Float(0x00000000000000000000000000000000000000000000000008e5c21900000000) diff --git a/crates/float/src/fuzz_ops.rs b/crates/float/src/fuzz_ops.rs deleted file mode 100644 index 4c28f78..0000000 --- a/crates/float/src/fuzz_ops.rs +++ /dev/null @@ -1,306 +0,0 @@ -#[cfg(test)] -mod tests { - use crate::Float; - use alloy::primitives::{aliases::I224, I256}; - use proptest::prelude::*; - - /// Convert a Solidity Float to f64 via unpack. - fn sol_to_f64(f: Float) -> Option { - let (coeff, exp) = f.unpack().ok()?; - let c: f64 = i256_to_f64(coeff); - let e: i32 = exp.as_i32(); - Some(c * 10.0_f64.powi(e)) - } - - fn i256_to_f64(v: I256) -> f64 { - if v.is_negative() { - let abs = (!v).wrapping_add(I256::ONE); - -(u256_to_f64(abs.into_raw())) - } else { - u256_to_f64(v.into_raw()) - } - } - - fn u256_to_f64(v: alloy::primitives::U256) -> f64 { - // Convert U256 to f64 via string parsing for accuracy. - v.to_string().parse::().unwrap_or(f64::INFINITY) - } - - // Generate floats in a range where f64 can represent them without - // overflow/underflow. Coefficients up to ~1e15 and exponents -15..15 - // keep values in f64's comfortable range. - prop_compose! { - fn f64_compatible_float()( - coefficient in -10i64.pow(15)..10i64.pow(15), - exponent in -15i32..15i32, - ) -> Float { - Float::pack_lossless( - I224::try_from(coefficient).unwrap(), - exponent, - ).unwrap() - } - } - - /// Check that two f64 values are approximately equal, allowing for - /// f64 rounding errors. Returns true if they're within a relative - /// tolerance of 1e-10 or both are effectively zero. - fn approx_eq(a: f64, b: f64) -> bool { - if a == b { - return true; - } - if a.is_nan() || b.is_nan() { - return false; - } - let max_abs = a.abs().max(b.abs()); - if max_abs < 1e-30 { - return true; - } - ((a - b).abs() / max_abs) < 1e-10 - } - - proptest! { - #[test] - fn fuzz_add( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let sol_result = (a + b).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let b_f64 = sol_to_f64(b).unwrap(); - let expected = a_f64 + b_f64; - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "add: {a_f64} + {b_f64} = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_sub( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let sol_result = (a - b).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let b_f64 = sol_to_f64(b).unwrap(); - let expected = a_f64 - b_f64; - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "sub: {a_f64} - {b_f64} = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_mul( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let sol_result = (a * b).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let b_f64 = sol_to_f64(b).unwrap(); - let expected = a_f64 * b_f64; - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "mul: {a_f64} * {b_f64} = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_div( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let b_f64 = sol_to_f64(b).unwrap(); - // Skip division by zero. - prop_assume!(b_f64.abs() > 1e-30); - - let sol_result = (a / b).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let expected = a_f64 / b_f64; - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "div: {a_f64} / {b_f64} = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_neg(a in f64_compatible_float()) { - let sol_result = (-a).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let expected = -a_f64; - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "neg: -{a_f64} = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_abs(a in f64_compatible_float()) { - let sol_result = a.abs().unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let expected = a_f64.abs(); - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "abs: |{a_f64}| = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_inv(a in f64_compatible_float()) { - let a_f64 = sol_to_f64(a).unwrap(); - // Skip values too close to zero. - prop_assume!(a_f64.abs() > 1e-10); - - let sol_result = a.inv().unwrap(); - let expected = 1.0 / a_f64; - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "inv: 1/{a_f64} = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_floor(a in f64_compatible_float()) { - let a_f64 = sol_to_f64(a).unwrap(); - let sol_result = a.floor().unwrap(); - let expected = a_f64.floor(); - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "floor: floor({a_f64}) = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_integer(a in f64_compatible_float()) { - let a_f64 = sol_to_f64(a).unwrap(); - let sol_result = a.integer().unwrap(); - let expected = a_f64.trunc(); - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "integer: trunc({a_f64}) = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_frac( - coefficient in -10i64.pow(10)..10i64.pow(10), - exponent in -5i32..0i32, - ) { - let a = Float::pack_lossless( - I224::try_from(coefficient).unwrap(), - exponent, - ).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let sol_result = a.frac().unwrap(); - let expected = a_f64.fract(); - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - (expected - actual).abs() < 1e-6, - "frac: fract({a_f64}) = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_min( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let sol_result = a.min(b).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let b_f64 = sol_to_f64(b).unwrap(); - let expected = a_f64.min(b_f64); - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "min: min({a_f64}, {b_f64}) = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_max( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let sol_result = a.max(b).unwrap(); - let a_f64 = sol_to_f64(a).unwrap(); - let b_f64 = sol_to_f64(b).unwrap(); - let expected = a_f64.max(b_f64); - let actual = sol_to_f64(sol_result).unwrap(); - prop_assert!( - approx_eq(expected, actual), - "max: max({a_f64}, {b_f64}) = {expected}, sol = {actual}", - ); - } - - #[test] - fn fuzz_is_zero(a in f64_compatible_float()) { - let a_f64 = sol_to_f64(a).unwrap(); - let sol_result = a.is_zero().unwrap(); - let expected = a_f64 == 0.0; - prop_assert!( - sol_result == expected, - "is_zero: is_zero({}) = {}, sol = {}", - a_f64, expected, sol_result - ); - } - - #[test] - fn fuzz_fixed_decimal_round_trip( - coefficient in 0i64..10i64.pow(15), - decimals in 0u8..18u8, - ) { - use alloy::primitives::U256; - let value = U256::from(coefficient as u64); - // Convert to float and back. - let float = Float::from_fixed_decimal(value, decimals); - prop_assume!(float.is_ok()); - let float = float.unwrap(); - let (back, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); - if lossless { - prop_assert!( - back == value, - "round-trip failed: {} with {} decimals, got {}", - coefficient, decimals, back - ); - } - } - - #[test] - fn fuzz_comparisons( - a in f64_compatible_float(), - b in f64_compatible_float(), - ) { - let a_f64 = sol_to_f64(a).unwrap(); - let b_f64 = sol_to_f64(b).unwrap(); - - // Only test comparisons when values are far enough apart - // that f64 precision issues don't cause false failures. - let diff = (a_f64 - b_f64).abs(); - let max_abs = a_f64.abs().max(b_f64.abs()); - prop_assume!(diff > max_abs * 1e-10 || diff < 1e-30); - - let sol_lt = a.lt(b).unwrap(); - let sol_gt = a.gt(b).unwrap(); - let sol_eq = a.eq(b).unwrap(); - - if diff < 1e-30 { - // Both effectively zero. - prop_assert!(sol_eq, "eq: {a_f64} == {b_f64} should be true"); - } else if a_f64 < b_f64 { - prop_assert!(sol_lt, "lt: {a_f64} < {b_f64} should be true"); - prop_assert!(!sol_gt, "gt: {a_f64} > {b_f64} should be false"); - } else { - prop_assert!(sol_gt, "gt: {a_f64} > {b_f64} should be true"); - prop_assert!(!sol_lt, "lt: {a_f64} < {b_f64} should be false"); - } - } - } -} From d1d86a9df64387faedc41b0f3306411b3258fef3 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Mon, 7 Sep 2026 16:29:21 +0000 Subject: [PATCH 3/4] Drop the moved test module bodies from lib.rs Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- crates/float/src/lib.rs | 974 ---------------------------------------- 1 file changed, 974 deletions(-) diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 6b283f5..4670e80 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -11,7 +11,6 @@ use alloy::primitives::aliases::I224; pub mod error; mod evm; -mod fuzz_ops; pub mod js_api; #[cfg(any(test, feature = "test-harness"))] pub mod tables; @@ -1285,13 +1284,9 @@ impl From for B256 { value.0 } } - #[cfg(test)] mod tests { - use crate::DecimalFloat::DecimalFloatErrors; - use super::*; - use core::str::FromStr; use proptest::prelude::*; use serde_json::json; @@ -1302,21 +1297,6 @@ mod tests { assert!(zero.eq(Float::default()).unwrap()); } - /// Float::zero() is_zero, formats as "0", equals parsed "0" and default. - #[test] - fn test_zero() { - let zero = Float::zero().unwrap(); - assert!(zero.is_zero().unwrap()); - assert_eq!(zero.format().unwrap(), "0"); - - // Test that zero equals parsed zero - let parsed_zero = Float::parse("0".to_string()).unwrap(); - assert!(zero.eq(parsed_zero).unwrap()); - - // Test that zero equals default - assert!(zero.eq(Float::default()).unwrap()); - } - prop_compose! { fn arb_float()( coefficient in any::(), @@ -1326,21 +1306,6 @@ mod tests { } } - prop_compose! { - fn reasonable_float()( - int_part in -10i128.pow(18)..10i128.pow(18), - decimal_part in 0u128..10u128.pow(18u32) - ) -> Float { - let num_str = if decimal_part == 0 { - format!("{int_part}") - } else { - format!("{int_part}.{decimal_part}") - }; - - Float::parse(num_str).unwrap() - } - } - /// JSON serialize then deserialize preserves equality and hex representation. #[test] fn test_serde() { @@ -1366,95 +1331,6 @@ mod tests { } } - /// Parsing an empty string returns a DecimalFloatSelector error. - #[test] - fn test_parse_empty_string_error() { - let err = Float::parse("".to_string()).unwrap_err(); - // We don't know the exact selector here, just ensure the error path is hit. - assert!(matches!(err, FloatError::DecimalFloatSelector(_))); - } - - #[test] - fn test_parse_exponent_overflow_error() { - // Extremely large exponent expected to overflow (exponent >> i32::MAX). - let err = Float::parse("1e3000000000".to_string()).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) - )); - } - - /// Malformed inputs ("1.2.3", "abc") return specific error selectors. - #[test] - fn test_parse_edge_cases() { - let err = Float::parse("1.2.3".to_string()).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloatSelector(Err(selector)) - if selector == fixed_bytes!("ad384e87") - )); - - let err = Float::parse("abc".to_string()).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloatSelector(Err(selector)) - if selector == fixed_bytes!("34bd2069") - )); - } - - /// Boundary constants are distinct, correctly signed, correctly ordered, - /// and bound normal values like 1 and -1. - #[test] - fn test_float_constants() { - // Test that all constant methods return valid floats - let max_pos = Float::max_positive_value().unwrap(); - let min_pos = Float::min_positive_value().unwrap(); - let max_neg = Float::max_negative_value().unwrap(); - let min_neg = Float::min_negative_value().unwrap(); - - let zero = Float::parse("0".to_string()).unwrap(); - - // Test mathematical properties without exposing binary representation - - // All constants should be distinct - assert!(!max_pos.eq(min_pos).unwrap()); - assert!(!max_neg.eq(min_neg).unwrap()); - assert!(!max_pos.eq(max_neg).unwrap()); - assert!(!min_pos.eq(min_neg).unwrap()); - - // Test sign properties - assert!(min_pos.gt(zero).unwrap()); // min positive should be > 0 - assert!(max_pos.gt(zero).unwrap()); // max positive should be > 0 - assert!(max_neg.lt(zero).unwrap()); // max negative should be < 0 - assert!(min_neg.lt(zero).unwrap()); // min negative should be < 0 - - // Test ordering relationships - assert!(min_pos.lt(max_pos).unwrap()); // min positive < max positive - assert!(min_neg.lt(max_neg).unwrap()); // min negative < max negative - - // Test boundary properties - let one = Float::parse("1".to_string()).unwrap(); - let neg_one = Float::parse("-1".to_string()).unwrap(); - - // Positive constants should be greater than normal values - assert!(max_pos.gt(one).unwrap()); - assert!(min_pos.lt(one).unwrap()); - - // Negative constants should be more extreme than normal negative values - assert!(max_neg.gt(neg_one).unwrap()); - assert!(min_neg.lt(neg_one).unwrap()); - } - - proptest! { - #[test] - /// format() then parse() round-trips to an equal value. - fn test_format_parse(float in reasonable_float()) { - let formatted = float.format().unwrap(); - let parsed = Float::parse(formatted.clone()).unwrap(); - prop_assert!(float.eq(parsed).unwrap()); - } - } - proptest! { #[test] /// as_hex() then from_hex() round-trips to identical hex. @@ -1464,854 +1340,4 @@ mod tests { prop_assert_eq!(parsed.as_hex(), hex); } } - - /// Adding two max-exponent floats overflows with ExponentOverflow. - #[test] - fn test_add_exponent_overflow_error() { - let max_coeff_str = "13479973333575319897333507543509815336818572211270286240551805124607"; - let large_coeff_i224 = I224::from_str(max_coeff_str).unwrap(); - let exponent_max = i32::MAX; - - let a = Float::pack_lossless(large_coeff_i224, exponent_max).unwrap(); - - let err = (a + a).unwrap_err(); - - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) - )); - } - - /// Subtracting opposite-sign max-exponent floats overflows. - #[test] - fn test_sub_exponent_overflow_error() { - let max_coeff_str = "13479973333575319897333507543509815336818572211270286240551805124607"; - let large_coeff_i224 = I224::from_str(max_coeff_str).unwrap(); - let exponent_max = i32::MAX; - - let a = Float::pack_lossless(large_coeff_i224, exponent_max).unwrap(); - let b = Float::pack_lossless(-large_coeff_i224, exponent_max).unwrap(); - - let err = (b - a).unwrap_err(); - - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) - )); - } - - proptest! { - #[test] - /// Addition does not panic for reasonable inputs. - fn test_add(a in reasonable_float(), b in reasonable_float()) { - (a + b).unwrap(); - } - } - - proptest! { - #[test] - /// Subtraction does not panic for reasonable inputs. - fn test_sub(a in reasonable_float(), b in reasonable_float()) { - (a - b).unwrap(); - } - } - - proptest! { - #[test] - /// (a + b) - b == a: subtraction inverts addition. - fn test_add_sub(a in reasonable_float(), b in reasonable_float()) { - let sum = (a + b).unwrap(); - let diff = (sum - b).unwrap(); - prop_assert_eq!( - a.format().unwrap(), - diff.format().unwrap(), - "a: {}, b: {}", - a.format().unwrap(), - b.format().unwrap(), - ); - } - } - - /// Manual check: -1 < 0 < 3, with correct lt/eq/gt for each pair. - #[test] - fn test_lt_eq_gt() { - let negone = Float::parse("-1".to_string()).unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - let three = Float::parse("3".to_string()).unwrap(); - - assert!(negone.lt(zero).unwrap()); - assert!(!negone.eq(zero).unwrap()); - assert!(!negone.gt(zero).unwrap()); - - assert!(!three.lt(zero).unwrap()); - assert!(!three.eq(zero).unwrap()); - assert!(three.gt(zero).unwrap()); - - assert!(zero.lt(three).unwrap()); - assert!(!zero.eq(three).unwrap()); - assert!(!zero.gt(three).unwrap()); - } - - proptest! { - #[test] - /// a == a, a-1 < a, a+1 > a for all reasonable floats. - fn test_lt_eq_gt_with_add(a in reasonable_float()) { - let b = a; - let eq = a.eq(b).unwrap(); - prop_assert!(eq); - - let one = Float::parse("1".to_string()).unwrap(); - - let a = (a - one).unwrap(); - let lt = a.lt(b).unwrap(); - prop_assert!(lt); - - let a = (a + one).unwrap(); - let eq = a.eq(b).unwrap(); - prop_assert!(eq); - - let a = (a + one).unwrap(); - let gt = a.gt(b).unwrap(); - prop_assert!(gt); - } - - #[test] - /// Trichotomy: exactly one of lt, eq, gt is true for any two floats. - fn test_exactly_one_lt_eq_gt(a in arb_float(), b in arb_float()) { - let eq = a.eq(b).unwrap(); - let lt = a.lt(b).unwrap(); - let gt = a.gt(b).unwrap(); - - let a_str = a.show_unpacked().unwrap(); - let b_str = b.show_unpacked().unwrap(); - - prop_assert!(lt || eq || gt, "a: {a_str}, b: {b_str}"); - prop_assert!(!(lt && eq), "both less than and equal: a: {a_str}, b: {b_str}"); - prop_assert!(!(eq && gt), "both equal and greater than: a: {a_str}, b: {b_str}"); - prop_assert!(!(lt && gt), "both less than and greater than: a: {a_str}, b: {b_str}"); - } - } - - /// abs(-x) == abs(x) == |x| for manual positive, negative, and zero cases. - #[test] - fn test_abs() { - let float = Float::parse("-3613.1324123".to_string()).unwrap(); - let abs = float.abs().unwrap(); - let formatted = abs.format().unwrap(); - assert_eq!(formatted, "3613.1324123"); - - let float = Float::parse("3613.1324123".to_string()).unwrap(); - let abs = float.abs().unwrap(); - let formatted = abs.format().unwrap(); - assert_eq!(formatted, "3613.1324123"); - - let float = Float::parse("0".to_string()).unwrap(); - let abs = float.abs().unwrap(); - let formatted = abs.format().unwrap(); - assert_eq!(formatted, "0"); - } - - proptest! { - #[test] - /// Multiplication does not panic for reasonable inputs. - fn test_mul(a in reasonable_float(), b in reasonable_float()) { - (a * b).unwrap(); - } - } - - /// Negating a negative produces positive format; negating zero stays "0". - #[test] - fn test_minus_format() { - let float = Float::parse("-123.1234234625468391".to_string()).unwrap(); - let negated = float.neg().unwrap(); - - let formatted_decimal = negated.format_with_scientific(false).unwrap(); - assert_eq!(formatted_decimal, "123.1234234625468391"); - - let float = Float::parse("0".to_string()).unwrap(); - let negated = float.neg().unwrap(); - let formatted = negated.format().unwrap(); - assert_eq!(formatted, "0"); - } - - proptest! { - #[test] - /// Double negation is identity: -(-a) == a. - fn test_minus_minus(float in arb_float()) { - let negated = float.neg().unwrap(); - let renegated = negated.neg().unwrap(); - prop_assert!(float.eq(renegated).unwrap()); - } - } - - proptest! { - #[test] - /// a * inv(a) ≈ 1 within ±1e-37 for nonzero a. - fn test_inv_prod(float in reasonable_float()) { - let zero = Float::parse("0".to_string()).unwrap(); - prop_assume!(!float.eq(zero).unwrap()); - - let inv = float.inv().unwrap(); - let product = (float * inv).unwrap(); - let one = Float::parse("1".to_string()).unwrap(); - - // Allow for minor rounding errors introduced by the lossy - // `inv` implementation. We consider the property to - // hold if the product is within `±1e-37` of 1. - - let eps = Float::parse("1e-37".to_string()).unwrap(); - let one_plus_eps = (one + eps).unwrap(); - let one_minus_eps = (one - eps).unwrap(); - - let within_upper = !product.gt(one_plus_eps).unwrap(); - let within_lower = !product.lt(one_minus_eps).unwrap(); - - prop_assert!( - within_upper && within_lower, - "float: {}, inv: {}, product: {} (not within ±ε)", - float.show_unpacked().unwrap(), - inv.show_unpacked().unwrap(), - product.show_unpacked().unwrap(), - ); - } - } - - proptest! { - #[test] - /// abs() never produces a string starting with "-". - fn test_abs_no_minus_sign(float in reasonable_float()) { - let abs = float.abs().unwrap(); - let formatted = abs.format().unwrap(); - prop_assert!(!formatted.starts_with("-")); - } - - #[test] - /// abs is idempotent: abs(abs(a)) == abs(a). - fn test_abs_abs(float in arb_float()) { - let abs = float.abs().unwrap(); - let abs_abs = abs.abs().unwrap(); - prop_assert!(abs.eq(abs_abs).unwrap()); - } - } - - proptest! { - #[test] - /// Division does not panic for nonzero divisor. - fn test_div(a in reasonable_float(), b in reasonable_float()) { - let zero = Float::parse("0".to_string()).unwrap(); - prop_assume!(!b.eq(zero).unwrap()); - - (a / b).unwrap(); - } - } - - prop_compose! { - fn small_int_float()(int_part in -1_000_000_000_000i128..1_000_000_000_000i128) -> Float { - Float::parse(int_part.to_string()).unwrap() - } - } - - proptest! { - #[test] - /// (a * b) / b == a: division inverts multiplication for small integers. - fn test_mul_div_int(a in small_int_float(), b in small_int_float()) { - let zero = Float::parse("0".to_string()).unwrap(); - prop_assume!(!b.eq(zero).unwrap()); - - let product = (a * b).unwrap(); - let quotient = (product / b).unwrap(); - - prop_assert!( - a.eq(quotient).unwrap(), - "a: {}, quotient: {}, b: {}", - a.show_unpacked().unwrap(), - quotient.show_unpacked().unwrap(), - b.show_unpacked().unwrap() - ); - } - } - - /// 6/3 == 2 and 2*3 == 6. - #[test] - fn test_mul_div_manual() { - let two = Float::parse("2".to_string()).unwrap(); - let three = Float::parse("3".to_string()).unwrap(); - let six = Float::parse("6".to_string()).unwrap(); - - assert!(two.eq((six / three).unwrap()).unwrap()); - assert!(six.eq((two * three).unwrap()).unwrap()); - } - - /// 1/0 returns DivisionByZero error. - #[test] - fn test_divide_by_zero_error() { - let one = Float::parse("1".to_string()).unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - let err = (one / zero).unwrap_err(); - - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::DivisionByZero(_)) - )); - } - - /// Multiplying near-max exponents overflows. - #[test] - fn test_mul_exponent_overflow_error() { - let near_max_exp = Float::parse("1e2147483646".to_string()).unwrap(); - let one_e_two = Float::parse("1e2".to_string()).unwrap(); - - let err = (near_max_exp * one_e_two).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) - )); - } - - /// Dividing near-max exponent by small exponent overflows. - #[test] - fn test_div_exponent_overflow_error() { - let near_max_exp = Float::parse("1e2147483646".to_string()).unwrap(); - let one_e_neg_hundred = Float::parse("1e-100".to_string()).unwrap(); - - let err = (near_max_exp / one_e_neg_hundred).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentOverflow(_)) - )); - } - - /// Multiplying near-min exponents underflows; the public arithmetic - /// surface reverts with `ExponentUnderflow` rather than silently - /// producing zero. - #[test] - fn test_mul_exponent_underflow_error() { - let near_min_exp = Float::parse("1e-2147483646".to_string()).unwrap(); - let one_e_neg_three = Float::parse("1e-3".to_string()).unwrap(); - - let err = (near_min_exp * one_e_neg_three).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::ExponentUnderflow(_)) - )); - } - - /// from_fixed_decimal for known value/decimals pairs matches parsed strings. - #[test] - fn test_from_fixed_decimal() { - let cases = vec![ - (U256::from(0u128), 0u8, "0"), - (U256::from(0u128), 18u8, "0"), - (U256::from(1u128), 18u8, "1e-18"), - (U256::from(123456789u128), 0u8, "123456789"), - (U256::from(123456789u128), 2u8, "123456789e-2"), - (U256::from(1000000000000000000u128), 18u8, "1"), - ]; - - for (amount, decimals, expected) in cases { - let float = Float::from_fixed_decimal(amount, decimals).expect("should convert"); - let expected = Float::parse(expected.to_string()).unwrap(); - assert!(float.eq(expected).unwrap()); - } - } - - /// U256::MAX with 1 decimal overflows (LossyConversionToFloat). - #[test] - fn test_from_fixed_decimal_err() { - let err = Float::from_fixed_decimal(U256::MAX, 1).unwrap_err(); - assert!(matches!( - err, - FloatError::DecimalFloat(e) if matches!(*e, DecimalFloatErrors::LossyConversionToFloat(_)) - )); - } - - /// to_fixed_decimal for known inputs matches expected U256 values. - #[test] - fn test_to_fixed_decimal() { - let cases = vec![ - ("0", 0u8, 0u128), - ("0", 18u8, 0u128), - ("1e-18", 18u8, 1u128), - ("123456789", 0u8, 123456789u128), - ("123456789e-2", 2u8, 123456789u128), - ("1", 18u8, 1000000000000000000u128), - ]; - - for (input, decimals, expected) in cases { - let float = Float::parse(input.to_string()).unwrap(); - let fixed = float.to_fixed_decimal(decimals).unwrap(); - assert_eq!(fixed, U256::from(expected)); - } - } - - /// For integers: floor == self, frac == 0, and floor + frac == self. - #[test] - fn test_frac_and_floor_integers() { - let int_float = Float::parse("12345".to_string()).unwrap(); - let floor = int_float.floor().unwrap(); - let frac = int_float.frac().unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - - assert!(int_float.eq(floor).unwrap()); - assert!(frac.eq(zero).unwrap()); - - let int_float = Float::parse("-98765".to_string()).unwrap(); - let floor = int_float.floor().unwrap(); - let frac = int_float.frac().unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - - assert!(int_float.eq(floor).unwrap()); - assert!(frac.eq(zero).unwrap()); - - let recombined = (floor + frac).unwrap(); - assert!(int_float.eq(recombined).unwrap()); - } - - /// floor(12345.6789) == 12345, frac(12345.6789) == 0.6789. - #[test] - fn test_frac_and_floor_floats() { - let float = Float::parse("12345.6789".to_string()).unwrap(); - let floor = float.floor().unwrap(); - let frac = float.frac().unwrap(); - - let expected_floor = Float::parse("12345".to_string()).unwrap(); - let expected_frac = Float::parse("0.6789".to_string()).unwrap(); - - assert!(floor.eq(expected_floor).unwrap()); - assert!(frac.eq(expected_frac).unwrap()); - } - - /// integer(12345.6789) == 12345, and integer + frac == original. - #[test] - fn test_integer_positive() { - let float = Float::parse("12345.6789".to_string()).unwrap(); - let int = float.integer().unwrap(); - let expected = Float::parse("12345".to_string()).unwrap(); - assert!(int.eq(expected).unwrap()); - - let frac = float.frac().unwrap(); - let recombined = (int + frac).unwrap(); - assert!(float.eq(recombined).unwrap()); - } - - /// integer truncates toward zero: integer(-12345.6789) == -12345. - #[test] - fn test_integer_negative() { - let float = Float::parse("-12345.6789".to_string()).unwrap(); - let int = float.integer().unwrap(); - let frac = float.frac().unwrap(); - - // integer truncates toward zero, so -12345.6789 -> -12345 - let expected_int = Float::parse("-12345".to_string()).unwrap(); - let expected_frac = Float::parse("-0.6789".to_string()).unwrap(); - - assert!(int.eq(expected_int).unwrap()); - assert!(frac.eq(expected_frac).unwrap()); - - // integer + frac == original - let recombined = (int + frac).unwrap(); - assert!(float.eq(recombined).unwrap()); - } - - /// integer(42) == 42, frac(42) == 0 for positive and negative whole numbers. - #[test] - fn test_integer_whole_numbers() { - let pos = Float::parse("42".to_string()).unwrap(); - assert!(pos.integer().unwrap().eq(pos).unwrap()); - let zero = Float::parse("0".to_string()).unwrap(); - assert!(pos.frac().unwrap().eq(zero).unwrap()); - - let neg = Float::parse("-42".to_string()).unwrap(); - assert!(neg.integer().unwrap().eq(neg).unwrap()); - assert!(neg.frac().unwrap().eq(zero).unwrap()); - } - - proptest! { - #[test] - /// from_fixed_decimal then to_fixed_decimal round-trips for any non-negative I224. - fn test_from_to_fixed_decimal_valid_range(coeff in any::(), decimals in 0u8..=66u8) { - prop_assume!(coeff >= I224::ZERO); - - let exponent = -(decimals as i32); - let value = U256::from(coeff); - - let float = Float::from_fixed_decimal(value, decimals).unwrap(); - let expected = Float::pack_lossless(coeff, exponent).unwrap(); - prop_assert!(float.eq(expected).unwrap()); - - let fixed = float.to_fixed_decimal(decimals).unwrap(); - assert_eq!(fixed, value); - } - } - - proptest! { - #[test] - /// integer(a) + frac(a) == a, frac has no integer part, integer has - /// no fractional part, and |frac| < 1. - fn test_int_frac_properties(float in arb_float()) { - let int = float.integer().unwrap(); - let frac = float.frac().unwrap(); - - let zero = Float::parse("0".to_string()).unwrap(); - - prop_assert!( - int.frac().unwrap().eq(zero).unwrap(), - "int.frac() is not zero: {}", - int.show_unpacked().unwrap() - ); - - prop_assert!( - frac.integer().unwrap().eq(zero).unwrap(), - "frac.integer() is not zero: {}", - frac.show_unpacked().unwrap() - ); - - let recombined = (int + frac).unwrap(); - prop_assert!( - float.eq(recombined).unwrap(), - "original: {}, int: {}, frac: {}, recombined: {}", - float.show_unpacked().unwrap(), - int.show_unpacked().unwrap(), - frac.show_unpacked().unwrap(), - recombined.show_unpacked().unwrap() - ); - - let one = Float::parse("1".to_string()).unwrap(); - let neg_one = one.neg().unwrap(); - prop_assert!( - frac.lt(one).unwrap(), - "frac not < 1: {}", - frac.show_unpacked().unwrap() - ); - prop_assert!( - frac.gt(neg_one).unwrap(), - "frac not > -1: {}", - frac.show_unpacked().unwrap() - ); - } - } - - /// min/max for known value pairs, including identical arguments. - #[test] - fn test_min_max_manual() { - let negone = Float::parse("-1".to_string()).unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - let three = Float::parse("3".to_string()).unwrap(); - let seven = Float::parse("7".to_string()).unwrap(); - - // --- min --- - assert!(negone.eq(negone.min(zero).unwrap()).unwrap()); - assert!(negone.eq(negone.min(three).unwrap()).unwrap()); - assert!(zero.eq(zero.min(three).unwrap()).unwrap()); - // min with identical arguments should return that argument - assert!(seven.eq(seven.min(seven).unwrap()).unwrap()); - - // --- max --- - assert!(zero.eq(negone.max(zero).unwrap()).unwrap()); - assert!(three.eq(negone.max(three).unwrap()).unwrap()); - assert!(three.eq(zero.max(three).unwrap()).unwrap()); - // max with identical arguments should return that argument - assert!(seven.eq(seven.max(seven).unwrap()).unwrap()); - } - - /// is_zero for "0", "-0", "0.0" (all true) and "1" (false). - #[test] - fn test_is_zero_manual() { - let zero = Float::parse("0".to_string()).unwrap(); - assert!(zero.is_zero().unwrap()); - - // Alternative zero representations that should also be considered zero. - let neg_zero = Float::parse("-0".to_string()).unwrap(); - assert!(neg_zero.is_zero().unwrap()); - let zero_point = Float::parse("0.0".to_string()).unwrap(); - assert!(zero_point.is_zero().unwrap()); - - let one = Float::parse("1".to_string()).unwrap(); - assert!(!one.is_zero().unwrap()); - } - - proptest! { - #[test] - /// min(a,b) <= both, max(a,b) >= both, each equals one operand, - /// and min <= max. - fn test_min_max_properties(a in reasonable_float(), b in reasonable_float()) { - let min = a.min(b).unwrap(); - let max = a.max(b).unwrap(); - - prop_assert!( - !min.gt(a).unwrap(), - "min > a: min={}, a={}", - min.show_unpacked().unwrap(), - a.show_unpacked().unwrap() - ); - prop_assert!( - !min.gt(b).unwrap(), - "min > b: min={}, b={}", - min.show_unpacked().unwrap(), - b.show_unpacked().unwrap() - ); - - prop_assert!( - !max.lt(a).unwrap(), - "max < a: max={}, a={}", - max.show_unpacked().unwrap(), - a.show_unpacked().unwrap() - ); - prop_assert!( - !max.lt(b).unwrap(), - "max < b: max={}, b={}", - max.show_unpacked().unwrap(), - b.show_unpacked().unwrap() - ); - - let min_is_a = min.eq(a).unwrap(); - let min_is_b = min.eq(b).unwrap(); - prop_assert!( - min_is_a || min_is_b, - "min is not equal to either operand: a={}, b={}, min={}", - a.show_unpacked().unwrap(), - b.show_unpacked().unwrap(), - min.show_unpacked().unwrap() - ); - - let max_is_a = max.eq(a).unwrap(); - let max_is_b = max.eq(b).unwrap(); - prop_assert!( - max_is_a || max_is_b, - "max is not equal to either operand: a={}, b={}, max={}", - a.show_unpacked().unwrap(), - b.show_unpacked().unwrap(), - max.show_unpacked().unwrap() - ); - - prop_assert!( - !min.gt(max).unwrap(), - "min > max: min={}, max={}", - min.show_unpacked().unwrap(), - max.show_unpacked().unwrap() - ); - } - } - - /// Manual lte/gte checks: -1 <= 0 <= 3, 0 >= -1, 3 >= 0. - #[test] - fn test_lte_gte() { - let negone = Float::parse("-1".to_string()).unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - let three = Float::parse("3".to_string()).unwrap(); - - assert!(negone.lte(zero).unwrap()); - assert!(zero.lte(three).unwrap()); - assert!(negone.lte(three).unwrap()); - - assert!(zero.gte(negone).unwrap()); - assert!(three.gte(zero).unwrap()); - assert!(three.gte(negone).unwrap()); - } - - proptest! { - #[test] - /// a-1 lte a, a lte a and gte a, a+1 gte a. - fn test_lte_gte_fuzz(a in reasonable_float()) { - let b = a; - let one = Float::parse("1".to_string()).unwrap(); - - let a = (a - one).unwrap(); - let lte = a.lte(b).unwrap(); - prop_assert!(lte); // lt - - let a = (a + one).unwrap(); - let gte = a.gte(b).unwrap(); - let lte = a.lte(b).unwrap(); - prop_assert!(gte); // eq - prop_assert!(lte); // eq - - let a = (a + one).unwrap(); - let gte = a.gte(b).unwrap(); - prop_assert!(gte); // gt - } - } - - /// from_fixed_decimal_lossy: lossless for small values, lossy for U256::MAX. - #[test] - fn test_from_fixed_decimal_lossy() { - // Test lossless conversions (values that fit in Float's precision) - let lossless_cases = vec![ - (U256::from(0u128), 0u8, "0"), - (U256::from(0u128), 18u8, "0"), - (U256::from(1u128), 18u8, "1e-18"), - (U256::from(123456789u128), 0u8, "123456789"), - (U256::from(123456789u128), 2u8, "123456789e-2"), - (U256::from(1000000000000000000u128), 18u8, "1"), - ]; - - for (amount, decimals, expected) in lossless_cases { - let (float, lossless) = - Float::from_fixed_decimal_lossy(amount, decimals).expect("should convert"); - let expected = Float::parse(expected.to_string()).unwrap(); - assert!(float.eq(expected).unwrap()); - assert!( - lossless, - "conversion should be lossless for amount={}, decimals={}", - amount, decimals - ); - } - - // Test lossy conversion with U256::MAX (too large to fit in Float's 224-bit coefficient) - let (float, lossless) = Float::from_fixed_decimal_lossy(U256::MAX, 1).unwrap(); - assert!(!lossless, "U256::MAX conversion should be lossy"); - assert!(!float.is_zero().unwrap(), "result should not be zero"); - } - - /// to_fixed_decimal_lossy: correctly reports lossy/lossless for precision loss. - #[test] - fn test_to_fixed_decimal_lossy() { - // Test lossy conversions (loss of precision) - let lossy_cases = vec![ - (U256::from(1), 18u8, 0u128), - (U256::from(123456789), 0u8, 12345678u128), - (U256::from(123456789), 2u8, 12345678u128), - ]; - - for (input, decimals, expected) in lossy_cases { - let float = Float::from_fixed_decimal(input, decimals + 1).unwrap(); - let (fixed, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); - assert_eq!( - fixed, - U256::from(expected), - "wrong value for input={}, decimals={}", - input, - decimals - ); - assert!( - !lossless, - "should be lossy for input={}, decimals={}", - input, decimals - ); - } - - // Test lossless conversions (no loss of precision) - let lossless_cases = vec![ - // Zero is always lossless - (U256::from(0), 0u8, 0u128), - (U256::from(0), 18u8, 0u128), - // Converting 12340 with 3 decimals (12.340) to 2 decimals (12.34) is lossless - (U256::from(12340), 3u8, 1234u128), - ]; - - for (input, decimals, expected) in lossless_cases { - let float = Float::from_fixed_decimal(input, decimals + 1).unwrap(); - let (fixed, lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); - assert_eq!( - fixed, - U256::from(expected), - "wrong value for input={}, decimals={}", - input, - decimals - ); - assert!( - lossless, - "should be lossless for input={}, decimals={}", - input, decimals - ); - } - } - - proptest! { - #[test] - /// Lossy fixed-decimal round-trip: from(decimals+1) then to(decimals) is - /// lossy iff the last digit is nonzero. - fn test_from_to_fixed_decimal_lossy_valid_range(coeff in any::(), decimals in 0u8..=66u8) { - prop_assume!(coeff >= I224::ZERO); - - let exponent = -(decimals as i32 + 1); - let value = U256::from(coeff); - - let (float, from_lossless) = Float::from_fixed_decimal_lossy(value, decimals + 1).unwrap(); - let expected = Float::pack_lossless(coeff, exponent).unwrap(); - prop_assert!(float.eq(expected).unwrap()); - - // from_fixed_decimal_lossy should be lossless for values that fit in Float's precision - prop_assert!(from_lossless, "from_fixed_decimal_lossy should be lossless for coeff={coeff}"); - - let (fixed, to_lossless) = float.to_fixed_decimal_lossy(decimals).unwrap(); - assert_eq!(fixed, value / U256::from(10)); - - // Converting from decimals+1 to decimals should be lossy unless the value is zero or - // the last digit is zero (divisible by 10) - if value == U256::ZERO || value % U256::from(10) == U256::ZERO { - prop_assert!(to_lossless, "to_fixed_decimal_lossy should be lossless when last digit is 0: value={}", value); - } else { - prop_assert!(!to_lossless, "to_fixed_decimal_lossy should be lossy when losing precision: value={}", value); - } - } - } - - proptest! { - #[test] - /// All reasonable positive floats are bounded by min/max_positive_value, - /// all negative by min/max_negative_value. - fn test_constants_relationships(float in reasonable_float()) { - let max_pos = Float::max_positive_value().unwrap(); - let min_pos = Float::min_positive_value().unwrap(); - let max_neg = Float::max_negative_value().unwrap(); - let min_neg = Float::min_negative_value().unwrap(); - let zero = Float::parse("0".to_string()).unwrap(); - - // Test that constants are the extremes - // Any reasonable positive float should be <= max_positive and >= min_positive - if float.gt(zero).unwrap() { - prop_assert!(float.lte(max_pos).unwrap()); - prop_assert!(float.gte(min_pos).unwrap()); - } - - // Any reasonable negative float should be <= max_negative and >= min_negative - // (max_negative is closest to zero, min_negative is furthest from zero) - if float.lt(zero).unwrap() { - prop_assert!(float.lte(max_neg).unwrap()); - prop_assert!(float.gte(min_neg).unwrap()); - } - - // Constants should be consistent regardless of arbitrary float - prop_assert!(max_pos.gt(zero).unwrap()); - prop_assert!(min_pos.gt(zero).unwrap()); - prop_assert!(max_neg.lt(zero).unwrap()); - prop_assert!(min_neg.lt(zero).unwrap()); - - // Verify constants maintain their ordering - prop_assert!(min_pos.lt(max_pos).unwrap()); - prop_assert!(min_neg.lt(max_neg).unwrap()); - prop_assert!(max_neg.lt(zero).unwrap()); - prop_assert!(min_pos.gt(zero).unwrap()); - } - } - - proptest! { - #[test] - /// No arbitrary float exceeds max_positive or is below min_negative. - fn test_constants_edge_cases(float in arb_float()) { - let max_pos = Float::max_positive_value().unwrap(); - let min_pos = Float::min_positive_value().unwrap(); - let max_neg = Float::max_negative_value().unwrap(); - let min_neg = Float::min_negative_value().unwrap(); - - // Constants should always be distinct - prop_assert!(!max_pos.eq(min_pos).unwrap()); - prop_assert!(!max_neg.eq(min_neg).unwrap()); - prop_assert!(!max_pos.eq(max_neg).unwrap()); - prop_assert!(!min_pos.eq(min_neg).unwrap()); - - // Test that constants are at the boundaries - // (Note: We can't test arithmetic operations that would overflow/underflow - // since those would fail, but we can test comparisons) - - // No arbitrary float should be greater than max_pos or less than min_neg - if !float.eq(max_pos).unwrap() { - prop_assert!(!float.gt(max_pos).unwrap()); - } - if !float.eq(min_neg).unwrap() { - prop_assert!(!float.lt(min_neg).unwrap()); - } - } - } } From 83f0f949387c0e7380402ad3f069f8bb7b8e77a2 Mon Sep 17 00:00:00 2001 From: baku-ccron Date: Tue, 8 Sep 2026 06:53:31 +0000 Subject: [PATCH 4/4] Document the harness unpack helpers Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QyCCzi9WZPhuXcU1hwr2bq --- crates/float/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/float/src/lib.rs b/crates/float/src/lib.rs index 4670e80..a3204aa 100644 --- a/crates/float/src/lib.rs +++ b/crates/float/src/lib.rs @@ -238,6 +238,8 @@ impl Float { }) } + /// The signed coefficient and exponent the library unpacks from this float. + /// The signed coefficient and exponent the library unpacks from this float. #[cfg(any(test, feature = "test-harness"))] pub fn unpack(self) -> Result<(alloy::primitives::I256, alloy::primitives::I256), FloatError> { let Float(float) = self; @@ -253,6 +255,8 @@ impl Float { }) } + /// `e`, as unpacked by the library. + /// `e`, as unpacked by the library. #[cfg(any(test, feature = "test-harness"))] pub fn show_unpacked(self) -> Result { let (coefficient, exponent) = self.unpack()?;