Commit 341c8d26 authored by Litian's avatar Litian

增加abi的命令行操作接口

parent 973b4e61
...@@ -15,6 +15,8 @@ import ( ...@@ -15,6 +15,8 @@ import (
"strconv" "strconv"
"encoding/json"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/crypto/sha3" "github.com/33cn/chain33/common/crypto/sha3"
...@@ -39,6 +41,7 @@ func EvmCmd() *cobra.Command { ...@@ -39,6 +41,7 @@ func EvmCmd() *cobra.Command {
cmd.AddCommand( cmd.AddCommand(
createContractCmd(), createContractCmd(),
callContractCmd(), callContractCmd(),
abiCmd(),
estimateContractCmd(), estimateContractCmd(),
checkContractAddrCmd(), checkContractAddrCmd(),
evmDebugCmd(), evmDebugCmd(),
...@@ -200,8 +203,10 @@ func createContractCmd() *cobra.Command { ...@@ -200,8 +203,10 @@ func createContractCmd() *cobra.Command {
func addCreateContractFlags(cmd *cobra.Command) { func addCreateContractFlags(cmd *cobra.Command) {
addCommonFlags(cmd) addCommonFlags(cmd)
cmd.MarkFlagRequired("input")
cmd.Flags().StringP("alias", "s", "", "human readable contract alias name") cmd.Flags().StringP("alias", "s", "", "human readable contract alias name")
cmd.Flags().StringP("abi", "b", "", "bind the abi data")
} }
func createContract(cmd *cobra.Command, args []string) { func createContract(cmd *cobra.Command, args []string) {
...@@ -213,6 +218,7 @@ func createContract(cmd *cobra.Command, args []string) { ...@@ -213,6 +218,7 @@ func createContract(cmd *cobra.Command, args []string) {
fee, _ := cmd.Flags().GetFloat64("fee") fee, _ := cmd.Flags().GetFloat64("fee")
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr") rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
paraName, _ := cmd.Flags().GetString("paraName") paraName, _ := cmd.Flags().GetString("paraName")
abi, _ := cmd.Flags().GetString("abi")
feeInt64 := uint64(fee*1e4) * 1e4 feeInt64 := uint64(fee*1e4) * 1e4
...@@ -221,7 +227,7 @@ func createContract(cmd *cobra.Command, args []string) { ...@@ -221,7 +227,7 @@ func createContract(cmd *cobra.Command, args []string) {
fmt.Fprintln(os.Stderr, "parse evm code error", err) fmt.Fprintln(os.Stderr, "parse evm code error", err)
return return
} }
action := evmtypes.EVMContractAction{Amount: 0, Code: bCode, GasLimit: 0, GasPrice: 0, Note: note, Alias: alias} action := evmtypes.EVMContractAction{Amount: 0, Code: bCode, GasLimit: 0, GasPrice: 0, Note: note, Alias: alias, Abi: abi}
data, err := createEvmTx(&action, types.ExecName(paraName+"evm"), caller, address.ExecAddress(types.ExecName(paraName+"evm")), expire, rpcLaddr, feeInt64) data, err := createEvmTx(&action, types.ExecName(paraName+"evm"), caller, address.ExecAddress(types.ExecName(paraName+"evm")), expire, rpcLaddr, feeInt64)
...@@ -343,6 +349,7 @@ func callContract(cmd *cobra.Command, args []string) { ...@@ -343,6 +349,7 @@ func callContract(cmd *cobra.Command, args []string) {
amount, _ := cmd.Flags().GetFloat64("amount") amount, _ := cmd.Flags().GetFloat64("amount")
fee, _ := cmd.Flags().GetFloat64("fee") fee, _ := cmd.Flags().GetFloat64("fee")
name, _ := cmd.Flags().GetString("exec") name, _ := cmd.Flags().GetString("exec")
abi, _ := cmd.Flags().GetString("abi")
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr") rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
amountInt64 := uint64(amount*1e4) * 1e4 amountInt64 := uint64(amount*1e4) * 1e4
...@@ -355,7 +362,7 @@ func callContract(cmd *cobra.Command, args []string) { ...@@ -355,7 +362,7 @@ func callContract(cmd *cobra.Command, args []string) {
return return
} }
action := evmtypes.EVMContractAction{Amount: amountInt64, Code: bCode, GasLimit: 0, GasPrice: 0, Note: note} action := evmtypes.EVMContractAction{Amount: amountInt64, Code: bCode, GasLimit: 0, GasPrice: 0, Note: note, Abi: abi}
//name表示发给哪个执行器 //name表示发给哪个执行器
data, err := createEvmTx(&action, name, caller, toAddr, expire, rpcLaddr, feeInt64) data, err := createEvmTx(&action, name, caller, toAddr, expire, rpcLaddr, feeInt64)
...@@ -379,11 +386,12 @@ func addCallContractFlags(cmd *cobra.Command) { ...@@ -379,11 +386,12 @@ func addCallContractFlags(cmd *cobra.Command) {
cmd.MarkFlagRequired("exec") cmd.MarkFlagRequired("exec")
cmd.Flags().Float64P("amount", "a", 0, "the amount transfer to the contract (optional)") cmd.Flags().Float64P("amount", "a", 0, "the amount transfer to the contract (optional)")
cmd.Flags().StringP("abi", "b", "", "call with abi")
} }
func addCommonFlags(cmd *cobra.Command) { func addCommonFlags(cmd *cobra.Command) {
cmd.Flags().StringP("input", "i", "", "input contract binary code") cmd.Flags().StringP("input", "i", "", "input contract binary code")
cmd.MarkFlagRequired("input")
cmd.Flags().StringP("caller", "c", "", "the caller address") cmd.Flags().StringP("caller", "c", "", "the caller address")
cmd.MarkFlagRequired("caller") cmd.MarkFlagRequired("caller")
...@@ -395,6 +403,85 @@ func addCommonFlags(cmd *cobra.Command) { ...@@ -395,6 +403,85 @@ func addCommonFlags(cmd *cobra.Command) {
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)") cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
} }
// abi命令
func abiCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "abi",
Short: "EVM ABI commands",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
getAbiCmd(),
callAbiCmd(),
)
return cmd
}
func getAbiCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "get abi data of evm contract",
Run: getAbi,
}
cmd.Flags().StringP("address", "a", "", "evm contract address")
cmd.MarkFlagRequired("address")
return cmd
}
func getAbi(cmd *cobra.Command, args []string) {
addr, _ := cmd.Flags().GetString("address")
var req = evmtypes.EvmQueryAbiReq{Address: addr}
var resp evmtypes.EvmQueryAbiResp
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
query := sendQuery(rpcLaddr, "QueryABI", req, &resp)
if query {
fmt.Fprintln(os.Stdout, resp.Abi)
}
}
func callAbiCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "call",
Short: "send query call by abi format",
Run: callAbi,
}
cmd.Flags().StringP("address", "a", "", "evm contract address")
cmd.MarkFlagRequired("address")
cmd.Flags().StringP("input", "b", "", "call params (abi format) like foobar(param1,param2)")
cmd.MarkFlagRequired("input")
cmd.Flags().StringP("caller", "c", "", "the caller address")
return cmd
}
func callAbi(cmd *cobra.Command, args []string) {
addr, _ := cmd.Flags().GetString("address")
input, _ := cmd.Flags().GetString("input")
caller, _ := cmd.Flags().GetString("caller")
var req = evmtypes.EvmQueryReq{Address: addr, Input: input, Caller: caller}
var resp evmtypes.EvmQueryResp
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
query := sendQuery(rpcLaddr, "Query", req, &resp)
if query {
data, err := json.MarshalIndent(&resp, "", " ")
if err != nil {
fmt.Println(resp.String())
} else {
fmt.Println(string(data))
}
}
}
func estimateContract(cmd *cobra.Command, args []string) { func estimateContract(cmd *cobra.Command, args []string) {
code, _ := cmd.Flags().GetString("input") code, _ := cmd.Flags().GetString("input")
name, _ := cmd.Flags().GetString("exec") name, _ := cmd.Flags().GetString("exec")
......
...@@ -46,7 +46,6 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, ...@@ -46,7 +46,6 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int,
contractAddr common.Address contractAddr common.Address
snapshot int snapshot int
execName string execName string
abiData string
methodName string methodName string
) )
...@@ -69,7 +68,7 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, ...@@ -69,7 +68,7 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int,
if isCreate { if isCreate {
// 如果携带ABI数据,则对数据合法性进行检查 // 如果携带ABI数据,则对数据合法性进行检查
if len(msg.ABI()) > 0 && types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMABI") { if len(msg.ABI()) > 0 && types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMABI") {
_, err = abi.JSON(strings.NewReader(abiData)) _, err = abi.JSON(strings.NewReader(msg.ABI()))
if err != nil { if err != nil {
return receipt, err return receipt, err
} }
......
...@@ -87,16 +87,18 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types ...@@ -87,16 +87,18 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
} }
// 从日志中查找调用结果 // 从日志中查找调用结果
func getCallReceipt(logs []*types.ReceiptLog) (res *evmtypes.ReceiptEVMContract) { func getCallReceipt(logs []*types.ReceiptLog) *evmtypes.ReceiptEVMContract {
if len(logs) == 0 { if len(logs) == 0 {
return res return nil
} }
for _, v := range logs { for _, v := range logs {
if v.Ty == evmtypes.TyLogCallContract { if v.Ty == evmtypes.TyLogCallContract {
types.Decode(v.Log, res) var res evmtypes.ReceiptEVMContract
types.Decode(v.Log, &res)
return &res
} }
} }
return res return nil
} }
// Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据 // Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
...@@ -153,7 +155,7 @@ func (evm *EVMExecutor) Query_Query(in *evmtypes.EvmQueryReq) (types.Message, er ...@@ -153,7 +155,7 @@ func (evm *EVMExecutor) Query_Query(in *evmtypes.EvmQueryReq) (types.Message, er
if receipt.Ty == types.ExecOk { if receipt.Ty == types.ExecOk {
callData := getCallReceipt(receipt.GetLogs()) callData := getCallReceipt(receipt.GetLogs())
if callData != nil { if callData != nil {
ret.RawData = callData.Ret ret.RawData = common.Bytes2Hex(callData.Ret)
ret.JsonData = callData.JsonRet ret.JsonData = callData.JsonRet
return ret, nil return ret, nil
} }
......
...@@ -144,6 +144,6 @@ message EvmQueryResp { ...@@ -144,6 +144,6 @@ message EvmQueryResp {
string address = 1; string address = 1;
string input = 2; string input = 2;
string caller = 3; string caller = 3;
bytes rawData = 4; string rawData = 4;
string jsonData = 5; string jsonData = 5;
} }
\ No newline at end of file
...@@ -1117,7 +1117,7 @@ type EvmQueryResp struct { ...@@ -1117,7 +1117,7 @@ type EvmQueryResp struct {
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Input string `protobuf:"bytes,2,opt,name=input,proto3" json:"input,omitempty"` Input string `protobuf:"bytes,2,opt,name=input,proto3" json:"input,omitempty"`
Caller string `protobuf:"bytes,3,opt,name=caller,proto3" json:"caller,omitempty"` Caller string `protobuf:"bytes,3,opt,name=caller,proto3" json:"caller,omitempty"`
RawData []byte `protobuf:"bytes,4,opt,name=rawData,proto3" json:"rawData,omitempty"` RawData string `protobuf:"bytes,4,opt,name=rawData,proto3" json:"rawData,omitempty"`
JsonData string `protobuf:"bytes,5,opt,name=jsonData,proto3" json:"jsonData,omitempty"` JsonData string `protobuf:"bytes,5,opt,name=jsonData,proto3" json:"jsonData,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
...@@ -1170,11 +1170,11 @@ func (m *EvmQueryResp) GetCaller() string { ...@@ -1170,11 +1170,11 @@ func (m *EvmQueryResp) GetCaller() string {
return "" return ""
} }
func (m *EvmQueryResp) GetRawData() []byte { func (m *EvmQueryResp) GetRawData() string {
if m != nil { if m != nil {
return m.RawData return m.RawData
} }
return nil return ""
} }
func (m *EvmQueryResp) GetJsonData() string { func (m *EvmQueryResp) GetJsonData() string {
...@@ -1211,13 +1211,13 @@ func init() { ...@@ -1211,13 +1211,13 @@ func init() {
func init() { proto.RegisterFile("evmcontract.proto", fileDescriptor_74353de561acd7c6) } func init() { proto.RegisterFile("evmcontract.proto", fileDescriptor_74353de561acd7c6) }
var fileDescriptor_74353de561acd7c6 = []byte{ var fileDescriptor_74353de561acd7c6 = []byte{
// 834 bytes of a gzipped FileDescriptorProto // 833 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4b, 0x6f, 0x2b, 0x35, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4b, 0x6f, 0x2b, 0x35,
0x18, 0xd5, 0x24, 0x93, 0xc7, 0x7c, 0x09, 0xb7, 0xad, 0x81, 0x32, 0xaa, 0x58, 0x44, 0x16, 0x17, 0x18, 0xd5, 0x24, 0x93, 0xc7, 0x7c, 0x09, 0xb7, 0xad, 0x81, 0x32, 0xaa, 0x58, 0x44, 0x16, 0x17,
0xa2, 0x2b, 0x11, 0xa1, 0xcb, 0x06, 0x5d, 0x09, 0xa4, 0x28, 0x77, 0x54, 0x90, 0x08, 0x0f, 0x57, 0xa2, 0x2b, 0x11, 0xa1, 0xcb, 0x06, 0x5d, 0x09, 0xa4, 0x28, 0x77, 0x54, 0x90, 0x08, 0x0f, 0x57,
0x64, 0xef, 0xcc, 0x98, 0x74, 0xda, 0xcc, 0x83, 0xb1, 0x27, 0x28, 0x5b, 0xd6, 0x2c, 0x59, 0xb2, 0x64, 0xef, 0xcc, 0x98, 0x74, 0xda, 0xcc, 0x83, 0xb1, 0x27, 0x28, 0x5b, 0xd6, 0x2c, 0x59, 0xb2,
0x63, 0xc9, 0x92, 0x1d, 0x3f, 0x87, 0x15, 0x3f, 0x03, 0x7d, 0x1e, 0xcf, 0x2b, 0x4d, 0x2a, 0x21, 0x63, 0xc9, 0x92, 0x1d, 0x3f, 0x87, 0x15, 0x3f, 0x03, 0x7d, 0x1e, 0xcf, 0x2b, 0x4d, 0x2a, 0x21,
0x55, 0x88, 0x55, 0x7d, 0xec, 0x63, 0xfb, 0x9c, 0xf9, 0xce, 0xe7, 0x14, 0x2e, 0xc4, 0x2e, 0xf2, 0x55, 0x88, 0x55, 0x7d, 0xec, 0x63, 0xfb, 0x9c, 0xf9, 0xce, 0xe7, 0x06, 0x2e, 0xc4, 0x2e, 0xf2,
0x93, 0x58, 0x65, 0xdc, 0x57, 0xb3, 0x34, 0x4b, 0x54, 0x42, 0x7a, 0x6a, 0x9f, 0x0a, 0x49, 0x7f, 0x93, 0x58, 0x65, 0xdc, 0x57, 0xb3, 0x34, 0x4b, 0x54, 0x42, 0x7a, 0x6a, 0x9f, 0x0a, 0x49, 0x7f,
0xb2, 0xe0, 0xc2, 0x5b, 0x2d, 0x17, 0x66, 0xf1, 0xeb, 0xf5, 0x9d, 0xf0, 0x15, 0x21, 0x60, 0xf3, 0xb2, 0xe0, 0xc2, 0x5b, 0x2d, 0x17, 0x66, 0xf1, 0xeb, 0xf5, 0x9d, 0xf0, 0x15, 0x21, 0x60, 0xf3,
0x20, 0xc8, 0x5c, 0x6b, 0x62, 0x4d, 0x1d, 0xa6, 0xc7, 0xe4, 0x05, 0xd8, 0x01, 0x57, 0xdc, 0xed, 0x20, 0xc8, 0x5c, 0x6b, 0x62, 0x4d, 0x1d, 0xa6, 0xc7, 0xe4, 0x05, 0xd8, 0x01, 0x57, 0xdc, 0xed,
...@@ -1249,20 +1249,20 @@ var fileDescriptor_74353de561acd7c6 = []byte{ ...@@ -1249,20 +1249,20 @@ var fileDescriptor_74353de561acd7c6 = []byte{
0x87, 0x39, 0xed, 0x0e, 0x9b, 0x1f, 0x76, 0xd8, 0x07, 0x27, 0x3a, 0x6c, 0x11, 0x05, 0x4f, 0xd3, 0x87, 0x39, 0xed, 0x0e, 0x9b, 0x1f, 0x76, 0xd8, 0x07, 0x27, 0x3a, 0x6c, 0x11, 0x05, 0x4f, 0xd3,
0x64, 0x4e, 0xb3, 0xc9, 0x7e, 0xb3, 0xe0, 0xed, 0x87, 0x71, 0x45, 0xb3, 0xff, 0x8b, 0xc4, 0x3a, 0x64, 0x4e, 0xb3, 0xc9, 0x7e, 0xb3, 0xe0, 0xed, 0x87, 0x71, 0x45, 0xb3, 0xff, 0x8b, 0xc4, 0x3a,
0x3a, 0xb1, 0xf4, 0x39, 0x9c, 0x2d, 0x6e, 0x85, 0x7f, 0xef, 0xad, 0x96, 0xb8, 0x97, 0x89, 0x1f, 0x3a, 0xb1, 0xf4, 0x39, 0x9c, 0x2d, 0x6e, 0x85, 0x7f, 0xef, 0xad, 0x96, 0xb8, 0x97, 0x89, 0x1f,
0x8e, 0xfd, 0x3e, 0xd0, 0x5f, 0x2c, 0x38, 0x6f, 0xf3, 0x64, 0x5a, 0x14, 0xba, 0xb8, 0x57, 0x93, 0x8e, 0xfd, 0x7f, 0xa0, 0xbf, 0x58, 0x70, 0xde, 0xe6, 0xc9, 0xb4, 0x28, 0x74, 0x71, 0xaf, 0x26,
0x87, 0xac, 0xc2, 0x0f, 0x74, 0x76, 0x8e, 0xe8, 0x3c, 0xf4, 0xdb, 0x3d, 0xe2, 0xf7, 0x5d, 0x70, 0x0f, 0x59, 0x85, 0x1f, 0xe8, 0xec, 0x1c, 0xd1, 0x79, 0xe8, 0xb7, 0x7b, 0xc4, 0xef, 0xbb, 0xe0,
0x74, 0xfa, 0x34, 0xa1, 0x48, 0x5e, 0x3d, 0x41, 0xf7, 0x70, 0xe1, 0x49, 0x15, 0x46, 0x5c, 0x09, 0xe8, 0xf4, 0x69, 0x42, 0x91, 0xbc, 0x7a, 0x82, 0xee, 0xe1, 0xc2, 0x93, 0x2a, 0x8c, 0xb8, 0x12,
0x6f, 0xb5, 0xbc, 0xe6, 0x12, 0xf5, 0x3f, 0x83, 0x8e, 0x4a, 0x8c, 0xfa, 0x8e, 0x4a, 0xaa, 0x8c, 0xde, 0x6a, 0x79, 0xcd, 0x25, 0xea, 0x7f, 0x06, 0x1d, 0x95, 0x18, 0xf5, 0x1d, 0x95, 0x54, 0x19,
0x76, 0x1a, 0xef, 0x50, 0x5d, 0x82, 0x6e, 0xab, 0x04, 0xf5, 0x1b, 0x68, 0xb7, 0xde, 0x40, 0xf3, 0xed, 0x34, 0xde, 0xa1, 0xba, 0x04, 0xdd, 0x56, 0x09, 0xea, 0x37, 0xd0, 0x6e, 0xbd, 0x81, 0xe6,
0x1a, 0xf5, 0xea, 0xd7, 0xe8, 0x7d, 0x20, 0x87, 0x57, 0xcb, 0x14, 0x79, 0x1b, 0x2e, 0x4d, 0x8a, 0x35, 0xea, 0xd5, 0xaf, 0xd1, 0xfb, 0x40, 0x0e, 0xaf, 0x96, 0x29, 0xf2, 0x36, 0x5c, 0x9a, 0x14,
0x71, 0x48, 0x9f, 0xc3, 0xc8, 0xdb, 0x45, 0xaf, 0xc5, 0x3a, 0xdf, 0xa0, 0xb8, 0x4b, 0xe8, 0x27, 0xe3, 0x90, 0x3e, 0x87, 0x91, 0xb7, 0x8b, 0x5e, 0x8b, 0x75, 0xbe, 0x41, 0x71, 0x97, 0xd0, 0x4f,
0x29, 0xc6, 0x50, 0x73, 0x7a, 0xcc, 0x20, 0xfa, 0x11, 0x8c, 0x6b, 0x9a, 0x4c, 0x31, 0xde, 0x01, 0x52, 0x8c, 0xa1, 0xe6, 0xf4, 0x98, 0x41, 0xf4, 0x23, 0x18, 0xd7, 0x34, 0x99, 0x62, 0xbc, 0x03,
0x02, 0x0c, 0x68, 0x2e, 0x8d, 0x9b, 0xe6, 0x14, 0x7d, 0x01, 0xcf, 0xbc, 0x5d, 0xf4, 0x6d, 0x2e, 0x04, 0x18, 0xd0, 0x5c, 0x1a, 0x37, 0xcd, 0x29, 0xfa, 0x02, 0x9e, 0x79, 0xbb, 0xe8, 0xdb, 0x5c,
0xb2, 0xfd, 0x7c, 0x1d, 0xe2, 0xd9, 0x2e, 0x0c, 0xb0, 0x58, 0x42, 0x96, 0xfc, 0x12, 0xd2, 0x4f, 0x64, 0xfb, 0xf9, 0x3a, 0xc4, 0xb3, 0x5d, 0x18, 0x60, 0xb1, 0x84, 0x2c, 0xf9, 0x25, 0xa4, 0x9f,
0xe1, 0xac, 0xc5, 0x95, 0xe9, 0x69, 0x72, 0xe9, 0xb5, 0x53, 0x7b, 0xfd, 0x4e, 0x7b, 0xd0, 0xdb, 0xc2, 0x59, 0x8b, 0x2b, 0xd3, 0xd3, 0xe4, 0xd2, 0x6b, 0xa7, 0xf6, 0xfa, 0x9d, 0xf6, 0xa0, 0xb7,
0x1f, 0xbd, 0x07, 0xbb, 0x21, 0x8c, 0xd3, 0x5c, 0x95, 0xdd, 0xa0, 0xc1, 0xa9, 0x8f, 0x4d, 0x7f, 0x3f, 0x7a, 0x0f, 0x76, 0x43, 0x18, 0xa7, 0xb9, 0x2a, 0xbb, 0x41, 0x83, 0x53, 0x1f, 0x9b, 0xfe,
0xb6, 0xb4, 0x69, 0x73, 0xee, 0xa3, 0x9a, 0xfe, 0xd5, 0xc1, 0x78, 0x4e, 0xc6, 0x7f, 0xc4, 0xb7, 0x6c, 0x69, 0xd3, 0xe6, 0xdc, 0x47, 0x35, 0xfd, 0xab, 0x83, 0xf1, 0x9c, 0x8c, 0xff, 0x88, 0x6f,
0xcf, 0xfc, 0xf8, 0x94, 0x10, 0x23, 0x8b, 0x2f, 0xb2, 0x5e, 0x2a, 0x8a, 0x59, 0xe1, 0x75, 0x5f, 0x9f, 0x89, 0x4c, 0x09, 0x31, 0xb2, 0xf8, 0x22, 0xeb, 0xa5, 0xa2, 0x98, 0x15, 0x5e, 0xf7, 0xf5,
0xff, 0xef, 0xf4, 0xf1, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x88, 0x5b, 0x84, 0x50, 0x09, 0x6f, 0xa7, 0x8f, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x22, 0x7b, 0xc5, 0xdf, 0x50, 0x09, 0x00,
0x00, 0x00, 0x00,
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment