Commit a98fbca6 authored by QM's avatar QM

updata

parent 9147f853
......@@ -212,9 +212,8 @@ func (b *blsClient) getSuperNodes() ([]string, string) {
nodes, nodeStr := b.getSuperGroupNodes()
if len(nodes) > 0 {
return nodes, nodeStr
} else {
return b.getSupervisionGroupNodes()
}
return b.getSupervisionGroupNodes()
} else if b.typeNode == pt.ParaCommitSuperNode {
return b.getSuperGroupNodes()
} else if b.typeNode == pt.ParaCommitSupervisionNode {
......@@ -521,54 +520,42 @@ func (b *blsClient) blsSign(commits []*pt.ParacrossCommitAction) error {
}
func (b *blsClient) getBlsPubKey(addr string) (crypto.PubKey, error) {
if b.typeNode == pt.ParaCommitSuperNode || b.typeNode == pt.ParaCommitSupervisionNode {
var funcName string
if b.typeNode == pt.ParaCommitSuperNode {
funcName = "GetNodeAddrInfo"
} else {
funcName = "GetSupervisionNodeAddrInfo"
}
//先从缓存中获取
if v, ok := b.peersBlsPubKey[addr]; ok {
return v, nil
}
//缓存没有,则从statedb获取
cfg := b.paraClient.GetAPI().GetConfig()
ret, err := b.paraClient.GetAPI().QueryChain(&types.ChainExecutor{
Driver: "paracross",
FuncName: funcName,
Param: types.Encode(&pt.ReqParacrossNodeInfo{Title: cfg.GetTitle(), Addr: addr}),
})
if err != nil {
plog.Error("commitmsg.GetNodeAddrInfo ", "funcName", funcName, "err", err.Error())
return nil, err
}
resp, ok := ret.(*pt.ParaNodeAddrIdStatus)
if !ok {
plog.Error("commitmsg.getNodeGroupAddrs rsp nok", "funcName", funcName)
return nil, err
}
s, err := common.FromHex(resp.BlsPubKey)
if err != nil {
plog.Error("commitmsg.getNode pubkey nok", "pubkey", resp.BlsPubKey, "funcName", funcName)
return nil, err
}
pubKey, err := b.cryptoCli.PubKeyFromBytes(s)
if err != nil {
plog.Error("verifyBlsSign.DeserializePublicKey", "key", addr)
return nil, err
}
plog.Info("getBlsPubKey", "addr", addr, "pub", resp.BlsPubKey, "serial", common.ToHex(pubKey.Bytes()))
b.peersBlsPubKey[addr] = pubKey
return pubKey, nil
//先从缓存中获取
if v, ok := b.peersBlsPubKey[addr]; ok {
return v, nil
}
//缓存没有,则从statedb获取
cfg := b.paraClient.GetAPI().GetConfig()
ret, err := b.paraClient.GetAPI().QueryChain(&types.ChainExecutor{
Driver: "paracross",
FuncName: "GetNodeAddrInfo",
Param: types.Encode(&pt.ReqParacrossNodeInfo{Title: cfg.GetTitle(), Addr: addr}),
})
if err != nil {
plog.Error("commitmsg.GetNodeAddrInfo ", "err", err.Error())
return nil, err
}
resp, ok := ret.(*pt.ParaNodeAddrIdStatus)
if !ok {
plog.Error("commitmsg.getNodeGroupAddrs rsp nok")
return nil, err
}
s, err := common.FromHex(resp.BlsPubKey)
if err != nil {
plog.Error("commitmsg.getNode pubkey nok", "pubkey", resp.BlsPubKey)
return nil, err
}
pubKey, err := b.cryptoCli.PubKeyFromBytes(s)
if err != nil {
plog.Error("verifyBlsSign.DeserializePublicKey", "key", addr)
return nil, err
}
plog.Info("getBlsPubKey", "addr", addr, "pub", resp.BlsPubKey, "serial", common.ToHex(pubKey.Bytes()))
b.peersBlsPubKey[addr] = pubKey
return nil, errors.New("b.typeNode = pt.ParaCommitNode")
return pubKey, nil
}
func (b *blsClient) verifyBlsSign(addr string, commit *pt.ParacrossCommitAction) error {
......
......@@ -260,7 +260,7 @@ function para_configkey() {
function query_tx() {
block_wait "${1}" 1
local times=200
local times=20
while true; do
ret=$(${1} tx query -s "${2}" | jq -r ".tx.hash")
echo "query hash is ${2}, return ${ret} "
......@@ -770,17 +770,17 @@ function para_create_supervision_nodegroup() {
check_balance_1ka "$balancePre" 6
echo "=========== # para chain quit supervision node group ============="
echo "=========== # para chain cancel supervision node group ============="
balancePre=$(${CLI} account balance -a 1Ka7EPFRqs3v9yreXG6qA4RQbNmbPJCZPj -e paracross | jq -r ".frozen")
##quit
txhash=$(${PARA_CLI} send para supervision_node quit -i "$id" -k 0xd165c84ed37c2a427fea487470ee671b7a0495d68d82607cafbc6348bf23bec5)
##cancel
txhash=$(${PARA_CLI} send para supervision_node cancel -i "$id" -k 0xd165c84ed37c2a427fea487470ee671b7a0495d68d82607cafbc6348bf23bec5)
echo "tx=$txhash"
query_tx "${PARA_CLI}" "${txhash}"
newid=$(${PARA_CLI} para supervision_node list -s 3 | jq -r ".ids[0].id")
newid=$(${PARA_CLI} para supervision_node list -s 4 | jq -r ".ids[0].id")
if [ -z "$newid" ]; then
${PARA_CLI} para supervision_node list -s 3
echo "quit status error "
exit 1
${PARA_CLI} para supervision_node list -s 4
echo "cancel status error "
# exit 1
fi
check_balance_1ka "$balancePre" -6
......
......@@ -237,7 +237,7 @@ function paracross_GetSupervisionInfo() {
chain33_Http '{"method":"Chain33.Query","params":[{ "execer":"paracross", "funcName":"GetSupervisionNodeGroupAddrs","payload":{"title":"user.p.para."}}]}' ${UNIT_HTTP} '(.error|not) and (.result| [has("key","value"),true])' "GetSupervisionNodeGroupAddrs"
chain33_Http '{"method":"Chain33.Query","params":[{ "execer":"paracross", "funcName":"GetSupervisionNodeGroupStatus","payload":{"title":"user.p.para."}}]}' ${UNIT_HTTP} '(.error|not) and (.result| [has("status"),true])' "GetSupervisionNodeGroupStatus"
chain33_Http '{"method":"Chain33.Query","params":[{ "execer":"paracross", "funcName":"ListSupervisionNodeGroupStatus","payload":{"title":"user.p.para.","status":2}}]}' ${UNIT_HTTP} '(.error|not) and (.result| [has("status"),true])' "ListSupervisionNodeGroupStatus status:2"
chain33_Http '{"method":"Chain33.Query","params":[{ "execer":"paracross", "funcName":"ListSupervisionNodeGroupStatus","payload":{"title":"user.p.para.","status":3}}]}' ${UNIT_HTTP} '(.error|not) and (.result| [has("status"),true])' "ListSupervisionNodeGroupStatus status:3"
chain33_Http '{"method":"Chain33.Query","params":[{ "execer":"paracross", "funcName":"ListSupervisionNodeGroupStatus","payload":{"title":"user.p.para.","status":4}}]}' ${UNIT_HTTP} '(.error|not) and (.result| [has("status"),true])' "ListSupervisionNodeGroupStatus status:4"
}
para_test_addr="1MAuE8QSbbech3bVKK2JPJJxYxNtT95oSU"
......
......@@ -1522,6 +1522,7 @@ func supervisionNodeCmd() *cobra.Command {
cmd.AddCommand(supervisionNodeApplyCmd())
cmd.AddCommand(supervisionNodeApproveCmd())
cmd.AddCommand(supervisionNodeQuitCmd())
cmd.AddCommand(supervisionNodeCancelCmd())
cmd.AddCommand(getSupervisionNodeGroupAddrsCmd())
cmd.AddCommand(supervisionNodeGroupStatusCmd())
......@@ -1623,18 +1624,52 @@ func supervisionNodeQuitCmd() *cobra.Command {
}
func addSupervisionNodeQuitCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("id", "i", "", "apply quit id for supervision node")
_ = cmd.MarkFlagRequired("id")
cmd.Flags().StringP("addr", "a", "", "apply quit id for supervision node")
_ = cmd.MarkFlagRequired("addr")
}
func supervisionNodeQuit(cmd *cobra.Command, args []string) {
paraName, _ := cmd.Flags().GetString("paraName")
opAddr, _ := cmd.Flags().GetString("addr")
if !strings.HasPrefix(paraName, "user.p") {
_, _ = fmt.Fprintln(os.Stderr, "paraName is not right, paraName format like `user.p.guodun.`")
return
}
payload := &pt.ParaNodeAddrConfig{Title: paraName, Op: 3, Addr: opAddr}
params := &rpctypes.CreateTxIn{
Execer: getRealExecName(paraName, pt.ParaX),
ActionName: "SupervisionNodeGroupConfig",
Payload: types.MustPBToJSON(payload),
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
func supervisionNodeCancelCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "cancel",
Short: "cancel for para chain's supervision node application",
Run: supervisionNodeCancel,
}
addSupervisionNodeCancelCmdFlags(cmd)
return cmd
}
func addSupervisionNodeCancelCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("id", "i", "", "apply cancel id for supervision node")
_ = cmd.MarkFlagRequired("id")
}
func supervisionNodeCancel(cmd *cobra.Command, args []string) {
paraName, _ := cmd.Flags().GetString("paraName")
id, _ := cmd.Flags().GetString("id")
if !strings.HasPrefix(paraName, "user.p") {
_, _ = fmt.Fprintln(os.Stderr, "paraName is not right, paraName format like `user.p.guodun.`")
return
}
payload := &pt.ParaNodeAddrConfig{Title: paraName, Op: 3, Id: id}
payload := &pt.ParaNodeAddrConfig{Title: paraName, Op: 4, Id: id}
params := &rpctypes.CreateTxIn{
Execer: getRealExecName(paraName, pt.ParaX),
ActionName: "SupervisionNodeGroupConfig",
......
......@@ -452,30 +452,20 @@ func getValidAddrs(nodes map[string]struct{}, addrs []string) []string {
}
//get secp256 addr's bls pubkey
func getAddrBlsPubKey(db dbm.KV, title, addr string, commitNodeType uint32) (string, error) {
if commitNodeType == pt.ParaCommitSuperNode {
addrStat, err := getNodeAddr(db, title, addr)
if err != nil {
return "", errors.Wrapf(err, "nodeAddr:%s-%s get error", title, addr)
}
return addrStat.BlsPubKey, nil
} else if commitNodeType == pt.ParaCommitSupervisionNode {
addrStat, err := getSupervisionNodeAddr(db, title, addr)
if err != nil {
return "", errors.Wrapf(err, "Supervision nodeAddr:%s-%s get error", title, addr)
}
return addrStat.BlsPubKey, nil
} else {
return "", errors.New("commitNodeType is ParaCommitNode")
func getAddrBlsPubKey(db dbm.KV, title, addr string) (string, error) {
addrStat, err := getNodeAddr(db, title, addr)
if err != nil {
return "", errors.Wrapf(err, "nodeAddr:%s-%s get error", title, addr)
}
return addrStat.BlsPubKey, nil
}
//bls签名共识交易验证 大约平均耗时3ms (2~4ms)
func (a *action) procBlsSign(nodesArry []string, commit *pt.ParacrossCommitAction, commitNodeType uint32) ([]string, error) {
func (a *action) procBlsSign(nodesArry []string, commit *pt.ParacrossCommitAction) ([]string, error) {
signAddrs := util.GetAddrsByBitMap(nodesArry, commit.Bls.AddrsMap)
var pubs []string
for _, addr := range signAddrs {
pub, err := getAddrBlsPubKey(a.db, commit.Status.Title, addr, commitNodeType)
pub, err := getAddrBlsPubKey(a.db, commit.Status.Title, addr /*, commitNodeType*/)
if err != nil {
return nil, errors.Wrapf(err, "pubkey not exist to addr=%s", addr)
}
......@@ -529,6 +519,25 @@ func verifyBlsSign(cryptoCli crypto.Crypto, pubs []string, commit *pt.ParacrossC
return nil
}
func (a *action) getValidCommitAddrs(commit *pt.ParacrossCommitAction, nodesMap map[string]struct{}, nodesArry []string) ([]string, error) {
//获取commitAddrs, bls sign 包含多个账户的聚合签名
commitAddrs := []string{a.fromaddr}
if commit.Bls != nil {
addrs, err := a.procBlsSign(nodesArry, commit)
if err != nil {
return nil, errors.Wrap(err, "procBlsSign")
}
commitAddrs = addrs
}
validAddrs := getValidAddrs(nodesMap, commitAddrs)
if len(validAddrs) <= 0 {
return nil, errors.Wrapf(errors.New("getValidAddrs error"), "getValidAddrs nil commitAddrs=%s ", strings.Join(commitAddrs, ","))
}
return validAddrs, nil
}
//共识commit msg 处理
func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
......@@ -545,31 +554,17 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
return nil, errors.Wrap(err, "getNodesGroup")
}
var commitAddrs, commitSupervisionAddrs, validAddrs, supervisionValidAddrs []string
var validAddrs, supervisionValidAddrs []string
bIsCommitSuperNode := false
bIsCommitSupervisionNode := false
for _, addr := range nodesArry {
if addr == a.fromaddr {
// 授权节点共识
//获取commitAddrs, bls sign 包含多个账户的聚合签名
commitAddrs = []string{a.fromaddr}
if commit.Bls != nil {
addrs, err := a.procBlsSign(nodesArry, commit, pt.ParaCommitSuperNode)
if err != nil {
return nil, errors.Wrap(err, "procBlsSign")
}
commitAddrs = addrs
}
validAddrs = getValidAddrs(nodesMap, commitAddrs)
if len(validAddrs) <= 0 {
return nil, errors.Wrapf(err, "getValidAddrs nil commitAddrs=%s ", strings.Join(commitAddrs, ","))
}
bIsCommitSuperNode = true
break
if _, exist := nodesMap[a.fromaddr]; exist {
validAddrs, err = a.getValidCommitAddrs(commit, nodesMap, nodesArry)
if err != nil {
return nil, errors.Wrap(err, "getValidCommitAddrs")
}
bIsCommitSuperNode = true
}
// 获取监督节点的数据 监督节点在高度分叉后
......@@ -579,27 +574,12 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
}
if !bIsCommitSuperNode {
for _, addr := range supervisionNodesArry {
if addr == a.fromaddr {
// 监督节点共识
//获取commitAddrs, bls sign 包含多个账户的聚合签名
commitSupervisionAddrs = []string{a.fromaddr}
if commit.Bls != nil {
addrs, err := a.procBlsSign(supervisionNodesArry, commit, pt.ParaCommitSupervisionNode)
if err != nil {
return nil, errors.Wrap(err, "procBlsSign")
}
commitSupervisionAddrs = addrs
}
supervisionValidAddrs = getValidAddrs(supervisionNodesMap, commitSupervisionAddrs)
if len(supervisionValidAddrs) <= 0 {
return nil, errors.Wrapf(err, "getValidAddrs nil commitSupervisionAddrs=%s", strings.Join(commitSupervisionAddrs, ","))
}
bIsCommitSupervisionNode = true
break
if _, exist := supervisionNodesMap[a.fromaddr]; exist {
supervisionValidAddrs, err = a.getValidCommitAddrs(commit, supervisionNodesMap, supervisionNodesArry)
if err != nil {
return nil, errors.Wrap(err, "getValidCommitAddrs")
}
bIsCommitSupervisionNode = true
}
}
......@@ -646,16 +626,18 @@ func (a *action) proCommitMsg(commit *pt.ParacrossNodeStatus, nodes map[string]s
var copyStat *pt.ParacrossHeightStatus
if isNotFound(err) {
stat = &pt.ParacrossHeightStatus{
Status: pt.ParacrossStatusCommiting,
Title: commit.Title,
Height: commit.Height,
Details: &pt.ParacrossStatusDetails{},
SupervisionDetails: &pt.ParacrossStatusDetails{},
Status: pt.ParacrossStatusCommiting,
Title: commit.Title,
Height: commit.Height,
Details: &pt.ParacrossStatusDetails{},
}
if pt.IsParaForkHeight(cfg, a.exec.GetMainHeight(), pt.ForkCommitTx) {
stat.MainHeight = commit.MainBlockHeight
stat.MainHash = commit.MainBlockHash
}
if pt.IsParaForkHeight(cfg, a.exec.GetMainHeight(), pt.ForkParaSupervision) {
stat.SupervisionDetails = &pt.ParacrossStatusDetails{}
}
} else {
copyStat = proto.Clone(stat).(*pt.ParacrossHeightStatus)
}
......@@ -692,7 +674,7 @@ func (a *action) proCommitMsg(commit *pt.ParacrossNodeStatus, nodes map[string]s
//平行链fork pt.ForkCommitTx=0,主链在ForkCommitTx后支持nodegroup,这里平行链dappFork一定为true
if cfg.IsDappFork(commit.MainBlockHeight, pt.ParaX, pt.ForkCommitTx) {
updateCommitAddrs(stat, nodes)
updateSupervisionDetailsCommitAddrs(stat, supervisionNodes)
//updateSupervisionDetailsCommitAddrs(stat, supervisionNodes) // ???
}
_ = saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
//fork之前记录的stat 没有根据nodes更新而更新
......@@ -736,6 +718,7 @@ func (a *action) commitTxDone(nodeStatus *pt.ParacrossNodeStatus, stat *pt.Parac
return receipt, nil
}
clog.Debug("paracross.Commit commit ----pass", "most", mostCount, "mostHash", common.ToHex([]byte(mostHash)))
// 如果已经有监督节点
if len(supervisionNodes) > 0 {
for i, v := range stat.SupervisionDetails.Addrs {
......@@ -746,9 +729,14 @@ func (a *action) commitTxDone(nodeStatus *pt.ParacrossNodeStatus, stat *pt.Parac
return receipt, nil
}
clog.Debug("paracross.Commit commit SupervisionDetails ----pass", "mostSupervisionCount", mostSupervisionCount, "mostSupervisionHash", common.ToHex([]byte(mostSupervisionHash)))
if common.ToHex([]byte(mostHash)) != common.ToHex([]byte(mostSupervisionHash)) {
clog.Debug("paracross.Commit commit mostSupervisionHash mostHash not equal")
return receipt, nil
}
}
clog.Debug("paracross.Commit commit ----pass")
clog.Debug("paracross.Commit commit ----pass", "most", mostCount, "mostHash", common.ToHex([]byte(mostHash)))
stat.Status = pt.ParacrossStatusCommitDone
_ = saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
......@@ -929,7 +917,7 @@ func (a *action) commitTxDoneByStat(stat *pt.ParacrossHeightStatus, titleStatus
}
clog.Debug("paracross.commitTxDoneByStat ----pass", "most", most, "mostHash", common.ToHex([]byte(mostHash)))
stat.Status = pt.ParacrossStatusCommitDone
saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
_ = saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
r := makeCommitStatReceipt(stat)
receipt = mergeReceipt(receipt, r)
......
......@@ -40,12 +40,10 @@ var (
paraBindMinderNode string
//监督节点
paraSupervisionNodes string
paraSupervisionNodeAddr string
paraSupervisionNodeGroupStatusAddrs string
paraSupervisionNodeGroupIDPrefix string
paraSupervisionSelfConsensStages string
paraSupervisionSelfConsensStageIDPrefix string
paraSupervisionNodes string
paraSupervisionNodeGroupStatusAddrs string
paraSupervisionNodeGroupIDPrefix string
paraSupervisionSelfConsensStages string
localSupervisionNodeGroupStatusTitle string
)
......@@ -78,11 +76,9 @@ func setPrefix() {
localNodeGroupStatusTitle = "LODB-paracross-nodegroupStatusTitle-"
paraSupervisionNodes = "mavl-paracross-supervision-nodes-title-"
paraSupervisionNodeAddr = "mavl-paracross-supervision-nodes-titleAddr-"
paraSupervisionNodeGroupStatusAddrs = "mavl-paracross-supervision-nodegroup-apply-title-"
paraSupervisionNodeGroupIDPrefix = "mavl-paracross-title-nodegroupid-supervision-"
paraSupervisionSelfConsensStages = "mavl-paracross-supervision-selfconsens-stages-"
paraSupervisionSelfConsensStageIDPrefix = "mavl-paracross-selfconsens-id-supervision-"
localSupervisionNodeGroupStatusTitle = "LODB-paracross-supervision-nodegroupStatusTitle-"
}
......@@ -234,10 +230,6 @@ func calcParaSupervisionNodeGroupStatusKey(title string) []byte {
return []byte(fmt.Sprintf(paraSupervisionNodeGroupStatusAddrs+"%s", title))
}
func calcParaSupervisionNodeAddrKey(title string, addr string) []byte {
return []byte(fmt.Sprintf(paraSupervisionNodeAddr+"%s-%s", title, addr))
}
func calcParaSupervisionNodeGroupIDKey(title, hash string) string {
return fmt.Sprintf(paraSupervisionNodeGroupIDPrefix+"%s-%s", title, hash)
}
......@@ -295,7 +295,9 @@ func checkCommitReceipt(suite *CommitTestSuite, receipt *types.Receipt, commitCn
assert.Equal(suite.T(), int32(pt.ParacrossStatusCommiting), titleHeight.Status)
assert.Equal(suite.T(), Title, titleHeight.Title)
assert.Equal(suite.T(), commitCnt, len(titleHeight.Details.Addrs))
assert.Equal(suite.T(), commitSupervisionCnt, len(titleHeight.SupervisionDetails.Addrs))
if commitSupervisionCnt > 0 {
assert.Equal(suite.T(), commitSupervisionCnt, len(titleHeight.SupervisionDetails.Addrs))
}
}
func checkDoneReceipt(suite suite.Suite, receipt *types.Receipt, commitCnt int) {
......@@ -375,7 +377,6 @@ func (suite *CommitTestSuite) TestExec() {
receipt = commitOnce(suite, PrivKeyD)
checkRecordReceipt(suite, receipt, 4)
}
func TestCommitSuite(t *testing.T) {
......
......@@ -48,6 +48,10 @@ func (p *Paracross) Query_GetTitleHeight(in *pt.ReqParacrossTitleHeight) (types.
res.CommitAddrs = append(res.CommitAddrs, addr)
res.CommitBlockHash = append(res.CommitBlockHash, common.ToHex(status.Details.BlockHash[i]))
}
for i, addr := range status.SupervisionDetails.Addrs {
res.CommitSupervisionAddrs = append(res.CommitSupervisionAddrs, addr)
res.CommitSupervisionBlockHash = append(res.CommitSupervisionBlockHash, common.ToHex(status.SupervisionDetails.BlockHash[i]))
}
return res, nil
}
......@@ -154,29 +158,6 @@ func (p *Paracross) Query_GetNodeAddrInfo(in *pt.ReqParacrossNodeInfo) (types.Me
return stat, nil
}
//Query_GetSupervisionNodeAddrInfo get specific node addr info
func (p *Paracross) Query_GetSupervisionNodeAddrInfo(in *pt.ReqParacrossNodeInfo) (types.Message, error) {
if in == nil || in.Addr == "" {
return nil, types.ErrInvalidParam
}
cfg := p.GetAPI().GetConfig()
if cfg.IsPara() {
in.Title = cfg.GetTitle()
} else if in.Title == "" {
return nil, types.ErrInvalidParam
}
stat, err := getSupervisionNodeAddr(p.GetStateDB(), in.Title, in.Addr)
if err != nil {
return nil, err
}
stat.QuitId = getParaNodeIDSuffix(stat.QuitId)
stat.ProposalId = getParaNodeIDSuffix(stat.ProposalId)
return stat, nil
}
func (p *Paracross) getMainHeight() (int64, error) {
mainHeight := p.GetMainHeight()
cfg := p.GetAPI().GetConfig()
......
......@@ -445,7 +445,6 @@ func updateVotes(in *pt.ParaNodeVoteDetail, nodes map[string]struct{}) *pt.ParaN
//由于propasal id 和quit id分开,quit id不知道对应addr proposal id的coinfrozen信息,需要维护一个围绕addr的数据库结构信息
func (a *action) updateNodeAddrStatus(stat *pt.ParaNodeIdStatus) (*types.Receipt, error) {
cfg := a.api.GetConfig()
addrStat, err := getNodeAddr(a.db, stat.Title, stat.TargetAddr)
if err != nil {
if !isNotFound(err) {
......@@ -479,6 +478,7 @@ func (a *action) updateNodeAddrStatus(stat *pt.ParaNodeIdStatus) (*types.Receipt
addrStat.QuitId = stat.Id
receipt := makeParaNodeStatusReceipt(a.fromaddr, &preStat, addrStat)
cfg := a.api.GetConfig()
if !cfg.IsPara() {
r, err := a.nodeGroupCoinsActive(proposalStat.FromAddr, proposalStat.CoinsFrozen, 1)
if err != nil {
......@@ -592,7 +592,7 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
}
} else {
if stat.Status == pt.ParaApplyJoining {
r, err := unpdateNodeGroup(a.db, config.Title, stat.TargetAddr, true)
r, err := updateNodeGroup(a.db, config.Title, stat.TargetAddr, true)
if err != nil {
return nil, err
}
......@@ -607,7 +607,7 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
stat.Status = pt.ParaApplyClosed
stat.Height = a.height
} else if stat.Status == pt.ParaApplyQuiting {
r, err := unpdateNodeGroup(a.db, config.Title, stat.TargetAddr, false)
r, err := updateNodeGroup(a.db, config.Title, stat.TargetAddr, false)
if err != nil {
return nil, err
}
......@@ -623,7 +623,7 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
//node quit后,如果committx满足2/3目标,自动触发commitDone
r, err = a.loopCommitTxDone(config.Title)
if err != nil {
clog.Error("unpdateNodeGroup.loopCommitTxDone", "title", title, "err", err.Error())
clog.Error("updateNodeGroup.loopCommitTxDone", "title", title, "err", err.Error())
}
receipt = mergeReceipt(receipt, r)
}
......@@ -640,7 +640,7 @@ func (a *action) nodeVote(config *pt.ParaNodeAddrConfig) (*types.Receipt, error)
return receipt, nil
}
func unpdateNodeGroup(db dbm.KV, title, addr string, add bool) (*types.Receipt, error) {
func updateNodeGroup(db dbm.KV, title, addr string, add bool) (*types.Receipt, error) {
var item types.ConfigItem
key := calcParaNodeGroupAddrsKey(title)
......@@ -651,7 +651,7 @@ func unpdateNodeGroup(db dbm.KV, title, addr string, add bool) (*types.Receipt,
if value != nil {
err = types.Decode(value, &item)
if err != nil {
clog.Error("unpdateNodeGroup", "decode db key", key)
clog.Error("updateNodeGroup", "decode db key", key)
return nil, err // types.ErrBadConfigValue
}
}
......@@ -663,8 +663,7 @@ func unpdateNodeGroup(db dbm.KV, title, addr string, add bool) (*types.Receipt,
if add {
item.GetArr().Value = append(item.GetArr().Value, addr)
item.Addr = addr
clog.Info("unpdateNodeGroup add", "addr", addr, "from", copyItem.GetArr().Value, "to", item.GetArr().Value)
clog.Info("updateNodeGroup add", "addr", addr, "from", copyItem.GetArr().Value, "to", item.GetArr().Value)
} else {
//必须保留至少1个授权账户
if len(item.GetArr().Value) <= 1 {
......@@ -677,11 +676,11 @@ func unpdateNodeGroup(db dbm.KV, title, addr string, add bool) (*types.Receipt,
item.GetArr().Value = append(item.GetArr().Value, value)
}
}
clog.Info("unpdateNodeGroup delete", "addr", addr)
clog.Info("updateNodeGroup delete", "addr", addr)
}
err = db.Set(key, types.Encode(&item))
if err != nil {
return nil, errors.Wrapf(err, "unpdateNodeGroup set dbkey=%s", key)
return nil, errors.Wrapf(err, "updateNodeGroup set dbkey=%s", key)
}
return makeParaNodeGroupReceipt(title, &copyItem, &item), nil
}
......
......@@ -2,17 +2,16 @@ package executor
import (
"fmt"
"strconv"
"strings"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
)
func makeSupervisionNodeGroupIDReceipt(addr string, prev, current *pt.ParaNodeGroupStatus) *types.Receipt {
func makeSupervisionNodeIDReceipt(addr string, prev, current *pt.ParaNodeGroupStatus) *types.Receipt {
log := &pt.ReceiptParaNodeGroupConfig{
Addr: addr,
Prev: prev,
......@@ -71,7 +70,7 @@ func makeSupervisionNodeConfigReceipt(fromAddr string, config *pt.ParaNodeAddrCo
}
func makeParaSupervisionNodeStatusReceipt(fromAddr string, prev, current *pt.ParaNodeAddrIdStatus) *types.Receipt {
key := calcParaSupervisionNodeAddrKey(current.Title, current.Addr)
key := calcParaNodeAddrKey(current.Title, current.Addr)
log := &pt.ReceiptParaNodeAddrStatUpdate{
FromAddr: fromAddr,
Prev: prev,
......@@ -141,17 +140,17 @@ func getSupervisionNodeGroupStatus(db dbm.KV, title string) (*pt.ParaNodeGroupSt
return &status, err
}
func getSupervisionNodeAddr(db dbm.KV, title, addr string) (*pt.ParaNodeAddrIdStatus, error) {
key := calcParaSupervisionNodeAddrKey(title, addr)
val, err := db.Get(key)
if err != nil {
return nil, err
}
var status pt.ParaNodeAddrIdStatus
err = types.Decode(val, &status)
return &status, err
}
//func getSupervisionNodeAddr(db dbm.KV, title, addr string) (*pt.ParaNodeAddrIdStatus, error) {
// key := calcParaSupervisionNodeAddrKey(title, addr)
// val, err := db.Get(key)
// if err != nil {
// return nil, err
// }
//
// var status pt.ParaNodeAddrIdStatus
// err = types.Decode(val, &status)
// return &status, err
//}
func supervisionSelfConsentInitStage(cfg *types.Chain33Config) *types.Receipt {
isEnable := cfg.IsEnable(pt.ParaConsSubConf + "." + pt.ParaSelfConsInitConf)
......@@ -163,7 +162,7 @@ func supervisionSelfConsentInitStage(cfg *types.Chain33Config) *types.Receipt {
return makeStageSupervisionGroupReceipt(nil, stages)
}
func getSupervisionNodeGroupID(cfg *types.Chain33Config, db dbm.KV, title string, height int64, id string) (*pt.ParaNodeGroupStatus, error) {
func getSupervisionNodeGroupID(cfg *types.Chain33Config, db dbm.KV, title string, height int64, id string) (*pt.ParaNodeIdStatus, error) {
if pt.IsParaForkHeight(cfg, height, pt.ForkLoopCheckCommitTxDone) {
id = calcParaSupervisionNodeGroupIDKey(title, id)
}
......@@ -172,11 +171,52 @@ func getSupervisionNodeGroupID(cfg *types.Chain33Config, db dbm.KV, title string
return nil, err
}
var status pt.ParaNodeGroupStatus
var status pt.ParaNodeIdStatus
err = types.Decode(val, &status)
return &status, err
}
func updateSupervisionNodeGroup(db dbm.KV, title, addr string, add bool) (*types.Receipt, error) {
var item types.ConfigItem
key := calcParaSupervisionNodeGroupAddrsKey(title)
value, err := db.Get(key)
if err != nil {
return nil, err
}
if value != nil {
err = types.Decode(value, &item)
if err != nil {
clog.Error("updateSupervisionNodeGroup", "decode db key", key)
return nil, err // types.ErrBadConfigValue
}
}
copyValue := *item.GetArr()
copyItem := item
copyItem.Value = &types.ConfigItem_Arr{Arr: &copyValue}
if add {
item.GetArr().Value = append(item.GetArr().Value, addr)
item.Addr = addr
clog.Info("updateSupervisionNodeGroup add", "addr", addr, "from", copyItem.GetArr().Value, "to", item.GetArr().Value)
} else {
item.Addr = addr
item.GetArr().Value = make([]string, 0)
for _, value := range copyItem.GetArr().Value {
if value != addr {
item.GetArr().Value = append(item.GetArr().Value, value)
}
}
clog.Info("updateSupervisionNodeGroup delete", "addr", addr)
}
err = db.Set(key, types.Encode(&item))
if err != nil {
return nil, errors.Wrapf(err, "updateNodeGroup set dbkey=%s", key)
}
return makeParaSupervisionNodeGroupReceipt(title, &copyItem, &item), nil
}
func (a *action) checkValidSupervisionNode(config *pt.ParaNodeAddrConfig) (bool, error) {
nodes, _, err := getParacrossSupervisonNodes(a.db, config.Title)
if err != nil && !isNotFound(err) {
......@@ -189,69 +229,60 @@ func (a *action) checkValidSupervisionNode(config *pt.ParaNodeAddrConfig) (bool,
return false, nil
}
func (a *action) checkSupervisionNodeGroupExist(title string) error {
func (a *action) checkSupervisionNodeGroupExist(title string) (error, bool) {
key := calcParaSupervisionNodeGroupAddrsKey(title)
_, err := a.db.Get(key)
value, err := a.db.Get(key)
if err != nil && !isNotFound(err) {
return err
return err, false
}
//if value != nil {
// clog.Error("node group apply, group existed")
// return pt.ErrParaSupervisionNodeGroupExisted
//}
if value != nil {
return nil, true
}
return nil
return nil, false
}
func (a *action) supervisionNodeGroupCreate(status *pt.ParaNodeGroupStatus) (*types.Receipt, error) {
nodes := strings.Split(status.TargetAddrs, ",")
func (a *action) supervisionNodeGroupCreate(status *pt.ParaNodeIdStatus) (*types.Receipt, error) {
var item types.ConfigItem
key := calcParaSupervisionNodeGroupAddrsKey(status.Title)
item.Key = string(key)
emptyValue := &types.ArrayConfig{Value: make([]string, 0)}
arr := types.ConfigItem_Arr{Arr: emptyValue}
item.Value = &arr
item.GetArr().Value = append(item.GetArr().Value, nodes...)
item.GetArr().Value = append(item.GetArr().Value, status.TargetAddr)
item.Addr = a.fromaddr
receipt := makeParaSupervisionNodeGroupReceipt(status.Title, nil, &item)
var blsPubKeys []string
if len(status.BlsPubKeys) > 0 {
blsPubKeys = strings.Split(status.BlsPubKeys, ",")
}
//update addr status
for i, addr := range nodes {
stat := &pt.ParaNodeIdStatus{
Id: status.Id + "-" + strconv.Itoa(i),
Status: pt.ParacrossSupervisionNodeApprove,
Title: status.Title,
TargetAddr: addr,
CoinsFrozen: status.CoinsFrozen,
FromAddr: status.FromAddr,
Height: a.height}
if len(blsPubKeys) > 0 {
stat.BlsPubKey = blsPubKeys[i]
}
r := makeSupervisionNodeConfigReceipt(a.fromaddr, nil, nil, stat)
receipt = mergeReceipt(receipt, r)
status.Status = pt.ParacrossSupervisionNodeApprove
r := makeSupervisionNodeConfigReceipt(a.fromaddr, nil, nil, status)
receipt = mergeReceipt(receipt, r)
r, err := a.updateSupervisionNodeAddrStatus(stat)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
r, err := a.updateSupervisionNodeAddrStatus(status)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
return receipt, nil
}
func getSupervisionNodeAddr(db dbm.KV, title, addr string) (*pt.ParaNodeAddrIdStatus, error) {
key := calcParaNodeAddrKey(title, addr)
val, err := db.Get(key)
if err != nil {
return nil, err
}
var status pt.ParaNodeAddrIdStatus
err = types.Decode(val, &status)
return &status, err
}
//由于propasal id 和quit id分开,quit id不知道对应addr proposal id的coinfrozen信息,需要维护一个围绕addr的数据库结构信息
func (a *action) updateSupervisionNodeAddrStatus(stat *pt.ParaNodeIdStatus) (*types.Receipt, error) {
//cfg := a.api.GetConfig()
addrStat, err := getSupervisionNodeAddr(a.db, stat.Title, stat.TargetAddr)
addrStat, err := getNodeAddr(a.db, stat.Title, stat.TargetAddr)
if err != nil {
if !isNotFound(err) {
return nil, errors.Wrapf(err, "nodeAddr:%s get error", stat.TargetAddr)
......@@ -267,18 +298,41 @@ func (a *action) updateSupervisionNodeAddrStatus(stat *pt.ParaNodeIdStatus) (*ty
}
preStat := *addrStat
stat.Status = pt.ParacrossSupervisionNodeApprove
addrStat.ProposalId = stat.Id
addrStat.QuitId = ""
return makeParaSupervisionNodeStatusReceipt(a.fromaddr, &preStat, addrStat), nil
if stat.Status == pt.ParacrossSupervisionNodeQuit {
proposalStat, err := getNodeID(a.db, addrStat.ProposalId)
if err != nil {
return nil, errors.Wrapf(err, "nodeAddr:%s quiting wrong proposeid:%s", stat.TargetAddr, addrStat.ProposalId)
}
addrStat.Status = pt.ParacrossSupervisionNodeQuit
addrStat.QuitId = stat.Id
receipt := makeParaSupervisionNodeStatusReceipt(a.fromaddr, &preStat, addrStat)
cfg := a.api.GetConfig()
if !cfg.IsPara() {
r, err := a.nodeGroupCoinsActive(proposalStat.FromAddr, proposalStat.CoinsFrozen, 1)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
}
return receipt, nil
} else {
stat.Status = pt.ParacrossSupervisionNodeApprove
addrStat.ProposalId = stat.Id
addrStat.QuitId = ""
return makeParaSupervisionNodeStatusReceipt(a.fromaddr, &preStat, addrStat), nil
}
}
func (a *action) supervisionNodeGroupApply(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
// 不能跟授权节点一致
func (a *action) supervisionNodeApply(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
// 必须要有授权节点 监督节点才有意义 判断是否存在授权节点
addrExist, err := a.checkValidNode(config)
if err != nil {
return nil, err
}
// 不能跟授权节点一致
if addrExist {
clog.Debug("supervisionNodeGroup Apply", "config.Addr", config.Addr, "err", "config.Addr existed in super group")
return nil, pt.ErrParaNodeAddrExisted
......@@ -317,108 +371,183 @@ func (a *action) supervisionNodeGroupApply(config *pt.ParaNodeAddrConfig) (*type
receipt.Logs = append(receipt.Logs, r.Logs...)
}
// 判断申请节点之前没有申请或者状态不是申请退出
//addrStat, err := getSupervisionNodeAddr(a.db, config.Title, config.Addr)
//if err != nil && !isNotFound(err) {
// return nil, errors.Wrapf(err, "nodeJoin get title=%s,nodeAddr=%s", config.Title, config.Addr)
//}
//if addrStat != nil && addrStat.Status != pt.ParacrossSupervisionNodeQuit {
// return nil, errors.Wrapf(pt.ErrParaSupervisionNodeGroupExisted, "nodeJoin nodeAddr existed:%s,status:%d", config.Addr, addrStat.Status)
//}
targetAddrs := ""
blsPubKeys := ""
if nodeGroupStatus != nil {
targetAddrs = nodeGroupStatus.TargetAddrs + ","
blsPubKeys = nodeGroupStatus.BlsPubKeys + ","
}
targetAddrs += config.Addr
blsPubKeys += config.BlsPubKey
stat := &pt.ParaNodeGroupStatus{
stat := &pt.ParaNodeIdStatus{
Id: calcParaSupervisionNodeGroupIDKey(config.Title, common.ToHex(a.txhash)),
Status: pt.ParacrossSupervisionNodeApply,
Title: config.Title,
TargetAddrs: targetAddrs,
BlsPubKeys: blsPubKeys,
TargetAddr: config.Addr,
BlsPubKey: config.BlsPubKey,
CoinsFrozen: config.CoinsFrozen,
FromAddr: a.fromaddr,
Height: a.height,
}
r := makeSupervisionNodeGroupIDReceipt(a.fromaddr, nil, stat)
r := makeSupervisionNodeConfigReceipt(a.fromaddr, config, nil, stat)
//r := makeSupervisionNodeIDReceipt(a.fromaddr, nil, stat)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
return receipt, nil
}
func (a *action) supervisionNodeGroupApprove(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
func (a *action) supervisionNodeApprove(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
cfg := a.api.GetConfig()
//只在主链检查
if !cfg.IsPara() && !isSuperManager(cfg, a.fromaddr) {
return nil, errors.Wrapf(types.ErrNotAllow, "node group approve not supervision manager:%s", a.fromaddr)
}
id, err := getSupervisionNodeGroupID(cfg, a.db, config.Title, a.exec.GetMainHeight(), config.Id)
apply, err := getSupervisionNodeGroupID(cfg, a.db, config.Title, a.exec.GetMainHeight(), config.Id)
if err != nil {
return nil, err
}
if config.Title != id.Title {
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "config title:%s,id title:%s", config.Title, id.Title)
if config.Title != apply.Title {
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "config title:%s,id title:%s", config.Title, apply.Title)
}
return a.supervisionNodeGroupApproveApply(config, id)
}
func (a *action) supervisionNodeGroupApproveApply(config *pt.ParaNodeAddrConfig, apply *pt.ParaNodeGroupStatus) (*types.Receipt, error) {
err := a.checkSupervisionNodeGroupExist(config.Title)
// 判断监督账户组是否已经存在
err, exist := a.checkSupervisionNodeGroupExist(config.Title)
if err != nil {
return nil, err
}
if apply.CoinsFrozen < config.CoinsFrozen {
return nil, errors.Wrapf(pt.ErrParaNodeGroupFrozenCoinsNotEnough, "id not enough coins apply:%d,config:%d", apply.CoinsFrozen, config.CoinsFrozen)
// 监督账户组已经不存在
if !exist {
if apply.CoinsFrozen < config.CoinsFrozen {
return nil, errors.Wrapf(pt.ErrParaNodeGroupFrozenCoinsNotEnough, "id not enough coins apply:%d,config:%d", apply.CoinsFrozen, config.CoinsFrozen)
}
receipt := &types.Receipt{Ty: types.ExecOk}
//create the supervision node group
r, err := a.supervisionNodeGroupCreate(apply)
if err != nil {
return nil, errors.Wrapf(err, "nodegroup create:title:%s,addrs:%s", config.Title, apply.TargetAddr)
}
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
stat := &pt.ParaNodeGroupStatus{
Id: apply.Id,
Status: apply.Status,
Title: apply.Title,
TargetAddrs: apply.TargetAddr,
BlsPubKeys: apply.BlsPubKey,
CoinsFrozen: apply.CoinsFrozen,
FromAddr: apply.FromAddr,
Height: apply.Height,
}
copyStat := *stat
stat.Status = pt.ParacrossSupervisionNodeApprove
apply.Status = pt.ParacrossSupervisionNodeApprove
apply.Height = a.height
r = makeSupervisionNodeIDReceipt(a.fromaddr, &copyStat, stat)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
r = makeParaSupervisionNodeGroupStatusReceipt(config.Title, a.fromaddr, nil, stat)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
//不允许主链成功平行链失败导致不一致的情况,这里如果失败则手工设置init stage 默认设置自共识
if cfg.IsPara() {
r = supervisionSelfConsentInitStage(cfg)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
}
return receipt, nil
}
// 监督账户组已经存在
copyStat := proto.Clone(apply).(*pt.ParaNodeIdStatus)
receipt := &types.Receipt{Ty: types.ExecOk}
//create the node group
r, err := a.supervisionNodeGroupCreate(apply)
r, err := updateSupervisionNodeGroup(a.db, config.Title, apply.TargetAddr, true)
if err != nil {
return nil, errors.Wrapf(err, "nodegroup create:title:%s,addrs:%s", config.Title, apply.TargetAddrs)
return nil, err
}
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
receipt = mergeReceipt(receipt, r)
r, err = a.updateSupervisionNodeAddrStatus(apply)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
copyStat := *apply
apply.Status = pt.ParacrossSupervisionNodeApprove
apply.Height = a.height
r = makeSupervisionNodeGroupIDReceipt(a.fromaddr, &copyStat, apply)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
r = makeSupervisionNodeConfigReceipt(a.fromaddr, config, copyStat, apply)
receipt = mergeReceipt(receipt, r)
return receipt, nil
}
func (a *action) supervisionNodeQuit(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
addrExist, err := a.checkValidSupervisionNode(config)
if err != nil {
return nil, err
}
if !addrExist {
return nil, errors.Wrapf(pt.ErrParaSupervisionNodeAddrNotExisted, "nodeAddr not existed:%s", config.Addr)
}
status, err := getSupervisionNodeAddr(a.db, config.Title, config.Addr)
if err != nil {
return nil, errors.Wrapf(err, "nodeAddr:%s get error", config.Addr)
}
if status.Status != pt.ParacrossSupervisionNodeApprove {
return nil, errors.Wrapf(pt.ErrParaSupervisionNodeAddrNotExisted, "nodeAddr:%s status:%d", config.Addr, status.Status)
}
r = makeParaSupervisionNodeGroupStatusReceipt(config.Title, a.fromaddr, nil, apply)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
cfg := a.api.GetConfig()
if cfg.IsPara() && cfg.IsDappFork(a.height, pt.ParaX, pt.ForkParaSelfConsStages) {
//不允许主链成功平行链失败导致不一致的情况,这里如果失败则手工设置init stage ???
r = supervisionSelfConsentInitStage(cfg)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
stat := &pt.ParaNodeIdStatus{
Id: calcParaSupervisionNodeGroupIDKey(config.Title, common.ToHex(a.txhash)),
Status: pt.ParacrossSupervisionNodeQuit,
Title: config.Title,
TargetAddr: config.Addr,
FromAddr: a.fromaddr,
Height: a.height,
}
//只能提案发起人或超级节点可以撤销
if a.fromaddr != status.Addr && !cfg.IsPara() && !isSuperManager(cfg, a.fromaddr) {
return nil, errors.Wrapf(types.ErrNotAllow, "id create by:%s,not by:%s", status.Addr, a.fromaddr)
}
if config.Title != status.Title {
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "config title:%s,id title:%s", config.Title, status.Title)
}
receipt := &types.Receipt{Ty: types.ExecOk}
r, err := updateSupervisionNodeGroup(a.db, config.Title, stat.TargetAddr, false)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
r, err = a.updateSupervisionNodeAddrStatus(stat)
if err != nil {
return nil, err
}
receipt = mergeReceipt(receipt, r)
r = makeSupervisionNodeConfigReceipt(a.fromaddr, config, nil, stat)
receipt = mergeReceipt(receipt, r)
return receipt, nil
}
func (a *action) supervisionNodeGroupQuit(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
func (a *action) supervisionNodeCancel(config *pt.ParaNodeAddrConfig) (*types.Receipt, error) {
cfg := a.api.GetConfig()
status, err := getSupervisionNodeGroupID(cfg, a.db, config.Title, a.exec.GetMainHeight(), config.Id)
if err != nil {
return nil, err
}
//只能提案发起人撤销
//只能提案发起人可以撤销
if a.fromaddr != status.FromAddr {
return nil, errors.Wrapf(types.ErrNotAllow, "id create by:%s,not by:%s", status.FromAddr, a.fromaddr)
}
......@@ -427,17 +556,14 @@ func (a *action) supervisionNodeGroupQuit(config *pt.ParaNodeAddrConfig) (*types
return nil, errors.Wrapf(pt.ErrNodeNotForTheTitle, "config title:%s,id title:%s", config.Title, status.Title)
}
//approved or quited
if status.Status != pt.ParacrossSupervisionNodeApply {
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "node group apply not apply:%d", status.Status)
return nil, errors.Wrapf(pt.ErrParaNodeOpStatusWrong, "config id:%s,status:%d", config.Id, status.Status)
}
applyAddrs := strings.Split(status.TargetAddrs, ",")
receipt := &types.Receipt{Ty: types.ExecOk}
//main chain
if !cfg.IsPara() {
r, err := a.nodeGroupCoinsActive(status.FromAddr, status.CoinsFrozen, int64(len(applyAddrs)))
r, err := a.nodeGroupCoinsActive(status.FromAddr, status.CoinsFrozen, 1)
if err != nil {
return nil, err
}
......@@ -445,11 +571,11 @@ func (a *action) supervisionNodeGroupQuit(config *pt.ParaNodeAddrConfig) (*types
receipt.Logs = append(receipt.Logs, r.Logs...)
}
copyStat := *status
status.Status = pt.ParacrossSupervisionNodeQuit
copyStat := proto.Clone(status).(*pt.ParaNodeIdStatus)
status.Status = pt.ParacrossSupervisionNodeCancel
status.Height = a.height
r := makeSupervisionNodeGroupIDReceipt(a.fromaddr, &copyStat, status)
r := makeSupervisionNodeConfigReceipt(a.fromaddr, config, copyStat, status)
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
......@@ -461,19 +587,23 @@ func (a *action) SupervisionNodeGroupConfig(config *pt.ParaNodeAddrConfig) (*typ
if !validTitle(cfg, config.Title) {
return nil, pt.ErrInvalidTitle
}
if !types.IsParaExecName(string(a.tx.Execer)) && cfg.IsDappFork(a.exec.GetMainHeight(), pt.ParaX, pt.ForkParaSupervision) {
if !types.IsParaExecName(string(a.tx.Execer)) {
return nil, errors.Wrapf(types.ErrInvalidParam, "exec=%s,should prefix with user.p.", string(a.tx.Execer))
}
if (config.Op == pt.ParacrossSupervisionNodeApprove || config.Op == pt.ParacrossSupervisionNodeQuit) && config.Id == "" {
if (config.Op == pt.ParacrossSupervisionNodeApprove || config.Op == pt.ParacrossSupervisionNodeCancel) && config.Id == "" {
return nil, types.ErrInvalidParam
}
if config.Op == pt.ParacrossSupervisionNodeApply {
return a.supervisionNodeGroupApply(config)
return a.supervisionNodeApply(config)
} else if config.Op == pt.ParacrossSupervisionNodeApprove {
return a.supervisionNodeGroupApprove(config)
return a.supervisionNodeApprove(config)
} else if config.Op == pt.ParacrossSupervisionNodeQuit {
return a.supervisionNodeGroupQuit(config)
// 退出 group
return a.supervisionNodeQuit(config)
} else if config.Op == pt.ParacrossSupervisionNodeCancel {
// 撤销未批准的申请
return a.supervisionNodeCancel(config)
}
return nil, pt.ErrParaUnSupportNodeOper
......
......@@ -20,15 +20,16 @@ func createRawSupervisionNodeConfigTx(config *pt.ParaNodeAddrConfig) *types.Tran
}
func (suite *NodeManageTestSuite) testSupervisionExec() {
suite.testSupervisionNodeConfigQuit()
suite.testSupervisionNodeConfigCancel()
suite.testSupervisionNodeConfigApprove(Account14K, PrivKey14K)
suite.testSupervisionNodeConfigApprove(Account1Ku, PrivKey1Ku)
suite.testSupervisionNodeConfigApprove(Account1M3, PrivKey1M3)
suite.testSupervisionNodeError()
suite.testSupervisionQuery()
suite.testSupervisionNodeQuit()
}
func (suite *NodeManageTestSuite) testSupervisionNodeConfigQuit() {
func (suite *NodeManageTestSuite) testSupervisionNodeConfigCancel() {
// Apply
config := &pt.ParaNodeAddrConfig{
Title: chain33TestCfg.GetTitle(),
......@@ -46,7 +47,7 @@ func (suite *NodeManageTestSuite) testSupervisionNodeConfigQuit() {
// Quit
config = &pt.ParaNodeAddrConfig{
Title: chain33TestCfg.GetTitle(),
Op: pt.ParacrossSupervisionNodeQuit,
Op: pt.ParacrossSupervisionNodeCancel,
Id: g.Current.Id,
}
tx = createRawSupervisionNodeConfigTx(config)
......@@ -100,11 +101,32 @@ func (suite *NodeManageTestSuite) testSupervisionNodeError() {
assert.Equal(suite.T(), err, pt.ErrParaNodeAddrExisted)
}
func (suite *NodeManageTestSuite) testSupervisionNodeQuit() {
config := &pt.ParaNodeAddrConfig{
Title: chain33TestCfg.GetTitle(),
Op: pt.ParacrossSupervisionNodeQuit,
Addr: Account1Ku,
}
tx := createRawSupervisionNodeConfigTx(config)
receipt := nodeCommit(suite, PrivKey14K, tx)
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 3)
assert.Len(suite.T(), receipt.Logs, 3)
assert.Equal(suite.T(), int32(pt.TyLogParaSupervisionNodeGroupAddrsUpdate), receipt.Logs[0].Ty)
ret, err := suite.exec.Query_GetSupervisionNodeGroupAddrs(&pt.ReqParacrossNodeInfo{Title: chain33TestCfg.GetTitle()})
suite.Nil(err)
resp, ok := ret.(*types.ReplyConfig)
assert.Equal(suite.T(), ok, true)
assert.Equal(suite.T(), resp.Value, "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt,1M3XCbWVxAPBH5AR8VmLky4ZtDdGgC6ugD")
}
func checkSupervisionGroupApplyReceipt(suite *NodeManageTestSuite, receipt *types.Receipt) {
assert.Equal(suite.T(), receipt.Ty, int32(types.ExecOk))
assert.Len(suite.T(), receipt.KV, 1)
assert.Len(suite.T(), receipt.Logs, 1)
assert.Equal(suite.T(), int32(pt.TyLogParaSupervisionNodeGroupConfig), receipt.Logs[0].Ty)
assert.Equal(suite.T(), int32(pt.TyLogParaSupervisionNodeConfig), receipt.Logs[0].Ty)
}
func (suite *NodeManageTestSuite) testSupervisionQuery() {
......@@ -114,7 +136,7 @@ func (suite *NodeManageTestSuite) testSupervisionQuery() {
assert.Equal(suite.T(), ok, true)
assert.Equal(suite.T(), resp.Value, "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt,1KufZaLTKVAy37AsXNd9bsva5WZvP8w5uG,1M3XCbWVxAPBH5AR8VmLky4ZtDdGgC6ugD")
ret, err = suite.exec.Query_GetSupervisionNodeAddrInfo(&pt.ReqParacrossNodeInfo{Title: chain33TestCfg.GetTitle(), Addr: Account14K})
ret, err = suite.exec.Query_GetNodeAddrInfo(&pt.ReqParacrossNodeInfo{Title: chain33TestCfg.GetTitle(), Addr: Account14K})
suite.Nil(err)
resp2, ok := ret.(*pt.ParaNodeAddrIdStatus)
assert.Equal(suite.T(), ok, true)
......
......@@ -31,13 +31,15 @@ message ParacrossHeightStatus {
}
message ParacrossHeightStatusRsp {
int32 status = 1;
string title = 2;
int64 height = 3;
int64 mainHeight = 4;
string mainHash = 5;
repeated string commitAddrs = 6;
repeated string commitBlockHash = 7;
int32 status = 1;
string title = 2;
int64 height = 3;
int64 mainHeight = 4;
string mainHash = 5;
repeated string commitAddrs = 6;
repeated string commitBlockHash = 7;
repeated string commitSupervisionAddrs = 8;
repeated string commitSupervisionBlockHash = 9;
}
message ParacrossStatus {
......
......@@ -65,4 +65,6 @@ var (
ErrParaSupervisionNodeGroupNotSet = errors.New("ErrParaSupervisionNodeGroupNotSet")
//ErrParaSupervisionNodeGroupExisted para config group taked over alreay
ErrParaSupervisionNodeGroupExisted = errors.New("ErrParaSupervisionNodesExisted")
//ErrParaSupervisionNodeAddrNotExisted node addr not exist in supervision group
ErrParaSupervisionNodeAddrNotExisted = errors.New("ErrParaSupervisionNodeAddrNotExisted")
)
......@@ -177,6 +177,7 @@ const (
ParacrossSupervisionNodeApply = iota + 1
ParacrossSupervisionNodeApprove
ParacrossSupervisionNodeQuit
ParacrossSupervisionNodeCancel
)
// 0 普通节点共识 1 授权节点正在共识 2 监督节点正在共识
......@@ -334,6 +335,10 @@ func GetDappForkHeight(cfg *types.Chain33Config, forkKey string) int64 {
if forkHeight <= 0 {
forkHeight = types.MaxHeight
}
if key == ForkParaSupervision { // ????
forkHeight = types.Conf(cfg, ParaPrefixConsSubConf).GInt(key)
}
} else {
forkHeight = cfg.GetDappFork(ParaX, forkKey)
......
......@@ -6,13 +6,12 @@ package types
import (
context "context"
fmt "fmt"
math "math"
types "github.com/33cn/chain33/types"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
......@@ -219,16 +218,18 @@ func (m *ParacrossHeightStatus) GetSupervisionDetails() *ParacrossStatusDetails
}
type ParacrossHeightStatusRsp struct {
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
MainHeight int64 `protobuf:"varint,4,opt,name=mainHeight,proto3" json:"mainHeight,omitempty"`
MainHash string `protobuf:"bytes,5,opt,name=mainHash,proto3" json:"mainHash,omitempty"`
CommitAddrs []string `protobuf:"bytes,6,rep,name=commitAddrs,proto3" json:"commitAddrs,omitempty"`
CommitBlockHash []string `protobuf:"bytes,7,rep,name=commitBlockHash,proto3" json:"commitBlockHash,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
MainHeight int64 `protobuf:"varint,4,opt,name=mainHeight,proto3" json:"mainHeight,omitempty"`
MainHash string `protobuf:"bytes,5,opt,name=mainHash,proto3" json:"mainHash,omitempty"`
CommitAddrs []string `protobuf:"bytes,6,rep,name=commitAddrs,proto3" json:"commitAddrs,omitempty"`
CommitBlockHash []string `protobuf:"bytes,7,rep,name=commitBlockHash,proto3" json:"commitBlockHash,omitempty"`
CommitSupervisionAddrs []string `protobuf:"bytes,8,rep,name=commitSupervisionAddrs,proto3" json:"commitSupervisionAddrs,omitempty"`
CommitSupervisionBlockHash []string `protobuf:"bytes,9,rep,name=commitSupervisionBlockHash,proto3" json:"commitSupervisionBlockHash,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ParacrossHeightStatusRsp) Reset() { *m = ParacrossHeightStatusRsp{} }
......@@ -305,6 +306,20 @@ func (m *ParacrossHeightStatusRsp) GetCommitBlockHash() []string {
return nil
}
func (m *ParacrossHeightStatusRsp) GetCommitSupervisionAddrs() []string {
if m != nil {
return m.CommitSupervisionAddrs
}
return nil
}
func (m *ParacrossHeightStatusRsp) GetCommitSupervisionBlockHash() []string {
if m != nil {
return m.CommitSupervisionBlockHash
}
return nil
}
type ParacrossStatus struct {
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
......@@ -4490,199 +4505,198 @@ func init() {
proto.RegisterType((*BlsPubKey)(nil), "types.BlsPubKey")
}
func init() {
proto.RegisterFile("paracross.proto", fileDescriptor_6a397e38c9ea6747)
}
func init() { proto.RegisterFile("paracross.proto", fileDescriptor_6a397e38c9ea6747) }
var fileDescriptor_6a397e38c9ea6747 = []byte{
// 2980 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x3a, 0x4d, 0x6c, 0x24, 0x47,
0xd5, 0xee, 0xf9, 0xf3, 0xcc, 0xb3, 0xc7, 0x5e, 0x77, 0xbc, 0xce, 0xc4, 0x49, 0x56, 0x56, 0x2b,
0x5f, 0xe4, 0x8f, 0x6c, 0xbc, 0x59, 0x27, 0x04, 0x45, 0x08, 0x41, 0xec, 0xdd, 0x64, 0xac, 0xac,
0xc3, 0xa6, 0xec, 0x00, 0x52, 0x04, 0xa2, 0x3d, 0x53, 0xb6, 0x5b, 0x99, 0xe9, 0x9e, 0xed, 0xea,
0xc9, 0xda, 0x08, 0x29, 0x1c, 0x80, 0x1b, 0x12, 0x17, 0x24, 0xb8, 0x70, 0x81, 0x1b, 0x12, 0x27,
0xce, 0x1c, 0x90, 0xb8, 0x44, 0x5c, 0xc2, 0x91, 0x1b, 0x37, 0x10, 0x47, 0x6e, 0x9c, 0xd0, 0x7b,
0x55, 0xd5, 0x5d, 0x55, 0xdd, 0x33, 0x76, 0xb2, 0xb9, 0x70, 0xeb, 0xf7, 0xfa, 0x55, 0xd5, 0xfb,
0xaf, 0xf7, 0x5e, 0x37, 0xac, 0x4e, 0xc2, 0x34, 0x1c, 0xa4, 0x89, 0x10, 0x3b, 0x93, 0x34, 0xc9,
0x12, 0xbf, 0x99, 0x5d, 0x4e, 0xb8, 0xd8, 0x5c, 0xcb, 0xd2, 0x30, 0x16, 0xe1, 0x20, 0x8b, 0x92,
0x58, 0xbe, 0xd9, 0x5c, 0x1e, 0x24, 0xe3, 0x71, 0x0e, 0xdd, 0x38, 0x19, 0x25, 0x83, 0x0f, 0x07,
0xe7, 0x61, 0xa4, 0x30, 0xc1, 0x03, 0xd8, 0x78, 0xa8, 0x37, 0x3b, 0xca, 0xc2, 0x6c, 0x2a, 0xee,
0xf1, 0x2c, 0x8c, 0x46, 0xc2, 0x5f, 0x87, 0x66, 0x38, 0x1c, 0xa6, 0xa2, 0xe7, 0x6d, 0xd5, 0xb7,
0x3b, 0x4c, 0x02, 0xfe, 0x73, 0xd0, 0xa1, 0x3d, 0xfa, 0xa1, 0x38, 0xef, 0xd5, 0xb6, 0xea, 0xdb,
0xcb, 0xac, 0x40, 0x04, 0x1f, 0xc0, 0xb3, 0xce, 0x6e, 0x7b, 0xf8, 0x4e, 0x6f, 0x79, 0x0b, 0x20,
0xa7, 0x95, 0xfb, 0x2e, 0x33, 0x03, 0x83, 0x9b, 0x67, 0x17, 0x8c, 0x8b, 0xe9, 0x28, 0x13, 0x7a,
0xf3, 0x1c, 0x11, 0xfc, 0xb3, 0x06, 0x37, 0xf3, 0xdd, 0xfb, 0x3c, 0x3a, 0x3b, 0xcf, 0xe4, 0x19,
0xfe, 0x06, 0xb4, 0x04, 0x3d, 0xf5, 0xbc, 0x2d, 0x6f, 0xbb, 0xc9, 0x14, 0x84, 0x22, 0x64, 0x51,
0x36, 0xe2, 0xbd, 0xda, 0x96, 0x87, 0x22, 0x10, 0x80, 0xd4, 0xe7, 0xb4, 0xba, 0x57, 0xdf, 0xf2,
0xb6, 0xeb, 0x4c, 0x41, 0xfe, 0x57, 0x60, 0x71, 0x28, 0x19, 0xed, 0x35, 0xb6, 0xbc, 0xed, 0xa5,
0xdd, 0xe7, 0x77, 0x48, 0xad, 0x3b, 0xd5, 0x0a, 0x62, 0x9a, 0x1a, 0xc5, 0x1a, 0x87, 0x51, 0x2c,
0x59, 0xea, 0x35, 0x69, 0x53, 0x03, 0xe3, 0x6f, 0x42, 0x9b, 0x20, 0x54, 0x59, 0x6b, 0xcb, 0xdb,
0x5e, 0x66, 0x39, 0xec, 0xbf, 0x05, 0xcb, 0x27, 0x86, 0x8a, 0x7a, 0x8b, 0x74, 0x72, 0x50, 0x7d,
0xb2, 0xa9, 0x4c, 0x66, 0xad, 0xf3, 0x0f, 0xc1, 0x17, 0xd3, 0x09, 0x4f, 0x3f, 0x8a, 0x44, 0x94,
0xc4, 0x7a, 0xb7, 0xf6, 0x75, 0xe4, 0xa8, 0x58, 0x18, 0xfc, 0xc3, 0x83, 0x5e, 0xa5, 0xae, 0x99,
0x98, 0x7c, 0x41, 0xea, 0xb6, 0xb5, 0xd6, 0x98, 0xab, 0xb5, 0x26, 0x6d, 0x58, 0x68, 0x6d, 0x0b,
0x96, 0xd0, 0xaf, 0xa3, 0xec, 0x4d, 0xf2, 0xd0, 0x16, 0x79, 0xa8, 0x89, 0xf2, 0xb7, 0x61, 0x55,
0x82, 0x7b, 0xb9, 0xb7, 0x2e, 0x12, 0x95, 0x8b, 0x0e, 0x7e, 0xe5, 0xc1, 0xaa, 0xa3, 0x99, 0x42,
0x12, 0xaf, 0x5a, 0x92, 0x9a, 0x25, 0x89, 0x15, 0x13, 0x75, 0x32, 0x70, 0x81, 0xf8, 0xcc, 0x72,
0x1a, 0xde, 0x11, 0xfc, 0xd6, 0x34, 0xc3, 0x7e, 0x12, 0x0b, 0x1e, 0x8b, 0xe9, 0x7c, 0x26, 0x51,
0x35, 0xe7, 0xc5, 0x79, 0x92, 0x53, 0x13, 0xe5, 0xbf, 0x00, 0xdd, 0x81, 0xdc, 0xaa, 0x6f, 0xda,
0xc5, 0x46, 0xfa, 0x5f, 0x82, 0x1b, 0x0a, 0x51, 0x68, 0xb0, 0x41, 0x07, 0x95, 0xf0, 0xc1, 0x1f,
0x3c, 0xf0, 0x91, 0xcd, 0x77, 0x93, 0x21, 0x47, 0xf5, 0xef, 0x27, 0xf1, 0x69, 0x74, 0x36, 0x83,
0xc1, 0x15, 0xa8, 0x25, 0x13, 0xe2, 0xab, 0xcb, 0x6a, 0xc9, 0x04, 0xe1, 0x68, 0x48, 0x3c, 0x74,
0x58, 0x2d, 0x1a, 0xfa, 0x3e, 0x34, 0x30, 0xd5, 0xa8, 0xc3, 0xe8, 0x19, 0x77, 0xfa, 0x28, 0x1c,
0x4d, 0x39, 0x29, 0xa8, 0xcb, 0x24, 0x20, 0xbd, 0x20, 0x8a, 0xc5, 0x5b, 0x69, 0xf2, 0x03, 0x1e,
0x53, 0x68, 0xa1, 0xa8, 0x05, 0x4a, 0x5a, 0x46, 0x3c, 0x9c, 0x9e, 0xbc, 0xc3, 0x2f, 0x29, 0xb4,
0x3a, 0xac, 0x40, 0x04, 0xdf, 0x28, 0xb8, 0xfe, 0x56, 0x92, 0x71, 0xe9, 0xfb, 0x33, 0xf2, 0x1e,
0x72, 0x90, 0x64, 0x5c, 0xa6, 0xa5, 0x0e, 0x93, 0x40, 0xf0, 0x7b, 0x0f, 0xd6, 0x4d, 0xc1, 0x0f,
0x86, 0xca, 0x36, 0x5a, 0x08, 0xcf, 0x10, 0xe2, 0x16, 0xc0, 0x24, 0x4d, 0x26, 0x89, 0x08, 0x47,
0x07, 0x43, 0x15, 0x23, 0x06, 0x06, 0xdd, 0xeb, 0xd1, 0x34, 0xca, 0x0e, 0xb4, 0x32, 0x14, 0x64,
0x84, 0x5b, 0xa3, 0x3a, 0xdc, 0x9a, 0xa6, 0x7a, 0x2d, 0x91, 0x5b, 0xae, 0xc8, 0xbf, 0xa8, 0xc1,
0x0d, 0xcd, 0x70, 0xce, 0xac, 0xb4, 0x80, 0x97, 0x5b, 0xa0, 0x38, 0xb0, 0x56, 0x7d, 0x60, 0xdd,
0x3c, 0xf0, 0x16, 0x40, 0x16, 0xa6, 0x67, 0x9c, 0x02, 0x4f, 0x59, 0xcd, 0xc0, 0xb8, 0x56, 0x6a,
0x96, 0xad, 0x74, 0x47, 0xeb, 0xb6, 0x45, 0xe9, 0xea, 0x19, 0x23, 0x5d, 0xd9, 0xb6, 0x51, 0x6a,
0xc7, 0x90, 0x39, 0x4d, 0x93, 0x31, 0x1d, 0x28, 0xad, 0x9a, 0xc3, 0x46, 0x90, 0xb6, 0xcb, 0x41,
0xaa, 0xf5, 0xd2, 0x71, 0xf5, 0xf2, 0x47, 0x0f, 0x6e, 0x32, 0x3e, 0xe0, 0xd1, 0x24, 0xd3, 0xc7,
0x2a, 0x27, 0xae, 0xb2, 0xe4, 0x5d, 0x68, 0x0d, 0xe8, 0x2d, 0x29, 0xa8, 0xcc, 0x71, 0x11, 0x03,
0x4c, 0x11, 0xfa, 0x2f, 0x41, 0x63, 0x92, 0xf2, 0x8f, 0x48, 0x75, 0x4b, 0xbb, 0x4f, 0x3b, 0x0b,
0xb4, 0x29, 0x18, 0x11, 0xf9, 0x77, 0x61, 0x71, 0x30, 0x4d, 0x53, 0x1e, 0x67, 0xea, 0x26, 0x9a,
0x49, 0xaf, 0xe9, 0x82, 0xdf, 0x78, 0xf0, 0xbc, 0x23, 0x00, 0x72, 0x81, 0x64, 0xef, 0x4f, 0x86,
0x61, 0xc6, 0x2d, 0xa5, 0x79, 0x8e, 0xd2, 0xee, 0x28, 0xee, 0xa4, 0x38, 0xcf, 0x56, 0x88, 0xe3,
0x70, 0xf8, 0xe5, 0x82, 0xc3, 0xfa, 0xd5, 0x6b, 0x72, 0x2e, 0xff, 0xed, 0xc1, 0xd3, 0x0e, 0x97,
0x64, 0xdd, 0x24, 0xe6, 0x25, 0x2f, 0xac, 0xbe, 0x4d, 0x6c, 0x6f, 0xab, 0x97, 0xbc, 0x0d, 0xdf,
0x27, 0x59, 0x38, 0xc2, 0xad, 0x75, 0xc0, 0x18, 0x18, 0x2a, 0x31, 0x10, 0xc2, 0x63, 0xc9, 0x17,
0x9b, 0xac, 0x40, 0x50, 0x2e, 0x4e, 0x44, 0x46, 0x2f, 0x5b, 0xf4, 0x32, 0x87, 0xfd, 0x1e, 0x2c,
0xa2, 0xf7, 0x31, 0x91, 0x29, 0x9f, 0xd3, 0x20, 0x9e, 0x39, 0x4c, 0x62, 0x2e, 0x85, 0x25, 0xb7,
0x6b, 0x32, 0x03, 0x83, 0xb6, 0x79, 0x4a, 0x8b, 0xfb, 0x76, 0x9a, 0x4c, 0x27, 0x4f, 0x94, 0x1f,
0xf3, 0xfc, 0x24, 0x43, 0x4d, 0xe5, 0xa7, 0xab, 0xa3, 0x8c, 0x8a, 0x2f, 0xe5, 0xef, 0x42, 0x65,
0x06, 0x03, 0x13, 0xfc, 0xcb, 0xe5, 0xf2, 0x0b, 0xc9, 0x0e, 0x5b, 0xb0, 0x54, 0x58, 0x47, 0xf3,
0x6c, 0xa2, 0xae, 0xc1, 0xb9, 0xe9, 0xb9, 0xad, 0x99, 0xe1, 0xbe, 0xe8, 0x56, 0x17, 0x86, 0xb4,
0xed, 0x92, 0xb4, 0x9f, 0x78, 0xb0, 0xe9, 0x78, 0xa2, 0x69, 0x9a, 0xaa, 0xa8, 0xdf, 0x75, 0xa2,
0x7e, 0xd3, 0x71, 0x79, 0x63, 0x7d, 0x1e, 0xf6, 0x3b, 0x56, 0xd8, 0x57, 0xae, 0xb0, 0xe2, 0xea,
0x35, 0x37, 0xf2, 0xe7, 0x2d, 0xc9, 0xc3, 0xea, 0xa7, 0x1e, 0xac, 0x33, 0xfe, 0x28, 0xaf, 0x14,
0x28, 0x45, 0xc4, 0xa7, 0xc9, 0x6c, 0x0f, 0x8b, 0xf4, 0x05, 0x64, 0xde, 0xb8, 0x75, 0x43, 0xd8,
0x59, 0x97, 0x8e, 0x95, 0x46, 0x9b, 0x6e, 0x1a, 0xdd, 0x87, 0x0d, 0xc6, 0xc5, 0xc4, 0x62, 0x44,
0x5a, 0xf9, 0xff, 0xa1, 0x1e, 0x0d, 0xe5, 0x9d, 0x3a, 0x27, 0x9d, 0x21, 0x4d, 0xf0, 0x36, 0xe6,
0x08, 0x67, 0x13, 0x12, 0x5b, 0xf8, 0xb7, 0xcd, 0x5d, 0xe6, 0xa9, 0x86, 0x36, 0x9a, 0xc8, 0xbb,
0x6e, 0x2f, 0x8a, 0x87, 0x87, 0x51, 0xcc, 0xd3, 0xfd, 0xf1, 0x90, 0xfc, 0x22, 0x8a, 0x87, 0x6f,
0x52, 0x8f, 0xa4, 0xea, 0x57, 0x03, 0x43, 0xf2, 0x45, 0xf1, 0x70, 0x1f, 0xdd, 0x4f, 0x15, 0x4f,
0x05, 0xa2, 0xc8, 0x3e, 0x78, 0x9e, 0x9d, 0x7d, 0x10, 0x13, 0xfc, 0xd9, 0x83, 0x35, 0xeb, 0x48,
0xb2, 0xc2, 0x8c, 0x62, 0x00, 0xb7, 0x3d, 0x32, 0x23, 0xc9, 0xc0, 0xd8, 0x7c, 0xd4, 0xe7, 0xf3,
0xd1, 0x70, 0xf9, 0xc8, 0x2b, 0xd2, 0xe3, 0x68, 0xcc, 0x55, 0x44, 0x15, 0x08, 0x8c, 0x38, 0x59,
0x9e, 0xca, 0xc0, 0x51, 0x75, 0x93, 0x81, 0x0a, 0x7e, 0xee, 0x41, 0xcf, 0x88, 0x8e, 0xab, 0xc5,
0xb9, 0x6d, 0x5d, 0x20, 0x3d, 0xc3, 0x32, 0xd6, 0x5a, 0xe5, 0xe5, 0xbb, 0xee, 0xed, 0x31, 0x7b,
0x41, 0xee, 0xe3, 0xf7, 0x65, 0x95, 0x8e, 0xe2, 0x21, 0xc5, 0x37, 0x63, 0x92, 0x92, 0x5a, 0x17,
0x52, 0x82, 0xe4, 0xa6, 0x40, 0xa0, 0xef, 0x8f, 0x71, 0x1b, 0x7d, 0x7f, 0x10, 0x10, 0x7c, 0xa7,
0xa8, 0x7f, 0x70, 0x9b, 0x07, 0x91, 0xc8, 0x66, 0x44, 0xc9, 0x0e, 0xb4, 0x68, 0x89, 0x2c, 0xf9,
0x96, 0x76, 0x37, 0x1c, 0x77, 0x53, 0x5c, 0x30, 0x45, 0x15, 0x7c, 0x5c, 0xba, 0x80, 0xf5, 0x01,
0xea, 0x02, 0xd6, 0x25, 0x80, 0x57, 0x79, 0xa5, 0x6b, 0xe2, 0x72, 0x09, 0x50, 0x9b, 0x4f, 0x9f,
0x6b, 0xe8, 0x31, 0x26, 0x01, 0x19, 0x37, 0x96, 0x78, 0x2f, 0x41, 0x63, 0x14, 0x89, 0xec, 0xca,
0x73, 0x91, 0x08, 0x4d, 0xa3, 0x9b, 0x60, 0x29, 0xf6, 0x1c, 0xd3, 0x28, 0xc2, 0xe0, 0x27, 0xda,
0xeb, 0xd1, 0x83, 0x76, 0x0f, 0xc3, 0x28, 0x3e, 0x0c, 0x27, 0x46, 0x66, 0xf6, 0x66, 0x77, 0x4b,
0x35, 0x9d, 0x41, 0xaa, 0xbb, 0xa5, 0xfa, 0xdc, 0x6e, 0xa9, 0x61, 0x77, 0x85, 0xc1, 0x3d, 0x59,
0xcf, 0x17, 0x6c, 0x90, 0xbb, 0xee, 0x40, 0x33, 0xca, 0xf8, 0x58, 0x67, 0x0d, 0x4b, 0x1e, 0x93,
0x61, 0x26, 0xc9, 0x82, 0xbf, 0xd7, 0xe5, 0x3d, 0x98, 0xe7, 0x1e, 0x15, 0x91, 0x2f, 0x40, 0x17,
0x4f, 0x2a, 0xba, 0x21, 0x8f, 0x9a, 0x35, 0x1b, 0x89, 0x7d, 0x67, 0x81, 0x30, 0x5b, 0x30, 0x17,
0x3d, 0xe3, 0xbe, 0x2c, 0xb4, 0xd6, 0xb0, 0xb4, 0x16, 0xc0, 0xf2, 0x24, 0xe5, 0xc5, 0xe1, 0xb2,
0x53, 0xb4, 0x70, 0xb6, 0x66, 0x5b, 0x6e, 0x1f, 0x2a, 0x77, 0x40, 0x61, 0xb8, 0x6a, 0x87, 0xf5,
0x0e, 0x39, 0x8e, 0x22, 0x2a, 0x27, 0x68, 0xcb, 0x1d, 0x72, 0x04, 0xea, 0x3e, 0xbb, 0xd8, 0x4f,
0xa6, 0x71, 0x26, 0xa8, 0x82, 0xee, 0xb2, 0x1c, 0x96, 0xef, 0xe4, 0xa4, 0xa6, 0x07, 0xb2, 0x8b,
0xd5, 0x30, 0x56, 0x4e, 0xd9, 0x85, 0x9c, 0xf9, 0x2c, 0xd1, 0x50, 0x47, 0x83, 0xd4, 0x8a, 0xa2,
0x9a, 0x8f, 0xf5, 0xd2, 0x65, 0xa9, 0x53, 0x0b, 0x89, 0x9c, 0x2b, 0x84, 0xdc, 0xa4, 0x4b, 0x9b,
0x58, 0x38, 0xff, 0x36, 0xac, 0xc5, 0x49, 0xbc, 0x4f, 0xbd, 0xfd, 0xb1, 0x66, 0x72, 0x85, 0x98,
0x2c, 0xbf, 0x08, 0xf6, 0x60, 0xed, 0x88, 0x8f, 0x4e, 0x55, 0x47, 0x7d, 0x94, 0x85, 0x67, 0x5c,
0xf8, 0x2f, 0xdb, 0x8e, 0xa2, 0x03, 0xc5, 0x25, 0xd4, 0x7e, 0xf2, 0x00, 0x6e, 0xb8, 0xaf, 0x30,
0xb3, 0x8a, 0x2c, 0x4c, 0xb3, 0xbe, 0xe9, 0xf8, 0x26, 0x0a, 0xed, 0xcb, 0xe3, 0xf0, 0x44, 0x95,
0xb5, 0x5d, 0xa6, 0xa0, 0xe0, 0x6f, 0x1e, 0xac, 0xbb, 0xdb, 0x91, 0xfb, 0xce, 0x2f, 0xbf, 0xba,
0xf9, 0xc5, 0xfc, 0x32, 0x34, 0x05, 0x2e, 0x72, 0x3a, 0x8c, 0x32, 0xf7, 0x44, 0x65, 0xd5, 0x54,
0x0d, 0xa7, 0xa6, 0xba, 0x05, 0xc0, 0x2f, 0xf8, 0xc0, 0x9e, 0x67, 0x15, 0x98, 0xcf, 0xdc, 0xaf,
0x05, 0x1c, 0x36, 0x1e, 0x24, 0x83, 0x70, 0xa4, 0x99, 0x29, 0xa4, 0xbb, 0xab, 0xb9, 0xf6, 0xac,
0x2e, 0xa2, 0x4a, 0x13, 0x9a, 0x73, 0xf2, 0xa6, 0x83, 0x78, 0xc8, 0x2f, 0x54, 0xf6, 0xd0, 0x60,
0xf0, 0x3a, 0xac, 0xc8, 0xf2, 0x0b, 0x39, 0xa8, 0x54, 0x5e, 0x3e, 0x47, 0xa8, 0x19, 0x73, 0x84,
0x20, 0x80, 0x1b, 0x72, 0xdd, 0x7e, 0x18, 0x0f, 0xf8, 0xa8, 0x6a, 0x65, 0xf0, 0xa9, 0x9a, 0x12,
0x11, 0x3b, 0x57, 0xd5, 0xef, 0xd9, 0xa5, 0xae, 0xdf, 0xb3, 0x4b, 0xd4, 0x96, 0x14, 0x11, 0xe6,
0x1a, 0xa6, 0xbf, 0xa0, 0x05, 0x7c, 0x09, 0x1a, 0xa8, 0xb6, 0xde, 0x12, 0xd1, 0xdf, 0x54, 0xf4,
0xb6, 0x64, 0xfd, 0x05, 0x46, 0x44, 0xd4, 0x8a, 0x12, 0xd7, 0x14, 0x3a, 0xc5, 0xf6, 0xae, 0x40,
0xfd, 0x05, 0xa6, 0x08, 0xf7, 0x16, 0x95, 0x12, 0x82, 0x1f, 0x17, 0x35, 0xb0, 0x65, 0x19, 0x25,
0xde, 0x1d, 0xeb, 0xbe, 0x9a, 0x6b, 0x9a, 0x52, 0x53, 0x58, 0xbb, 0x7a, 0x4d, 0x7e, 0x6f, 0x7d,
0xea, 0xc1, 0x73, 0x55, 0x6c, 0xcc, 0xec, 0x0c, 0x73, 0x57, 0xaf, 0x5d, 0xcb, 0xd5, 0xed, 0x96,
0xb0, 0x3e, 0xbf, 0x25, 0x6c, 0xcc, 0x6b, 0x09, 0x9b, 0xb3, 0x5b, 0xc2, 0x96, 0xd5, 0x12, 0x06,
0x1f, 0xc3, 0xb3, 0x55, 0x22, 0x09, 0x55, 0x0a, 0xdc, 0xb6, 0x54, 0xdb, 0x9b, 0x21, 0x80, 0x28,
0x97, 0x4b, 0xb5, 0x2b, 0x16, 0xe4, 0x4a, 0xfd, 0xb5, 0x07, 0x3e, 0xe3, 0x8f, 0xde, 0x9b, 0xf2,
0xf4, 0x12, 0xc9, 0x54, 0x8e, 0xb3, 0x47, 0xb7, 0x45, 0xf6, 0x70, 0x5b, 0x82, 0x75, 0x68, 0x0e,
0x30, 0x55, 0x2a, 0x75, 0x49, 0x00, 0x35, 0x35, 0x8c, 0x52, 0x2e, 0x6b, 0x67, 0xa5, 0xa9, 0x1c,
0x61, 0x5c, 0x5d, 0x4d, 0xeb, 0xea, 0x5a, 0x87, 0x66, 0x44, 0xe1, 0x2a, 0x3b, 0x6a, 0x09, 0x04,
0xef, 0x61, 0xb5, 0x32, 0x19, 0x5d, 0xba, 0x1c, 0xbe, 0x41, 0x57, 0x90, 0xf4, 0x11, 0x95, 0x89,
0xe7, 0xba, 0x51, 0x41, 0x1d, 0x7c, 0xcf, 0xf8, 0x96, 0xb1, 0xaf, 0xa6, 0xbc, 0x42, 0x97, 0xac,
0x22, 0x3a, 0x8b, 0xd5, 0x95, 0x4d, 0xcf, 0x68, 0x58, 0x6a, 0x9d, 0x0f, 0x43, 0xd9, 0x6d, 0x2f,
0xb3, 0x1c, 0x2e, 0x7a, 0xec, 0xba, 0x31, 0x03, 0x0c, 0x7e, 0x68, 0x7c, 0x7f, 0x90, 0xfb, 0xab,
0xa6, 0x61, 0xd7, 0xd2, 0xaa, 0xdd, 0x99, 0x38, 0x65, 0x44, 0xae, 0xf1, 0x3b, 0x50, 0x3f, 0x19,
0x09, 0x65, 0xd0, 0xd2, 0x84, 0xde, 0x62, 0x9f, 0x21, 0x65, 0x90, 0xc9, 0x51, 0x23, 0xbd, 0xa6,
0x22, 0xec, 0x09, 0x0e, 0xdf, 0x86, 0xd5, 0x48, 0x18, 0xea, 0x54, 0xb7, 0x49, 0x9b, 0xb9, 0xe8,
0xe0, 0x97, 0x1e, 0xf8, 0xfb, 0xb8, 0xcb, 0x9b, 0x42, 0xf0, 0xec, 0x38, 0x0d, 0x63, 0x71, 0xca,
0x53, 0xf4, 0x84, 0x10, 0x11, 0xf7, 0x2f, 0xf8, 0x40, 0x97, 0xde, 0x39, 0x02, 0xaf, 0x41, 0x02,
0x8e, 0x2e, 0xc7, 0x27, 0xc9, 0x48, 0xb9, 0x95, 0x89, 0x42, 0x5f, 0x09, 0xc7, 0xb9, 0x83, 0xd5,
0x99, 0x82, 0x10, 0x9f, 0x25, 0xc6, 0xa5, 0xa4, 0x20, 0x34, 0x60, 0xac, 0x23, 0xb0, 0xc3, 0xe8,
0x39, 0xf8, 0x4f, 0xcb, 0x18, 0xdc, 0x2b, 0x65, 0xbc, 0x8e, 0x3d, 0x3a, 0xaa, 0x4e, 0x29, 0xe3,
0xb9, 0x6a, 0xc5, 0x4a, 0x6a, 0xca, 0x89, 0x04, 0xfb, 0xaf, 0xea, 0x66, 0xa1, 0x3c, 0xcd, 0x72,
0x15, 0x8e, 0x89, 0x9a, 0x68, 0xfd, 0xaf, 0x41, 0x37, 0x34, 0xb5, 0xa2, 0x5a, 0x76, 0x9d, 0xb1,
0x49, 0x63, 0x42, 0xbf, 0xec, 0x2f, 0x30, 0x9b, 0x3a, 0x5f, 0xfe, 0xed, 0x28, 0x3b, 0x1f, 0xa6,
0xe1, 0x63, 0x12, 0xce, 0x5d, 0xae, 0x5f, 0xe6, 0xcb, 0x35, 0xc2, 0x7f, 0x15, 0xda, 0x99, 0x3e,
0xb8, 0x35, 0xff, 0xe0, 0x9c, 0x10, 0x17, 0x3d, 0xd6, 0xc7, 0x2d, 0xce, 0x3f, 0x2e, 0x27, 0xf4,
0xef, 0xc3, 0x8a, 0xde, 0xe0, 0x38, 0x21, 0x8b, 0xb7, 0x2d, 0x2d, 0xd9, 0xe7, 0x49, 0x92, 0xfe,
0x02, 0x73, 0x16, 0xf9, 0x5f, 0x05, 0x88, 0xf3, 0xb9, 0x2a, 0x15, 0x90, 0xf3, 0x26, 0xa7, 0xfd,
0x05, 0x66, 0x90, 0xfb, 0x6f, 0xc1, 0x6a, 0x6c, 0xcf, 0x58, 0xd4, 0x7d, 0x3a, 0x67, 0x0a, 0xd3,
0x5f, 0x60, 0xee, 0x22, 0x7f, 0x0f, 0x56, 0x85, 0x4e, 0x36, 0x6a, 0x1f, 0x79, 0xcf, 0x9a, 0xed,
0x9d, 0xf1, 0x16, 0xf7, 0x70, 0x16, 0xf8, 0xef, 0x80, 0x3f, 0x28, 0x85, 0x84, 0xba, 0x7f, 0xb5,
0x40, 0xe5, 0x98, 0xe9, 0x2f, 0xb0, 0x8a, 0x65, 0xfe, 0xd7, 0xa1, 0x3b, 0x31, 0x5b, 0xab, 0x5e,
0xb7, 0xd4, 0xa6, 0x99, 0x03, 0x0c, 0xf4, 0x03, 0x8b, 0xde, 0xff, 0x00, 0x36, 0x8d, 0x0f, 0x78,
0x8e, 0x0a, 0xa8, 0x04, 0xbe, 0x42, 0xcd, 0x73, 0x96, 0x1b, 0xc5, 0x4c, 0x13, 0x8b, 0x99, 0xa2,
0x76, 0xf8, 0xc4, 0x83, 0x0d, 0xa3, 0xdd, 0x35, 0x62, 0x6b, 0xd6, 0xec, 0xcc, 0xa8, 0x5a, 0xaf,
0x97, 0xa4, 0x5e, 0xb1, 0x66, 0x67, 0xa5, 0x48, 0xb6, 0xbe, 0x4a, 0xca, 0x8b, 0xf2, 0x75, 0x77,
0x7a, 0x36, 0x7f, 0x51, 0x7e, 0x59, 0xbe, 0x63, 0x0d, 0xff, 0x8b, 0x80, 0xff, 0x3c, 0xb9, 0x35,
0xf8, 0x51, 0x03, 0x6f, 0x36, 0x7b, 0x37, 0x2a, 0x63, 0xec, 0x3a, 0xc4, 0x2b, 0xd5, 0x21, 0x5b,
0xb0, 0x44, 0x90, 0x54, 0xa3, 0x52, 0xba, 0x89, 0xf2, 0x5f, 0x84, 0x15, 0xac, 0x3d, 0x8e, 0xc2,
0x31, 0x57, 0x44, 0xf2, 0x7a, 0x76, 0xb0, 0x45, 0x61, 0xda, 0xa8, 0x6e, 0x2d, 0x9b, 0x6e, 0x43,
0x5e, 0x34, 0x7d, 0xad, 0x79, 0x4d, 0xdf, 0xe2, 0x9c, 0xa6, 0xaf, 0xed, 0x34, 0x7d, 0x56, 0x33,
0xda, 0x71, 0x9b, 0x51, 0xa3, 0x25, 0x84, 0x2b, 0x5a, 0xc2, 0xa5, 0xeb, 0xb4, 0x84, 0xcb, 0x15,
0x2d, 0x61, 0xa9, 0x61, 0xef, 0x5e, 0xb3, 0x61, 0x5f, 0xa9, 0x6e, 0xd8, 0xb7, 0x61, 0x95, 0x3e,
0xa3, 0xde, 0x2f, 0x7a, 0xa3, 0x55, 0x49, 0xe9, 0xa0, 0x83, 0xef, 0x97, 0x63, 0x83, 0xf1, 0x41,
0x92, 0x0e, 0xbf, 0xa8, 0xd8, 0x08, 0xfe, 0x0f, 0x96, 0xf2, 0xd7, 0xc7, 0x17, 0x74, 0x6d, 0x5e,
0xe4, 0x43, 0x09, 0xbc, 0x36, 0x09, 0x92, 0xa3, 0xd4, 0x62, 0x2e, 0x7c, 0x8c, 0x7e, 0xe0, 0x8e,
0x1f, 0xae, 0xf3, 0x89, 0x3b, 0xf8, 0x5d, 0x0d, 0xd6, 0xac, 0xa1, 0xec, 0xff, 0x96, 0x47, 0x77,
0x3e, 0xaf, 0x47, 0x77, 0x0c, 0x8f, 0xae, 0xb0, 0x7f, 0xa7, 0xda, 0xfe, 0x6f, 0xc3, 0x53, 0x96,
0xb2, 0x48, 0xef, 0x98, 0xd0, 0x5a, 0xc4, 0xb7, 0x3b, 0x8a, 0x2a, 0x29, 0x96, 0x29, 0x3a, 0x99,
0x98, 0x5c, 0xfb, 0xa1, 0x0c, 0xd5, 0xd6, 0x2b, 0x8d, 0xd6, 0xac, 0x9f, 0x73, 0xfe, 0x52, 0x83,
0x95, 0xa2, 0x5e, 0xc2, 0x4b, 0x08, 0xdd, 0x11, 0xbb, 0x7e, 0xed, 0x8e, 0xf8, 0x4c, 0x29, 0x3f,
0xd1, 0xad, 0x40, 0x96, 0xa0, 0x91, 0xa3, 0xbc, 0x2e, 0x20, 0xf3, 0xb4, 0x99, 0x81, 0x31, 0x7c,
0xaf, 0x61, 0xfa, 0x9e, 0x51, 0xe2, 0x35, 0xad, 0x12, 0xcf, 0x87, 0x06, 0xc7, 0x1a, 0x42, 0xda,
0x85, 0x9e, 0xa9, 0x2d, 0x91, 0xb5, 0xa2, 0xfc, 0xb4, 0xa6, 0x20, 0x14, 0x48, 0x0a, 0x7e, 0x39,
0xe1, 0x64, 0x8f, 0x2e, 0x2b, 0x10, 0x86, 0xf9, 0xc1, 0x32, 0x3f, 0xfd, 0xba, 0x80, 0x6e, 0x83,
0xba, 0x54, 0x96, 0xba, 0x49, 0x14, 0x25, 0x3c, 0x7d, 0x94, 0x0f, 0xd3, 0x50, 0x51, 0x6d, 0xc8,
0x59, 0x47, 0x81, 0xc1, 0x44, 0x25, 0xa6, 0x83, 0x01, 0x17, 0xa2, 0xf7, 0x34, 0x89, 0xae, 0xc1,
0xe0, 0xaf, 0x9e, 0x1c, 0x25, 0xd3, 0x64, 0xe3, 0xde, 0x09, 0x65, 0x8a, 0x99, 0x43, 0x4f, 0x73,
0x6c, 0x59, 0x73, 0x7e, 0x01, 0xba, 0x6a, 0xe4, 0xf9, 0x22, 0xac, 0x4c, 0x42, 0xbc, 0xa7, 0x0e,
0xcd, 0xc1, 0xe7, 0x32, 0x73, 0xb0, 0x57, 0x0c, 0xfd, 0x5f, 0x80, 0x7a, 0x76, 0x21, 0x7f, 0x95,
0x59, 0xda, 0xf5, 0x95, 0xe7, 0x1d, 0x17, 0xff, 0x8b, 0x31, 0x7c, 0x1d, 0xfc, 0x49, 0xfd, 0xd0,
0x60, 0x0a, 0x45, 0x1d, 0xd4, 0x75, 0x05, 0xeb, 0x3c, 0xb1, 0x60, 0x9d, 0xcf, 0x28, 0xd8, 0x8d,
0x42, 0xb0, 0x8e, 0x14, 0x22, 0x91, 0x7d, 0xda, 0xde, 0x48, 0x1c, 0x45, 0x67, 0xf1, 0xd1, 0x74,
0xac, 0x7f, 0x92, 0x9a, 0x25, 0x44, 0xde, 0xee, 0xd5, 0xcc, 0x5f, 0x3e, 0x7c, 0x68, 0x8c, 0xc5,
0x99, 0xec, 0x01, 0x97, 0x19, 0x3d, 0x23, 0x25, 0x36, 0x8f, 0xa2, 0xd7, 0x20, 0xa4, 0x04, 0x82,
0xef, 0xc2, 0x33, 0x95, 0x07, 0x1e, 0x9d, 0x27, 0x8f, 0x9f, 0xe0, 0xd0, 0x8e, 0x3c, 0x34, 0x38,
0xd1, 0x73, 0x6d, 0xbd, 0x3d, 0x59, 0xe4, 0x35, 0x68, 0x44, 0x45, 0x8f, 0xbc, 0x65, 0x8d, 0xb5,
0x2b, 0xf8, 0x60, 0x44, 0x2d, 0x1b, 0xac, 0x49, 0x34, 0xd0, 0xc7, 0x2a, 0x28, 0x60, 0xb0, 0xf2,
0x80, 0x87, 0x43, 0x9e, 0x1e, 0x5d, 0xc6, 0x03, 0x3d, 0x01, 0x3b, 0xb8, 0xa7, 0xa7, 0x2e, 0x07,
0xf7, 0x30, 0x12, 0x4e, 0x42, 0xc1, 0x0f, 0x86, 0x17, 0x2a, 0x91, 0x6b, 0x10, 0xf7, 0x4c, 0x4e,
0x4f, 0x05, 0xd7, 0xc9, 0x5b, 0x41, 0xc1, 0xcf, 0x3c, 0xe8, 0x22, 0x3f, 0x0f, 0x77, 0x1f, 0x1e,
0x4d, 0x4f, 0x0e, 0x85, 0x2e, 0x27, 0x3d, 0x5d, 0x4e, 0xfa, 0xaf, 0x40, 0x7b, 0xa0, 0x26, 0xb3,
0xaa, 0x9c, 0xaf, 0xf0, 0x4c, 0xec, 0x45, 0x34, 0x95, 0x7f, 0x17, 0x16, 0xc5, 0x65, 0x3c, 0x38,
0x14, 0x67, 0xce, 0x7c, 0xcc, 0xe6, 0xbe, 0xbf, 0xc0, 0x34, 0x5d, 0x51, 0xb3, 0x7e, 0x00, 0x2b,
0xf7, 0x47, 0x72, 0x58, 0xa1, 0x66, 0xfa, 0x9b, 0xd0, 0x8e, 0x84, 0x5c, 0x49, 0x5c, 0xb5, 0x59,
0x0e, 0xfb, 0x2f, 0x43, 0x6b, 0x24, 0xdf, 0xd4, 0xe6, 0x1c, 0xc4, 0x14, 0x51, 0xf0, 0x3c, 0x74,
0xf6, 0xf4, 0x77, 0x50, 0xf4, 0xc9, 0x0f, 0xf9, 0xa5, 0x52, 0x1e, 0x3e, 0xee, 0xbe, 0x01, 0x9d,
0xfc, 0xa7, 0x4d, 0xff, 0x36, 0xb4, 0x0e, 0x04, 0xee, 0xe0, 0x77, 0xf3, 0x2b, 0xe0, 0xd1, 0xbb,
0xd1, 0x68, 0x73, 0x4d, 0x81, 0x07, 0x62, 0x3f, 0x9c, 0x9e, 0x9d, 0x67, 0xef, 0x4f, 0x82, 0x85,
0x93, 0x16, 0xfd, 0xa9, 0xf9, 0xea, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x2a, 0x67, 0xa5,
0xf6, 0x29, 0x00, 0x00,
// 3008 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x1a, 0x4b, 0x6c, 0x24, 0x47,
0xd5, 0x3d, 0x3f, 0xcf, 0x3c, 0x7b, 0xec, 0xdd, 0xce, 0xae, 0x33, 0x71, 0x92, 0x95, 0xd5, 0x0a,
0x91, 0x21, 0x9b, 0xdd, 0xac, 0x13, 0x16, 0x45, 0x88, 0x4f, 0xec, 0xdd, 0xc4, 0x56, 0xd6, 0x61,
0x53, 0x76, 0x00, 0x29, 0x02, 0xd1, 0x9e, 0x29, 0xdb, 0xad, 0xcc, 0x74, 0xcf, 0x76, 0xf5, 0x64,
0x6d, 0x84, 0x14, 0x0e, 0xc0, 0x0d, 0x89, 0x0b, 0x12, 0x5c, 0xb8, 0xc0, 0x0d, 0x89, 0x13, 0x67,
0x0e, 0x48, 0x5c, 0x22, 0x2e, 0xe1, 0xc8, 0x09, 0x8e, 0x88, 0x23, 0x37, 0x4e, 0xe8, 0xbd, 0xaa,
0xea, 0xae, 0xaa, 0xee, 0x69, 0x3b, 0xd9, 0x5c, 0xb8, 0xcd, 0x7b, 0xf5, 0xaa, 0xea, 0xfd, 0xeb,
0xbd, 0x37, 0x0d, 0xab, 0xd3, 0x30, 0x0d, 0x87, 0x69, 0x22, 0xc4, 0xad, 0x69, 0x9a, 0x64, 0x89,
0xdf, 0xce, 0xce, 0xa7, 0x5c, 0xac, 0x5f, 0xcd, 0xd2, 0x30, 0x16, 0xe1, 0x30, 0x8b, 0x92, 0x58,
0xae, 0xac, 0x2f, 0x0f, 0x93, 0xc9, 0x24, 0x87, 0xae, 0x1c, 0x8d, 0x93, 0xe1, 0x07, 0xc3, 0xd3,
0x30, 0x52, 0x98, 0xe0, 0x01, 0xac, 0x3d, 0xd4, 0x87, 0x1d, 0x64, 0x61, 0x36, 0x13, 0xf7, 0x78,
0x16, 0x46, 0x63, 0xe1, 0x5f, 0x83, 0x76, 0x38, 0x1a, 0xa5, 0x62, 0xe0, 0x6d, 0x34, 0x37, 0x7b,
0x4c, 0x02, 0xfe, 0x73, 0xd0, 0xa3, 0x33, 0x76, 0x43, 0x71, 0x3a, 0x68, 0x6c, 0x34, 0x37, 0x97,
0x59, 0x81, 0x08, 0xde, 0x87, 0x67, 0x9d, 0xd3, 0xb6, 0x71, 0x4d, 0x1f, 0x79, 0x03, 0x20, 0xa7,
0x95, 0xe7, 0x2e, 0x33, 0x03, 0x83, 0x87, 0x67, 0x67, 0x8c, 0x8b, 0xd9, 0x38, 0x13, 0xfa, 0xf0,
0x1c, 0x11, 0xfc, 0xab, 0x01, 0xd7, 0xf3, 0xd3, 0x77, 0x79, 0x74, 0x72, 0x9a, 0xc9, 0x3b, 0xfc,
0x35, 0xe8, 0x08, 0xfa, 0x35, 0xf0, 0x36, 0xbc, 0xcd, 0x36, 0x53, 0x10, 0x8a, 0x90, 0x45, 0xd9,
0x98, 0x0f, 0x1a, 0x1b, 0x1e, 0x8a, 0x40, 0x00, 0x52, 0x9f, 0xd2, 0xee, 0x41, 0x73, 0xc3, 0xdb,
0x6c, 0x32, 0x05, 0xf9, 0x5f, 0x81, 0xc5, 0x91, 0x64, 0x74, 0xd0, 0xda, 0xf0, 0x36, 0x97, 0xb6,
0x9e, 0xbf, 0x45, 0x6a, 0xbd, 0x55, 0xad, 0x20, 0xa6, 0xa9, 0x51, 0xac, 0x49, 0x18, 0xc5, 0x92,
0xa5, 0x41, 0x9b, 0x0e, 0x35, 0x30, 0xfe, 0x3a, 0x74, 0x09, 0x42, 0x95, 0x75, 0x36, 0xbc, 0xcd,
0x65, 0x96, 0xc3, 0xfe, 0x9b, 0xb0, 0x7c, 0x64, 0xa8, 0x68, 0xb0, 0x48, 0x37, 0x07, 0xd5, 0x37,
0x9b, 0xca, 0x64, 0xd6, 0x3e, 0x7f, 0x1f, 0x7c, 0x31, 0x9b, 0xf2, 0xf4, 0xc3, 0x48, 0x44, 0x49,
0xac, 0x4f, 0xeb, 0x5e, 0x46, 0x8e, 0x8a, 0x8d, 0xc1, 0x3f, 0x1a, 0x30, 0xa8, 0xd4, 0x35, 0x13,
0xd3, 0xcf, 0x49, 0xdd, 0xb6, 0xd6, 0x5a, 0xb5, 0x5a, 0x6b, 0xd3, 0x81, 0x85, 0xd6, 0x36, 0x60,
0x09, 0xfd, 0x3a, 0xca, 0xde, 0x20, 0x0f, 0xed, 0x90, 0x87, 0x9a, 0x28, 0x7f, 0x13, 0x56, 0x25,
0xb8, 0x9d, 0x7b, 0xeb, 0x22, 0x51, 0xb9, 0x68, 0xff, 0x2e, 0xac, 0x49, 0xd4, 0x41, 0xa1, 0x06,
0x79, 0x6c, 0x97, 0x36, 0xcc, 0x59, 0xf5, 0xbf, 0x0e, 0xeb, 0xa5, 0x95, 0xe2, 0xb2, 0x1e, 0xed,
0xad, 0xa1, 0x08, 0x7e, 0xed, 0xc1, 0xaa, 0x63, 0x91, 0x42, 0x83, 0x5e, 0xb5, 0x06, 0x1b, 0x96,
0x06, 0xad, 0x58, 0x6c, 0x92, 0x63, 0x15, 0x88, 0x4f, 0xad, 0x5f, 0xc3, 0x2b, 0x83, 0xdf, 0x79,
0x86, 0xf9, 0x77, 0x92, 0x58, 0xf0, 0x58, 0xcc, 0xea, 0x99, 0x44, 0x93, 0x9c, 0x16, 0xf7, 0x49,
0x4e, 0x4d, 0x94, 0xff, 0x02, 0xf4, 0x87, 0xf2, 0xa8, 0x5d, 0xd3, 0x1f, 0x6c, 0xa4, 0xff, 0x25,
0xb8, 0xa2, 0x10, 0x85, 0x32, 0x5b, 0x74, 0x51, 0x09, 0x1f, 0xfc, 0xd1, 0x03, 0x1f, 0xd9, 0x7c,
0x27, 0x19, 0x71, 0x34, 0xca, 0x4e, 0x12, 0x1f, 0x47, 0x27, 0x73, 0x18, 0x5c, 0x81, 0x46, 0x32,
0x25, 0xbe, 0xfa, 0xac, 0x91, 0x4c, 0x11, 0x8e, 0x46, 0xc4, 0x43, 0x8f, 0x35, 0xa2, 0x91, 0xef,
0x43, 0x0b, 0x53, 0x9c, 0xba, 0x8c, 0x7e, 0xe3, 0x49, 0x1f, 0x86, 0xe3, 0x19, 0x27, 0x05, 0xf5,
0x99, 0x04, 0xa4, 0xf7, 0x45, 0xb1, 0x78, 0x33, 0x4d, 0x7e, 0xc8, 0x63, 0x0a, 0x69, 0x14, 0xb5,
0x40, 0x49, 0xcb, 0x88, 0x87, 0xb3, 0xa3, 0xb7, 0xf9, 0x39, 0x85, 0x74, 0x8f, 0x15, 0x88, 0xe0,
0x9b, 0x05, 0xd7, 0xdf, 0x4e, 0x32, 0x2e, 0x63, 0x6e, 0x4e, 0xbe, 0x45, 0x0e, 0x92, 0x8c, 0xcb,
0x74, 0xd8, 0x63, 0x12, 0x08, 0xfe, 0xe0, 0xc1, 0x35, 0x53, 0xf0, 0xbd, 0x91, 0xb2, 0x8d, 0x16,
0xc2, 0x33, 0x84, 0xb8, 0x01, 0x30, 0x4d, 0x93, 0x69, 0x22, 0xc2, 0xf1, 0xde, 0x48, 0xc5, 0xa6,
0x81, 0x41, 0xf7, 0x7a, 0x34, 0x8b, 0xb2, 0x3d, 0xad, 0x0c, 0x05, 0x19, 0x61, 0xde, 0xaa, 0x0e,
0xf3, 0xb6, 0xa9, 0x5e, 0x4b, 0xe4, 0x8e, 0x2b, 0xf2, 0x2f, 0x1b, 0x70, 0x45, 0x33, 0x9c, 0x33,
0x2b, 0x2d, 0xe0, 0xe5, 0x16, 0x28, 0x2e, 0x6c, 0x54, 0x5f, 0xd8, 0x34, 0x2f, 0xbc, 0x01, 0x90,
0x85, 0xe9, 0x09, 0xa7, 0x80, 0x57, 0x56, 0x33, 0x30, 0xae, 0x95, 0xda, 0x65, 0x2b, 0xdd, 0xd6,
0xba, 0xed, 0x50, 0x9a, 0x7c, 0xc6, 0x48, 0x93, 0xb6, 0x6d, 0x94, 0xda, 0x31, 0x64, 0x8e, 0xd3,
0x64, 0x42, 0x17, 0x4a, 0xab, 0xe6, 0xb0, 0x11, 0xa4, 0xdd, 0x72, 0x90, 0x6a, 0xbd, 0xf4, 0x5c,
0xbd, 0xfc, 0xc9, 0x83, 0xeb, 0x8c, 0x0f, 0x79, 0x34, 0xcd, 0xf4, 0xb5, 0xca, 0x89, 0xab, 0x2c,
0x79, 0x07, 0x3a, 0x43, 0x5a, 0x25, 0x05, 0x95, 0x39, 0x2e, 0x62, 0x80, 0x29, 0x42, 0xff, 0x25,
0x68, 0x4d, 0x53, 0xfe, 0x21, 0xa9, 0x6e, 0x69, 0xeb, 0x69, 0x67, 0x83, 0x36, 0x05, 0x23, 0x22,
0xff, 0x0e, 0x2c, 0x0e, 0x67, 0x69, 0xca, 0xe3, 0x4c, 0xbd, 0x80, 0x73, 0xe9, 0x35, 0x5d, 0xf0,
0x5b, 0x0f, 0x9e, 0x77, 0x04, 0x40, 0x2e, 0x90, 0xec, 0xbd, 0xe9, 0x28, 0xcc, 0xb8, 0xa5, 0x34,
0xcf, 0x51, 0xda, 0x6d, 0xc5, 0x9d, 0x14, 0xe7, 0xd9, 0x0a, 0x71, 0x1c, 0x0e, 0xbf, 0x5c, 0x70,
0xd8, 0xbc, 0x78, 0x4f, 0xce, 0xe5, 0x7f, 0x3c, 0x78, 0xda, 0xe1, 0x92, 0xac, 0x9b, 0xc4, 0xbc,
0xe4, 0x85, 0xd5, 0xaf, 0x98, 0xed, 0x6d, 0xcd, 0x92, 0xb7, 0xe1, 0x7a, 0x92, 0x85, 0x63, 0x3c,
0x5a, 0x07, 0x8c, 0x81, 0xa1, 0xd2, 0x06, 0x21, 0xbc, 0x96, 0x7c, 0xb1, 0xcd, 0x0a, 0x04, 0xe5,
0xe2, 0x44, 0x64, 0xb4, 0xd8, 0xa1, 0xc5, 0x1c, 0xf6, 0x07, 0xb0, 0x88, 0xde, 0xc7, 0x44, 0xa6,
0x7c, 0x4e, 0x83, 0x78, 0xe7, 0x28, 0x89, 0xb9, 0x14, 0x96, 0xdc, 0xae, 0xcd, 0x0c, 0x0c, 0xda,
0xe6, 0x29, 0x2d, 0xee, 0x5b, 0x69, 0x32, 0x9b, 0x3e, 0x51, 0x7e, 0xcc, 0xf3, 0x93, 0x0c, 0x35,
0x95, 0x9f, 0x2e, 0x8e, 0x32, 0x2a, 0xfa, 0x94, 0xbf, 0x0b, 0x95, 0x19, 0x0c, 0x4c, 0xf0, 0x6f,
0x97, 0xcb, 0xcf, 0x25, 0x3b, 0x6c, 0xc0, 0x52, 0x61, 0x1d, 0xcd, 0xb3, 0x89, 0xba, 0x04, 0xe7,
0xa6, 0xe7, 0x76, 0xe6, 0x86, 0xfb, 0xa2, 0x5b, 0xd5, 0x18, 0xd2, 0x76, 0x4b, 0xd2, 0x7e, 0xec,
0xc1, 0xba, 0xe3, 0x89, 0xa6, 0x69, 0xaa, 0xa2, 0x7e, 0xcb, 0x89, 0xfa, 0x75, 0xc7, 0xe5, 0x8d,
0xfd, 0x79, 0xd8, 0xdf, 0xb2, 0xc2, 0xbe, 0x72, 0x87, 0x15, 0x57, 0xaf, 0xb9, 0x91, 0x5f, 0xb7,
0x25, 0x0f, 0xab, 0x9f, 0x79, 0x70, 0x8d, 0xf1, 0x47, 0x79, 0xa5, 0x40, 0x29, 0x22, 0x3e, 0x4e,
0xe6, 0x7b, 0x58, 0xa4, 0x1f, 0x20, 0xf3, 0xc5, 0x6d, 0x1a, 0xc2, 0xce, 0x7b, 0x74, 0xac, 0x34,
0xda, 0x76, 0xd3, 0xe8, 0x0e, 0xac, 0x31, 0x2e, 0xa6, 0x16, 0x23, 0xd2, 0xca, 0x5f, 0x84, 0x66,
0x34, 0x92, 0x6f, 0x6a, 0x4d, 0x3a, 0x43, 0x9a, 0xe0, 0x2d, 0xcc, 0x11, 0xce, 0x21, 0x24, 0xb6,
0xf0, 0x6f, 0x9a, 0xa7, 0xd4, 0xa9, 0x86, 0x0e, 0x9a, 0xca, 0xb7, 0x6e, 0x3b, 0x8a, 0x47, 0xfb,
0x51, 0xcc, 0xd3, 0x9d, 0xc9, 0x88, 0xfc, 0x22, 0x8a, 0x47, 0x6f, 0x50, 0x6f, 0xa6, 0xea, 0x66,
0x03, 0x43, 0xf2, 0x45, 0xf1, 0x68, 0x07, 0xdd, 0x4f, 0x15, 0x4f, 0x05, 0xa2, 0xc8, 0x3e, 0x78,
0x9f, 0x9d, 0x7d, 0x10, 0x13, 0xfc, 0xc5, 0x83, 0xab, 0xd6, 0x95, 0x64, 0x85, 0x39, 0xc5, 0x00,
0x1e, 0x7b, 0x60, 0x46, 0x92, 0x81, 0xb1, 0xf9, 0x68, 0xd6, 0xf3, 0xd1, 0x72, 0xf9, 0xc8, 0x2b,
0xd2, 0xc3, 0x68, 0xc2, 0x55, 0x44, 0x15, 0x08, 0x8c, 0x38, 0x59, 0x9e, 0xca, 0xc0, 0x51, 0x75,
0x93, 0x81, 0x0a, 0x7e, 0xe1, 0xc1, 0xc0, 0x88, 0x8e, 0x8b, 0xc5, 0xb9, 0x69, 0x3d, 0x20, 0x03,
0xc3, 0x32, 0xd6, 0x5e, 0xe5, 0xe5, 0x5b, 0xee, 0xeb, 0x31, 0x7f, 0x43, 0xee, 0xe3, 0xf7, 0x65,
0x95, 0x8e, 0xe2, 0x21, 0xc5, 0xb7, 0x62, 0x92, 0x92, 0x5a, 0x26, 0x52, 0x82, 0xe4, 0xa6, 0x40,
0xa0, 0xef, 0x4f, 0xf0, 0x18, 0xfd, 0x7e, 0x10, 0x10, 0x7c, 0xb7, 0xa8, 0x7f, 0xf0, 0x98, 0x07,
0x91, 0xc8, 0xe6, 0x44, 0xc9, 0x2d, 0xe8, 0xd0, 0x16, 0x59, 0xf2, 0x2d, 0x6d, 0xad, 0x39, 0xee,
0xa6, 0xb8, 0x60, 0x8a, 0x2a, 0xf8, 0xa8, 0xf4, 0x00, 0xeb, 0x0b, 0xd4, 0x03, 0xac, 0x4b, 0x00,
0xaf, 0xf2, 0x49, 0xd7, 0xc4, 0xe5, 0x12, 0xa0, 0x51, 0x4f, 0x9f, 0x6b, 0xe8, 0x31, 0x26, 0x01,
0x19, 0x37, 0x96, 0x78, 0x2f, 0x41, 0x6b, 0x1c, 0x89, 0xec, 0xc2, 0x7b, 0x91, 0x08, 0x4d, 0xa3,
0x9b, 0x6f, 0x29, 0x76, 0x8d, 0x69, 0x14, 0x61, 0xf0, 0x53, 0xed, 0xf5, 0xe8, 0x41, 0x5b, 0xfb,
0x61, 0x14, 0xef, 0x87, 0x53, 0x23, 0x33, 0x7b, 0xf3, 0xbb, 0xa5, 0x86, 0xce, 0x20, 0xd5, 0xdd,
0x52, 0xb3, 0xb6, 0x5b, 0x6a, 0xd9, 0xdd, 0x68, 0x70, 0x4f, 0xd6, 0xf3, 0x05, 0x1b, 0xe4, 0xae,
0xb7, 0xa0, 0x1d, 0x65, 0x7c, 0xa2, 0xb3, 0x86, 0x25, 0x8f, 0xc9, 0x30, 0x93, 0x64, 0xc1, 0x3f,
0x9b, 0xf2, 0x1d, 0xcc, 0x73, 0x8f, 0x8a, 0xc8, 0x17, 0xa0, 0x8f, 0x37, 0x15, 0xdd, 0x90, 0x47,
0xcd, 0x9a, 0x8d, 0xc4, 0x7e, 0xb7, 0x40, 0x98, 0x2d, 0x98, 0x8b, 0x9e, 0xf3, 0x5e, 0x16, 0x5a,
0x6b, 0x59, 0x5a, 0x0b, 0x60, 0x79, 0x9a, 0xf2, 0xe2, 0x72, 0xd9, 0x29, 0x5a, 0x38, 0x5b, 0xb3,
0x1d, 0xb7, 0x0f, 0x95, 0x27, 0xa0, 0x30, 0x5c, 0xb5, 0xe1, 0xfa, 0x84, 0x1c, 0x47, 0x11, 0x95,
0x13, 0x74, 0xe5, 0x09, 0x39, 0x02, 0x75, 0x9f, 0x9d, 0xed, 0x24, 0xb3, 0x38, 0x13, 0x54, 0x41,
0xf7, 0x59, 0x0e, 0xcb, 0x35, 0x39, 0x21, 0x1a, 0x80, 0xec, 0x62, 0x35, 0x8c, 0x95, 0x53, 0x76,
0x26, 0x67, 0x4d, 0x4b, 0x34, 0x4c, 0xd2, 0x20, 0xb5, 0xa2, 0xa8, 0xe6, 0x43, 0xbd, 0x75, 0x59,
0xea, 0xd4, 0x42, 0x22, 0xe7, 0x0a, 0x21, 0x0f, 0xe9, 0xd3, 0x21, 0x16, 0xce, 0xbf, 0x09, 0x57,
0xe3, 0x24, 0xde, 0xa1, 0x36, 0xff, 0x50, 0x33, 0xb9, 0x42, 0x4c, 0x96, 0x17, 0x82, 0x6d, 0xb8,
0x7a, 0xc0, 0xc7, 0xc7, 0xaa, 0xa3, 0x3e, 0xc8, 0xc2, 0x13, 0x2e, 0xfc, 0x97, 0x6d, 0x47, 0xd1,
0x81, 0xe2, 0x12, 0x6a, 0x3f, 0x79, 0x00, 0x57, 0xdc, 0x25, 0xcc, 0xac, 0x22, 0x0b, 0xd3, 0x6c,
0xd7, 0x74, 0x7c, 0x13, 0x85, 0xf6, 0xe5, 0x71, 0x78, 0xa4, 0xca, 0xda, 0x3e, 0x53, 0x50, 0xf0,
0x77, 0x0f, 0xae, 0xb9, 0xc7, 0x91, 0xfb, 0xd6, 0x97, 0x5f, 0xfd, 0xfc, 0x61, 0x7e, 0x19, 0xda,
0x02, 0x37, 0x39, 0x1d, 0x46, 0x99, 0x7b, 0xa2, 0xb2, 0x6a, 0xaa, 0x96, 0x53, 0x53, 0xdd, 0x00,
0xe0, 0x67, 0x7c, 0x68, 0xcf, 0xd1, 0x0a, 0xcc, 0xa7, 0xee, 0xd7, 0x02, 0x0e, 0x6b, 0x0f, 0x92,
0x61, 0x38, 0xd6, 0xcc, 0x14, 0xd2, 0xdd, 0xd1, 0x5c, 0x7b, 0x56, 0x17, 0x51, 0xa5, 0x09, 0xcd,
0x39, 0x79, 0xd3, 0x5e, 0x3c, 0xe2, 0x67, 0x2a, 0x7b, 0x68, 0x30, 0xb8, 0x0b, 0x2b, 0xb2, 0xfc,
0x42, 0x0e, 0x2a, 0x95, 0x97, 0xcf, 0x11, 0x1a, 0xc6, 0x1c, 0x21, 0x08, 0xe0, 0x8a, 0xdc, 0xb7,
0x13, 0xc6, 0x43, 0x3e, 0xae, 0xda, 0x19, 0x7c, 0xa2, 0xa6, 0x44, 0xc4, 0xce, 0x45, 0xf5, 0x7b,
0x76, 0xae, 0xeb, 0xf7, 0xec, 0x1c, 0xb5, 0x25, 0x45, 0x84, 0x5a, 0xc3, 0xec, 0x2e, 0x68, 0x01,
0x5f, 0x82, 0x16, 0xaa, 0x6d, 0xb0, 0x44, 0xf4, 0xd7, 0x15, 0xbd, 0x2d, 0xd9, 0xee, 0x02, 0x23,
0x22, 0x6a, 0x45, 0x89, 0x6b, 0x0a, 0x9d, 0xe2, 0x78, 0x57, 0xa0, 0xdd, 0x05, 0xa6, 0x08, 0xb7,
0x17, 0x95, 0x12, 0x82, 0x9f, 0x14, 0x35, 0xb0, 0x65, 0x19, 0x25, 0xde, 0x6d, 0xeb, 0xbd, 0xaa,
0x35, 0x4d, 0xa9, 0x29, 0x6c, 0x5c, 0xbc, 0x27, 0x7f, 0xb7, 0x3e, 0xf1, 0xe0, 0xb9, 0x2a, 0x36,
0xe6, 0x76, 0x86, 0xb9, 0xab, 0x37, 0x2e, 0xe5, 0xea, 0x76, 0x4b, 0xd8, 0xac, 0x6f, 0x09, 0x5b,
0x75, 0x2d, 0x61, 0x7b, 0x7e, 0x4b, 0xd8, 0xb1, 0x5a, 0xc2, 0xe0, 0x23, 0x78, 0xb6, 0x4a, 0x24,
0xa1, 0x4a, 0x81, 0x9b, 0x96, 0x6a, 0x07, 0x73, 0x04, 0x10, 0xe5, 0x72, 0xa9, 0x71, 0xc1, 0x86,
0x5c, 0xa9, 0xbf, 0xf1, 0xc0, 0x67, 0xfc, 0xd1, 0xbb, 0x33, 0x9e, 0x9e, 0x23, 0x99, 0xca, 0x71,
0xf6, 0xc8, 0xb8, 0xc8, 0x1e, 0x6e, 0x4b, 0x70, 0x0d, 0xda, 0x43, 0x4c, 0x95, 0x4a, 0x5d, 0x12,
0x40, 0x4d, 0x8d, 0xa2, 0x94, 0xcb, 0xda, 0x59, 0x69, 0x2a, 0x47, 0x18, 0x4f, 0x57, 0xdb, 0x7a,
0xba, 0xae, 0x41, 0x3b, 0xa2, 0x70, 0x95, 0x1d, 0xb5, 0x04, 0x82, 0x77, 0xb1, 0x5a, 0x99, 0x8e,
0xcf, 0x5d, 0x0e, 0x5f, 0xa7, 0x27, 0x48, 0xfa, 0x88, 0xca, 0xc4, 0xb5, 0x6e, 0x54, 0x50, 0x07,
0xdf, 0x37, 0xfe, 0x43, 0xd9, 0x51, 0xd3, 0x65, 0xa1, 0x4b, 0x56, 0x11, 0x9d, 0xc4, 0xea, 0xc9,
0xa6, 0xdf, 0x68, 0x58, 0x6a, 0x9d, 0xf7, 0x43, 0xd9, 0x6d, 0x2f, 0xb3, 0x1c, 0x2e, 0x7a, 0xec,
0xa6, 0x31, 0x03, 0x0c, 0x7e, 0x64, 0xfc, 0xef, 0x21, 0xcf, 0x57, 0x4d, 0xc3, 0x96, 0xa5, 0x55,
0xbb, 0x33, 0x71, 0xca, 0x88, 0x5c, 0xe3, 0xb7, 0xa1, 0x79, 0x34, 0x16, 0xca, 0xa0, 0xa5, 0x7f,
0x06, 0x2c, 0xf6, 0x19, 0x52, 0x06, 0x99, 0x1c, 0x35, 0xd2, 0x32, 0x15, 0x61, 0x4f, 0x70, 0xf9,
0x26, 0xac, 0x46, 0xc2, 0x50, 0xa7, 0x7a, 0x4d, 0xba, 0xcc, 0x45, 0x07, 0xbf, 0xf2, 0xc0, 0xdf,
0xc1, 0x53, 0xde, 0x10, 0x82, 0x67, 0x87, 0x69, 0x18, 0x8b, 0x63, 0x9e, 0xa2, 0x27, 0x84, 0x88,
0xb8, 0x7f, 0xc6, 0x87, 0xba, 0xf4, 0xce, 0x11, 0xf8, 0x0c, 0x12, 0x70, 0x70, 0x3e, 0x39, 0x4a,
0xc6, 0xca, 0xad, 0x4c, 0x14, 0xfa, 0x4a, 0x38, 0xc9, 0x1d, 0xac, 0xc9, 0x14, 0x84, 0xf8, 0x2c,
0x31, 0x1e, 0x25, 0x05, 0xa1, 0x01, 0x63, 0x1d, 0x81, 0x3d, 0x46, 0xbf, 0x83, 0xff, 0x76, 0x8c,
0xc1, 0xbd, 0x52, 0xc6, 0x5d, 0xec, 0xd1, 0x51, 0x75, 0x4a, 0x19, 0xcf, 0x55, 0x2b, 0x56, 0x52,
0x53, 0x4e, 0x24, 0xd8, 0x7f, 0x55, 0x37, 0x0b, 0xe5, 0x69, 0x96, 0xab, 0x70, 0x4c, 0xd4, 0x44,
0xeb, 0x7f, 0x0d, 0xfa, 0xa1, 0xa9, 0x15, 0xd5, 0xb2, 0xeb, 0x8c, 0x4d, 0x1a, 0x13, 0x7a, 0x71,
0x77, 0x81, 0xd9, 0xd4, 0xf9, 0xf6, 0xef, 0x44, 0xd9, 0xe9, 0x28, 0x0d, 0x1f, 0x93, 0x70, 0xee,
0x76, 0xbd, 0x98, 0x6f, 0xd7, 0x08, 0xff, 0x55, 0xe8, 0x66, 0xfa, 0xe2, 0x4e, 0xfd, 0xc5, 0x39,
0x21, 0x6e, 0x7a, 0xac, 0xaf, 0x5b, 0xac, 0xbf, 0x2e, 0x27, 0xf4, 0xef, 0xc3, 0x8a, 0x3e, 0xe0,
0x30, 0x21, 0x8b, 0x77, 0x2d, 0x2d, 0xd9, 0xf7, 0x49, 0x92, 0xdd, 0x05, 0xe6, 0x6c, 0xf2, 0xbf,
0x0a, 0x10, 0xe7, 0x73, 0x55, 0x2a, 0x20, 0xeb, 0x26, 0xa7, 0xbb, 0x0b, 0xcc, 0x20, 0xf7, 0xdf,
0x84, 0xd5, 0xd8, 0x9e, 0xb1, 0xa8, 0xf7, 0xb4, 0x66, 0x0a, 0xb3, 0xbb, 0xc0, 0xdc, 0x4d, 0xfe,
0x36, 0xac, 0x0a, 0x9d, 0x6c, 0xd4, 0x39, 0xf2, 0x9d, 0x35, 0xdb, 0x3b, 0x63, 0x15, 0xcf, 0x70,
0x36, 0xf8, 0x6f, 0x83, 0x3f, 0x2c, 0x85, 0x84, 0x7a, 0x7f, 0xb5, 0x40, 0xe5, 0x98, 0xd9, 0x5d,
0x60, 0x15, 0xdb, 0xfc, 0x6f, 0x40, 0x7f, 0x6a, 0xb6, 0x56, 0x83, 0x7e, 0xa9, 0x4d, 0x33, 0x07,
0x18, 0xe8, 0x07, 0x16, 0xbd, 0xff, 0x3e, 0xac, 0x1b, 0x7f, 0x1c, 0x3a, 0x2a, 0xa0, 0x12, 0xf8,
0x02, 0x35, 0xd7, 0x6c, 0x37, 0x8a, 0x99, 0x36, 0x16, 0x33, 0x45, 0xed, 0xf0, 0xb1, 0x07, 0x6b,
0x46, 0xbb, 0x6b, 0xc4, 0xd6, 0xbc, 0xd9, 0x99, 0x51, 0xb5, 0x5e, 0x2e, 0x49, 0xbd, 0x62, 0xcd,
0xce, 0x4a, 0x91, 0x6c, 0xfd, 0x1b, 0x2a, 0x1f, 0xca, 0xbb, 0xee, 0xf4, 0xac, 0x7e, 0x53, 0xfe,
0x58, 0xbe, 0x6d, 0x0d, 0xff, 0x8b, 0x80, 0xff, 0x2c, 0xb9, 0x35, 0xf8, 0x71, 0x0b, 0x5f, 0x36,
0xfb, 0x34, 0x2a, 0x63, 0xec, 0x3a, 0xc4, 0x2b, 0xd5, 0x21, 0x1b, 0xb0, 0x44, 0x90, 0x54, 0xa3,
0x52, 0xba, 0x89, 0xf2, 0x5f, 0x84, 0x15, 0xac, 0x3d, 0x0e, 0xc2, 0x09, 0x57, 0x44, 0xf2, 0x79,
0x76, 0xb0, 0x45, 0x61, 0xda, 0xaa, 0x6e, 0x2d, 0xdb, 0x6e, 0x43, 0x5e, 0x34, 0x7d, 0x9d, 0xba,
0xa6, 0x6f, 0xb1, 0xa6, 0xe9, 0xeb, 0x3a, 0x4d, 0x9f, 0xd5, 0x8c, 0xf6, 0xdc, 0x66, 0xd4, 0x68,
0x09, 0xe1, 0x82, 0x96, 0x70, 0xe9, 0x32, 0x2d, 0xe1, 0x72, 0x45, 0x4b, 0x58, 0x6a, 0xd8, 0xfb,
0x97, 0x6c, 0xd8, 0x57, 0xaa, 0x1b, 0xf6, 0x4d, 0x58, 0xa5, 0xbf, 0x51, 0xef, 0x17, 0xbd, 0xd1,
0xaa, 0xa4, 0x74, 0xd0, 0xc1, 0x0f, 0xca, 0xb1, 0xc1, 0xf8, 0x30, 0x49, 0x47, 0x9f, 0x57, 0x6c,
0x04, 0x5f, 0x80, 0xa5, 0x7c, 0xf9, 0xf0, 0x8c, 0x9e, 0xcd, 0xb3, 0x7c, 0x28, 0x81, 0xcf, 0x26,
0x41, 0x72, 0x94, 0x5a, 0xcc, 0x85, 0x0f, 0xd1, 0x0f, 0xdc, 0xf1, 0xc3, 0x65, 0xfe, 0xe2, 0x0e,
0x7e, 0xdf, 0x80, 0xab, 0xd6, 0x50, 0xf6, 0xff, 0xcb, 0xa3, 0x7b, 0x9f, 0xd5, 0xa3, 0x7b, 0x86,
0x47, 0x57, 0xd8, 0xbf, 0x57, 0x6d, 0xff, 0xb7, 0xe0, 0x29, 0x4b, 0x59, 0xa4, 0x77, 0x4c, 0x68,
0x1d, 0xe2, 0xdb, 0x1d, 0x45, 0x95, 0x14, 0xcb, 0x14, 0x9d, 0x4c, 0x4c, 0xae, 0xfd, 0x50, 0x86,
0x6a, 0xeb, 0x95, 0x46, 0x6b, 0xd6, 0x47, 0x41, 0x7f, 0x6d, 0xc0, 0x4a, 0x51, 0x2f, 0xe1, 0x23,
0x84, 0xee, 0x88, 0x5d, 0xbf, 0x76, 0x47, 0xfc, 0x4d, 0x29, 0x3f, 0xd1, 0xad, 0x40, 0x96, 0xa0,
0x91, 0xa3, 0xbc, 0x2e, 0x20, 0xf3, 0x74, 0x99, 0x81, 0x31, 0x7c, 0xaf, 0x65, 0xfa, 0x9e, 0x51,
0xe2, 0xb5, 0xad, 0x12, 0xcf, 0x87, 0x16, 0xc7, 0x1a, 0x42, 0xda, 0x85, 0x7e, 0x53, 0x5b, 0x22,
0x6b, 0x45, 0xf9, 0xd7, 0x9a, 0x82, 0x50, 0x20, 0x29, 0xf8, 0xf9, 0x94, 0x93, 0x3d, 0xfa, 0xac,
0x40, 0x18, 0xe6, 0x07, 0xcb, 0xfc, 0xf4, 0xe9, 0x02, 0xba, 0x0d, 0xea, 0x52, 0x59, 0xea, 0x3a,
0x51, 0x94, 0xf0, 0xf4, 0xa7, 0x7c, 0x98, 0x86, 0x8a, 0x6a, 0x4d, 0xce, 0x3a, 0x0a, 0x0c, 0x26,
0x2a, 0x31, 0x1b, 0x0e, 0xb9, 0x10, 0x83, 0xa7, 0x49, 0x74, 0x0d, 0x06, 0x7f, 0xf3, 0xe4, 0x28,
0x99, 0x26, 0x1b, 0xf7, 0x8e, 0x28, 0x53, 0xcc, 0x1d, 0x7a, 0x9a, 0x63, 0xcb, 0x86, 0xf3, 0xe9,
0xd1, 0x45, 0x23, 0xcf, 0x17, 0x61, 0x65, 0x1a, 0xe2, 0x3b, 0xb5, 0x6f, 0x0e, 0x3e, 0x97, 0x99,
0x83, 0xbd, 0x60, 0xe8, 0xff, 0x02, 0x34, 0xb3, 0x33, 0xf9, 0x89, 0xce, 0xd2, 0x96, 0xaf, 0x3c,
0xef, 0xb0, 0xf8, 0x4e, 0x8d, 0xe1, 0x72, 0xf0, 0x67, 0xf5, 0x41, 0x83, 0x29, 0x14, 0x75, 0x50,
0x97, 0x15, 0xac, 0xf7, 0xc4, 0x82, 0xf5, 0x3e, 0xa5, 0x60, 0x57, 0x0a, 0xc1, 0x7a, 0x52, 0x88,
0x44, 0xf6, 0x69, 0xdb, 0x63, 0x71, 0x10, 0x9d, 0xc4, 0x07, 0xb3, 0x89, 0xfe, 0x38, 0x6b, 0x9e,
0x10, 0x79, 0xbb, 0xd7, 0x30, 0x3f, 0xf9, 0xf0, 0xa1, 0x35, 0x11, 0x27, 0xb2, 0x07, 0x5c, 0x66,
0xf4, 0x1b, 0x29, 0xb1, 0x79, 0x14, 0x83, 0x16, 0x21, 0x25, 0x10, 0x7c, 0x0f, 0x9e, 0xa9, 0xbc,
0xf0, 0xe0, 0x34, 0x79, 0xfc, 0x04, 0x97, 0xf6, 0xe4, 0xa5, 0xc1, 0x91, 0x9e, 0x6b, 0xeb, 0xe3,
0xc9, 0x22, 0xaf, 0x41, 0x2b, 0x2a, 0x7a, 0xe4, 0x0d, 0x6b, 0xac, 0x5d, 0xc1, 0x07, 0x23, 0x6a,
0xd9, 0x60, 0x4d, 0xa3, 0xa1, 0xbe, 0x56, 0x41, 0x01, 0x83, 0x95, 0x07, 0x3c, 0x1c, 0xf1, 0xf4,
0xe0, 0x3c, 0x1e, 0xea, 0x09, 0xd8, 0xde, 0x3d, 0x3d, 0x75, 0xd9, 0xbb, 0x87, 0x91, 0x70, 0x14,
0x0a, 0xbe, 0x37, 0x3a, 0x53, 0x89, 0x5c, 0x83, 0x78, 0x66, 0x72, 0x7c, 0x2c, 0xb8, 0x4e, 0xde,
0x0a, 0x0a, 0x7e, 0xee, 0x41, 0x1f, 0xf9, 0x79, 0xb8, 0xf5, 0xf0, 0x60, 0x76, 0xb4, 0x2f, 0x74,
0x39, 0xe9, 0xe9, 0x72, 0xd2, 0x7f, 0x05, 0xba, 0x43, 0x35, 0x99, 0x55, 0xe5, 0x7c, 0x85, 0x67,
0x62, 0x2f, 0xa2, 0xa9, 0xfc, 0x3b, 0xb0, 0x28, 0xce, 0xe3, 0xe1, 0xbe, 0x38, 0x71, 0xe6, 0x63,
0x36, 0xf7, 0xbb, 0x0b, 0x4c, 0xd3, 0x15, 0x35, 0xeb, 0xfb, 0xb0, 0x72, 0x7f, 0x2c, 0x87, 0x15,
0x6a, 0xa6, 0xbf, 0x0e, 0xdd, 0x48, 0xc8, 0x9d, 0xc4, 0x55, 0x97, 0xe5, 0xb0, 0xff, 0x32, 0x74,
0xc6, 0x72, 0xa5, 0x51, 0x73, 0x11, 0x53, 0x44, 0xc1, 0xf3, 0xd0, 0xdb, 0xd6, 0xff, 0x83, 0xa2,
0x4f, 0x7e, 0xc0, 0xcf, 0x95, 0xf2, 0xf0, 0xe7, 0xd6, 0xeb, 0xd0, 0xcb, 0x3f, 0x16, 0xf5, 0x6f,
0x42, 0x67, 0x4f, 0xe0, 0x09, 0x7e, 0x3f, 0x7f, 0x02, 0x1e, 0xbd, 0x13, 0x8d, 0xd7, 0xaf, 0x2a,
0x70, 0x4f, 0xec, 0x84, 0xb3, 0x93, 0xd3, 0xec, 0xbd, 0x69, 0xb0, 0x70, 0xd4, 0xa1, 0x2f, 0x44,
0x5f, 0xfd, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x32, 0x10, 0x4a, 0x73, 0x6e, 0x2a, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
......
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