Skip to content
Snippets Groups Projects
Commit 3e9db936 authored by Josh Brooks's avatar Josh Brooks
Browse files

Implement checks for group changes within network.Instance's ndf

parent 187e1d60
No related branches found
No related tags found
No related merge requests found
......@@ -8,12 +8,10 @@ require (
github.com/pkg/errors v0.9.1
github.com/spf13/jwalterweatherman v1.1.0
gitlab.com/elixxir/crypto v0.0.0-20200229000841-b1ee7117a1d0
gitlab.com/elixxir/primitives v0.0.0-20200301205752-350e61bd19b3
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 // indirect
gitlab.com/elixxir/primitives v0.0.0-20200305183907-bb65b3b9afd6
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/genproto v0.0.0-20200303153909-beee998c1893 // indirect
google.golang.org/genproto v0.0.0-20200305110556-506484158171 // indirect
google.golang.org/grpc v1.27.1
)
......
......@@ -48,14 +48,20 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
gitlab.com/elixxir/crypto v0.0.0-20200206203107-b8926242da23 h1:J9MKdOxLGzDZoLy2Q0CAxPlPjSH+k4NG3JhgvatAZjo=
gitlab.com/elixxir/crypto v0.0.0-20200206203107-b8926242da23/go.mod h1:wWulHuSqxiGhvasduZrtyTTqy+7y5ebe440GdORhzig=
gitlab.com/elixxir/crypto v0.0.0-20200229000841-b1ee7117a1d0 h1:2oq/Y1pA3bwCdlRjhFjoOtb2somDY+wYz2vuiOQkVVA=
gitlab.com/elixxir/crypto v0.0.0-20200229000841-b1ee7117a1d0/go.mod h1:QPClJr3F90ejz6iHaCZuhexytd6PP97dDnt93iRCTDo=
gitlab.com/elixxir/primitives v0.0.0-20200131183153-e93c6b75019f/go.mod h1:REJMcwIcyxh74VSHqy4S9yYiaEsQYObOPglRExDpk14=
gitlab.com/elixxir/primitives v0.0.0-20200218211222-4193179f359c/go.mod h1:REJMcwIcyxh74VSHqy4S9yYiaEsQYObOPglRExDpk14=
gitlab.com/elixxir/primitives v0.0.0-20200301205752-350e61bd19b3 h1:vPyV7UFvsrDKOmNUMdtyEPCmbzRIpleGarA/ejou6cI=
gitlab.com/elixxir/primitives v0.0.0-20200301205752-350e61bd19b3/go.mod h1:ZCg9za7qWcObBMVRGulVTL/0+Z2zX2BH3XkCPDOtb18=
gitlab.com/elixxir/primitives v0.0.0-20200305183907-bb65b3b9afd6 h1:yKiTmyV5JqYNowu9nJwE/FEAvSMytFgKQ5yoI4YPa98=
gitlab.com/elixxir/primitives v0.0.0-20200305183907-bb65b3b9afd6/go.mod h1:vx+QS3daQGu4WrHMU6IOuddbpJQnEOhbDyhYdHm/nNQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
......@@ -78,6 +84,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
......@@ -96,6 +103,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2El
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200303153909-beee998c1893 h1:OTjq5CN+5TpMIvzqxSFCjbBX3jNKjX0XOPi4SdBxQU8=
google.golang.org/genproto v0.0.0-20200303153909-beee998c1893/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171 h1:xes2Q2k+d/+YNXVw0FpZkIDJiaux4OVrRKXRAzH6A0U=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
......
......@@ -5,31 +5,19 @@
////////////////////////////////////////////////////////////////////////////////
package dataStructures
import (
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/large"
"sync"
)
// todo docstring
type Group struct {
grp *cyclic.Group
mutex *sync.RWMutex
grp string
}
// NewGroup creates a ds.Group with a cyclic.Group and a mutex
func NewGroup(p, g *large.Int) *Group {
ourGroup := cyclic.NewGroup(p, g)
func NewGroup(ourGroup string) *Group {
return &Group{
grp: ourGroup,
mutex: &sync.RWMutex{},
}
}
// Get returns the ds.Groups's cyclic group
func (g *Group) Get() *cyclic.Group {
g.mutex.RLock()
defer g.mutex.RUnlock()
func (g *Group) Get() string {
return g.grp
}
......@@ -6,43 +6,44 @@
package dataStructures
import (
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/large"
"gitlab.com/elixxir/primitives/ndf"
"reflect"
"sync"
"testing"
)
// Happy path
func TestGroup_Get(t *testing.T) {
p := large.NewInt(33)
g := large.NewInt(29)
expectedGroup := cyclic.NewGroup(p, g)
expectedGroup := ndf.Group{
Prime: "123",
SmallPrime: "456",
Generator: "2",
}
ourGroup := &Group{
grp: expectedGroup,
mutex: &sync.RWMutex{},
grp: expectedGroup.String(),
}
receivedGroup := ourGroup.Get()
if !reflect.DeepEqual(expectedGroup, receivedGroup) {
if !reflect.DeepEqual(expectedGroup.String(), receivedGroup) {
t.Errorf("Getter didn't get expected value! "+
"\n\tExpected: %+v"+
"\n\tReceived: %+v", expectedGroup, receivedGroup)
"\n\tReceived: %+v", expectedGroup.String(), receivedGroup)
}
}
// Happy path
func TestNewGroup(t *testing.T) {
p := large.NewInt(33)
g := large.NewInt(29)
expectedGroup := cyclic.NewGroup(p, g)
expectedGroup := ndf.Group{
Prime: "123",
SmallPrime: "456",
Generator: "2",
}
recievedGroup := NewGroup(p, g).Get()
recievedGroup := NewGroup(expectedGroup.String()).Get()
if !reflect.DeepEqual(expectedGroup, recievedGroup) {
if !reflect.DeepEqual(expectedGroup.String(), recievedGroup) {
t.Errorf("\n\tExpected: %+v"+
"\n\tReceived: %+v", expectedGroup, recievedGroup)
"\n\tReceived: %+v", expectedGroup.String(), recievedGroup)
}
}
......@@ -40,7 +40,7 @@ func NewNdf(definition *ndf.NetworkDefinition) (*Ndf, error) {
}
//Updates to a new NDF if the passed NDF is valid
func (file *Ndf) Update(m *pb.NDF) error {
func (file *Ndf) Update(m *pb.NDF, e2eGrp, cmixGrp string) error {
//build the ndf object
decoded, _, err := ndf.DecodeNDF(string(m.Ndf))
......@@ -49,6 +49,14 @@ func (file *Ndf) Update(m *pb.NDF) error {
return errors.WithMessage(err, "Could not decode the NDF")
}
if decoded.E2E.String() != e2eGrp && e2eGrp != "" {
return errors.New("Attempt to change e2e group detected!")
}
if decoded.CMIX.String() != cmixGrp && cmixGrp != "" {
return errors.New("Attempt to change cmix group detected!")
}
file.lock.Lock()
defer file.lock.Unlock()
......
......@@ -18,7 +18,7 @@ func setup() *Ndf {
}
ndf := &Ndf{}
_ = ndf.Update(msg)
_ = ndf.Update(msg, testutils.E2eGrp, testutils.CmixGrp)
return ndf
}
......@@ -39,12 +39,12 @@ func TestNdf_Update(t *testing.T) {
}
ndf := Ndf{}
err := ndf.Update(badMsg)
err := ndf.Update(badMsg, testutils.E2eGrp, testutils.CmixGrp)
if err == nil {
t.Error("Should have returned error when unable to decode ndf")
}
err = ndf.Update(msg)
err = ndf.Update(msg, testutils.E2eGrp, testutils.CmixGrp)
if err != nil {
t.Errorf("Failed to update ndf: %+v", err)
}
......
......@@ -13,18 +13,11 @@ import (
"gitlab.com/elixxir/comms/connect"
pb "gitlab.com/elixxir/comms/mixmessages"
ds "gitlab.com/elixxir/comms/network/dataStructures"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/signature"
"gitlab.com/elixxir/primitives/id"
"gitlab.com/elixxir/primitives/ndf"
)
//todo: how to handle groups? modify network instance to add groups
// add groups, error if they have changed
// w/ structure have concurrency issue
// add rwlocks to groups
// fixme: how to handle full vs partial
// The Instance struct stores a combination of comms info and round info for servers
type Instance struct {
comm *connect.ProtoComms
......@@ -56,12 +49,17 @@ func NewInstance(c *connect.ProtoComms, partial, full *ndf.NetworkDefinition) (*
}
}
cmixGrp := fullNdf.Get().CMIX.String()
e2eGrp := fullNdf.Get().E2E.String()
return &Instance{
comm: c,
partial: partialNdf,
full: fullNdf,
roundUpdates: &ds.Updates{},
roundData: &ds.Data{},
cmixGroup: ds.NewGroup(cmixGrp),
e2eGroup: ds.NewGroup(e2eGrp),
}, nil
}
......@@ -74,7 +72,7 @@ func (i *Instance) UpdatePartialNdf(m *pb.NDF) error {
"for NDF partial verification")
}
return i.partial.update(m, perm.GetPubKey())
return i.partial.update(m, perm.GetPubKey(), i.e2eGroup.Get(), i.cmixGroup.Get())
}
//update the full ndf
......@@ -86,7 +84,7 @@ func (i *Instance) UpdateFullNdf(m *pb.NDF) error {
"for full NDF verification")
}
return i.full.update(m, perm.GetPubKey())
return i.full.update(m, perm.GetPubKey(), i.e2eGroup.Get(), i.cmixGroup.Get())
}
// Return the partial ndf from this instance
......@@ -127,12 +125,12 @@ func (i *Instance) RoundUpdate(info *pb.RoundInfo) error {
}
// GetE2EGroup gets the e2eGroup from the instance
func (i *Instance) GetE2EGroup() *cyclic.Group {
func (i *Instance) GetE2EGroup() string {
return i.e2eGroup.Get()
}
// GetE2EGroup gets the cmixGroup from the instance
func (i *Instance) GetCmixGroup() *cyclic.Group {
func (i *Instance) GetCmixGroup() string {
return i.cmixGroup.Get()
}
......
......@@ -12,7 +12,6 @@ import (
ds "gitlab.com/elixxir/comms/network/dataStructures"
"gitlab.com/elixxir/comms/testkeys"
"gitlab.com/elixxir/comms/testutils"
"gitlab.com/elixxir/crypto/large"
"gitlab.com/elixxir/crypto/signature"
"gitlab.com/elixxir/crypto/signature/rsa"
"gitlab.com/elixxir/primitives/id"
......@@ -282,9 +281,7 @@ func TestInstance_GetPermissioningAddress(t *testing.T) {
// Happy path
func TestInstance_GetCmixGroup(t *testing.T) {
p := large.NewInt(33)
g := large.NewInt(29)
expectedGroup := ds.NewGroup(p, g)
expectedGroup := ds.NewGroup(testutils.E2eGrp)
i := Instance{
cmixGroup: expectedGroup,
......@@ -302,9 +299,7 @@ func TestInstance_GetCmixGroup(t *testing.T) {
// Happy path
func TestInstance_GetE2EGroup(t *testing.T) {
p := large.NewInt(33)
g := large.NewInt(29)
expectedGroup := ds.NewGroup(p, g)
expectedGroup := ds.NewGroup(testutils.E2eGrp)
i := Instance{
e2eGroup: expectedGroup,
......
......@@ -35,13 +35,13 @@ func NewSecuredNdf(definition *ndf.NetworkDefinition) (*SecuredNdf, error) {
}
// unexported NDF update code
func (sndf *SecuredNdf) update(m *pb.NDF, key *rsa.PublicKey) error {
func (sndf *SecuredNdf) update(m *pb.NDF, key *rsa.PublicKey, e2eGrp, cmixGrp string) error {
err := signature.Verify(m, key)
if err != nil {
return errors.WithMessage(err, "Could not validate NDF")
}
return sndf.f.Update(m)
return sndf.f.Update(m, e2eGrp, cmixGrp)
}
// Get the primitives object for an ndf
......
......@@ -23,7 +23,7 @@ func setup() *ds.Ndf {
}
ndf := &ds.Ndf{}
_ = ndf.Update(msg)
_ = ndf.Update(msg, testutils.E2eGrp, testutils.CmixGrp)
return ndf
}
......@@ -71,13 +71,13 @@ func TestSecuredNdf_update(t *testing.T) {
if err != nil {
t.Errorf("Failed to secure ndf: %+v", err)
}
err = sndf.update(&f, privKey.GetPublic())
err = sndf.update(&f, privKey.GetPublic(), "", "")
if err != nil {
t.Errorf("Could not update ndf: %s", err)
}
err = sndf.update(&f, badPub)
err = sndf.update(&f, badPub, testutils.E2eGrp, testutils.CmixGrp)
if err == nil {
t.Errorf("should have received bad key error")
}
......
......@@ -67,4 +67,6 @@ var (
EmptyNdf, _, _ = ndf.DecodeNDF("")
JsonBytes, _ = base64.StdEncoding.DecodeString("AQAAAA7UiTKgAAAAAP5cNTIuMjUuMTM1LjUyLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURnVENDQW1tZ0F3SUJBZ0lKQUtMZFo4VWlnSUFlTUEwR0NTcUdTSWIzRFFFQkJRVUFNRzh4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlEQXBEWVd4cFptOXlibWxoTVJJd0VBWURWUVFIREFsRGJHRnlaVzF2Ym5ReApHekFaQmdOVkJBb01FbEJ5YVhaaGRHVm5jbWwwZVNCRGIzSndMakVhTUJnR0ExVUVBd3dSWjJGMFpYZGhlU291ClkyMXBlQzV5YVhBd0hoY05NVGt3TXpBMU1UZ3pOVFUwV2hjTk1qa3dNekF5TVRnek5UVTBXakJ2TVFzd0NRWUQKVlFRR0V3SlZVekVUTUJFR0ExVUVDQXdLUTJGc2FXWnZjbTVwWVRFU01CQUdBMVVFQnd3SlEyeGhjbVZ0YjI1MApNUnN3R1FZRFZRUUtEQkpRY21sMllYUmxaM0pwZEhrZ1EyOXljQzR4R2pBWUJnTlZCQU1NRVdkaGRHVjNZWGtxCkxtTnRhWGd1Y21sd01JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBOStBYXh3RFAKeEhiaExtbjRIb1p1MG9VTTQ4UXVmYzZUNVhFWlRycE1ycUpBb3VYays2MUpjMEVGSDk2L3NiajdWeXZuWFBSbwpnSUVOYmsyWTg0QmtCOVNrUk1JWHlhL2doOWRPRURTZ252ai95ZzI0bDNiZEtGcUJNS2lGZzAwUFlCMzBmVStBCmJlM09JL2xlMEkrdisrUndIMkFWMEJNcStUNlBjQUdqQ0MxUTFaQjB3UDkvVnFOTVdxNWxiSzl3RDQ2SVFpU2kKK1NnSVFlRTdIb2lBWlhyR08wWTdsOVAzK1ZSb1hqUlFicWZuM0VUTkw5WnZRdWFyd0FZQzlJeDVNeFVyUzVhZwpPbWZqYzhiZmtwWURGQVhSWG1kS05JU0ptdENlYlgya0RycFA4QmRhc3g3RnpzeDU5Y0VVSENsMmFKT1dYYzdSCjVtM2p1T1ZMMUhVeGpRSURBUUFCb3lBd0hqQWNCZ05WSFJFRUZUQVRnaEZuWVhSbGQyRjVLaTVqYldsNExuSnAKY0RBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQU11M3hvYzJMVzJVRXhBQUlZWVdFRVRnZ0xOcmxHb254dGVTdQpqdUpqT1IraWs1U1ZMbjBsRXUyMit6K0ZDQTdnU2s5RmtXdSt2OXFuZk9mbTJBbStXS1lXdjNkSjVSeXBXL2hECk5Ya09ZeFZKTllGeGVTaG5Ib2hOcXE0ZURLcGRxU3hFY3VFckZYSmRMYlpQMXVOczRXSU9LblRoZ3poa3B1eTcKdFpSb3N2T0YxWDV1TDFmclZKekhONWpBU0VEQWE3aEpObVEyNGtoK2RzL0dlMzlmR0Q4cEszMUNXaG5JWGVEbwp2S0Q3d2l2aS9nU09CdGNSV1dMdlU4U2l6WmtTM2hnVHcwbFNPZjVnZXV6dmFzQ0VZbHFyS0Zzc2o2Y1R6YkNCCnh5M3JhM1dhelJUTlRXNFRta0hsQ1VDOUkzb1dUVHh3NWlReEYvSTJrUVFud1I3TDN3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLTUyLjI1LjIxOS4zOC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEZ1RDQ0FtbWdBd0lCQWdJSkFLTGRaOFVpZ0lBZU1BMEdDU3FHU0liM0RRRUJCUVVBTUc4eEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbERiR0Z5WlcxdmJuUXgKR3pBWkJnTlZCQW9NRWxCeWFYWmhkR1ZuY21sMGVTQkRiM0p3TGpFYU1CZ0dBMVVFQXd3UloyRjBaWGRoZVNvdQpZMjFwZUM1eWFYQXdIaGNOTVRrd016QTFNVGd6TlRVMFdoY05Namt3TXpBeU1UZ3pOVFUwV2pCdk1Rc3dDUVlEClZRUUdFd0pWVXpFVE1CRUdBMVVFQ0F3S1EyRnNhV1p2Y201cFlURVNNQkFHQTFVRUJ3d0pRMnhoY21WdGIyNTAKTVJzd0dRWURWUVFLREJKUWNtbDJZWFJsWjNKcGRIa2dRMjl5Y0M0eEdqQVlCZ05WQkFNTUVXZGhkR1YzWVhrcQpMbU50YVhndWNtbHdNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTkrQWF4d0RQCnhIYmhMbW40SG9adTBvVU00OFF1ZmM2VDVYRVpUcnBNcnFKQW91WGsrNjFKYzBFRkg5Ni9zYmo3Vnl2blhQUm8KZ0lFTmJrMlk4NEJrQjlTa1JNSVh5YS9naDlkT0VEU2dudmoveWcyNGwzYmRLRnFCTUtpRmcwMFBZQjMwZlUrQQpiZTNPSS9sZTBJK3YrK1J3SDJBVjBCTXErVDZQY0FHakNDMVExWkIwd1A5L1ZxTk1XcTVsYks5d0Q0NklRaVNpCitTZ0lRZUU3SG9pQVpYckdPMFk3bDlQMytWUm9YalJRYnFmbjNFVE5MOVp2UXVhcndBWUM5SXg1TXhVclM1YWcKT21mamM4YmZrcFlERkFYUlhtZEtOSVNKbXRDZWJYMmtEcnBQOEJkYXN4N0Z6c3g1OWNFVUhDbDJhSk9XWGM3Ugo1bTNqdU9WTDFIVXhqUUlEQVFBQm95QXdIakFjQmdOVkhSRUVGVEFUZ2hGbllYUmxkMkY1S2k1amJXbDRMbkpwCmNEQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFNdTN4b2MyTFcyVUV4QUFJWVlXRUVUZ2dMTnJsR29ueHRlU3UKanVKak9SK2lrNVNWTG4wbEV1MjIreitGQ0E3Z1NrOUZrV3UrdjlxbmZPZm0yQW0rV0tZV3YzZEo1UnlwVy9oRApOWGtPWXhWSk5ZRnhlU2huSG9oTnFxNGVES3BkcVN4RWN1RXJGWEpkTGJaUDF1TnM0V0lPS25UaGd6aGtwdXk3CnRaUm9zdk9GMVg1dUwxZnJWSnpITjVqQVNFREFhN2hKTm1RMjRraCtkcy9HZTM5ZkdEOHBLMzFDV2huSVhlRG8KdktEN3dpdmkvZ1NPQnRjUldXTHZVOFNpelprUzNoZ1R3MGxTT2Y1Z2V1enZhc0NFWWxxcktGc3NqNmNUemJDQgp4eTNyYTNXYXpSVE5UVzRUbWtIbENVQzlJM29XVFR4dzVpUXhGL0kya1FRbndSN0wzdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS01Mi40MS44MC4xMDQtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRGdUQ0NBbW1nQXdJQkFnSUpBS0xkWjhVaWdJQWVNQTBHQ1NxR1NJYjNEUUVCQlFVQU1HOHhDekFKQmdOVgpCQVlUQWxWVE1STXdFUVlEVlFRSURBcERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhEQWxEYkdGeVpXMXZiblF4Ckd6QVpCZ05WQkFvTUVsQnlhWFpoZEdWbmNtbDBlU0JEYjNKd0xqRWFNQmdHQTFVRUF3d1JaMkYwWlhkaGVTb3UKWTIxcGVDNXlhWEF3SGhjTk1Ua3dNekExTVRnek5UVTBXaGNOTWprd016QXlNVGd6TlRVMFdqQnZNUXN3Q1FZRApWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKUTJ4aGNtVnRiMjUwCk1Sc3dHUVlEVlFRS0RCSlFjbWwyWVhSbFozSnBkSGtnUTI5eWNDNHhHakFZQmdOVkJBTU1FV2RoZEdWM1lYa3EKTG1OdGFYZ3VjbWx3TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUE5K0FheHdEUAp4SGJoTG1uNEhvWnUwb1VNNDhRdWZjNlQ1WEVaVHJwTXJxSkFvdVhrKzYxSmMwRUZIOTYvc2JqN1Z5dm5YUFJvCmdJRU5iazJZODRCa0I5U2tSTUlYeWEvZ2g5ZE9FRFNnbnZqL3lnMjRsM2JkS0ZxQk1LaUZnMDBQWUIzMGZVK0EKYmUzT0kvbGUwSSt2KytSd0gyQVYwQk1xK1Q2UGNBR2pDQzFRMVpCMHdQOS9WcU5NV3E1bGJLOXdENDZJUWlTaQorU2dJUWVFN0hvaUFaWHJHTzBZN2w5UDMrVlJvWGpSUWJxZm4zRVROTDladlF1YXJ3QVlDOUl4NU14VXJTNWFnCk9tZmpjOGJma3BZREZBWFJYbWRLTklTSm10Q2ViWDJrRHJwUDhCZGFzeDdGenN4NTljRVVIQ2wyYUpPV1hjN1IKNW0zanVPVkwxSFV4alFJREFRQUJveUF3SGpBY0JnTlZIUkVFRlRBVGdoRm5ZWFJsZDJGNUtpNWpiV2w0TG5KcApjREFOQmdrcWhraUc5dzBCQVFVRkFBT0NBUUVBTXUzeG9jMkxXMlVFeEFBSVlZV0VFVGdnTE5ybEdvbnh0ZVN1Cmp1SmpPUitpazVTVkxuMGxFdTIyK3orRkNBN2dTazlGa1d1K3Y5cW5mT2ZtMkFtK1dLWVd2M2RKNVJ5cFcvaEQKTlhrT1l4VkpOWUZ4ZVNobkhvaE5xcTRlREtwZHFTeEVjdUVyRlhKZExiWlAxdU5zNFdJT0tuVGhnemhrcHV5Nwp0WlJvc3ZPRjFYNXVMMWZyVkp6SE41akFTRURBYTdoSk5tUTI0a2grZHMvR2UzOWZHRDhwSzMxQ1dobklYZURvCnZLRDd3aXZpL2dTT0J0Y1JXV0x2VThTaXpaa1MzaGdUdzBsU09mNWdldXp2YXNDRVlscXJLRnNzajZjVHpiQ0IKeHkzcmEzV2F6UlROVFc0VG1rSGxDVUM5STNvV1RUeHc1aVF4Ri9JMmtRUW53UjdMM3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxOC4yMzcuMTQ3LjEwNS0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEYkRDQ0FsU2dBd0lCQWdJSkFPVU50Wm5lSVlFQ01BMEdDU3FHU0liM0RRRUJCUVVBTUdneEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbERiR0Z5WlcxdmJuUXgKR3pBWkJnTlZCQW9NRWxCeWFYWmhkR1ZuY21sMGVTQkRiM0p3TGpFVE1CRUdBMVVFQXd3S0tpNWpiV2w0TG5KcApjREFlRncweE9UQXpNRFV4T0RNMU5ETmFGdzB5T1RBek1ESXhPRE0xTkROYU1HZ3hDekFKQmdOVkJBWVRBbFZUCk1STXdFUVlEVlFRSURBcERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhEQWxEYkdGeVpXMXZiblF4R3pBWkJnTlYKQkFvTUVsQnlhWFpoZEdWbmNtbDBlU0JEYjNKd0xqRVRNQkVHQTFVRUF3d0tLaTVqYldsNExuSnBjRENDQVNJdwpEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBUFAwV3lWa2ZaQS9DRWQyRGdLcGN1ZG4wb0RoCkR3c2pteDhMQkRXc1VnUXp5THJGaVZpZ2ZVbVVlZmtuVUgzZFRKam1pSnRHcUxzYXlDbldkcVdMSFBKWXZGZnMKV1lXMElHRjkzVUcvNE41VUFXTzRva0MzQ1lnS1NpNGVrcGZ3MnpnWnEwZ21ielRuWGNIRjlnZm1RN2pKVUtTRQp0SlBTTnpYcStQWmVKVEM5ekpBYjRMajhRekgxOHJETThEYUwyeTFuczBZMkh1MGVkQkZuL09xYXZCSktiL3VBCm0zQUVqcWVPaEM3RVFValZhbVdsVEJQdDQwK0IvNmFGSlg1QlltMkpGa1JzR0JJeUJWTDQ2TXZDMDJNZ3pUVDkKYkpJSmZ3cW1CYVRydXdlbU5nekd1N0prMDNocXFTMVRVRXZTSTYveDhiVm9iYTNvcmNLa2Y5SHNEakVDQXdFQQpBYU1aTUJjd0ZRWURWUjBSQkE0d0RJSUtLaTVqYldsNExuSnBjREFOQmdrcWhraUc5dzBCQVFVRkFBT0NBUUVBCm5lVW9jTjRBYmNRQUMxK2IzVG84dTVVR2RhR3hoY0d5WkJsQW9lblJWZGpYSzNsVGpzTWRNV2I0UWN0Z05mSWYKVS96dVVuMm14VG1GL2VrUDBnQ0NndGxlWnI5K0RZS1U1aGxYazhLMTB1S3hHRDZFdm9pWFp6bGZlVXVvdGdwMgpxdkkzeXNPbS9odkNmeUVrcWhmSHRieGpWN2o3djdlUUZQYnZOYVhiTGEweXI0QzR2TUsvWjA5VWk5SnJaL1o0CmN5SWt4ZkM2L3JPcUFpclNkSXAwOUVHaXc3R004Z3VIeWdnRTRJaVpyRHNsVDhWM3hJbDk4NWNiQ3hTeGVXMVIKdGdINHJkRVh1VmU5KzMxb0pobVhPRTl1eDJqQ29wOXRFSk1nV2c3SFN0cko1cGxQYmIrSG1qb1gzbkJPMDRFNQo2bTUyUHl6TU5WKzJOMjFJUHBwS3dBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANTIuMTEuMTM2LjIzOC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEYkRDQ0FsU2dBd0lCQWdJSkFPVU50Wm5lSVlFQ01BMEdDU3FHU0liM0RRRUJCUVVBTUdneEN6QUpCZ05WCkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbERiR0Z5WlcxdmJuUXgKR3pBWkJnTlZCQW9NRWxCeWFYWmhkR1ZuY21sMGVTQkRiM0p3TGpFVE1CRUdBMVVFQXd3S0tpNWpiV2w0TG5KcApjREFlRncweE9UQXpNRFV4T0RNMU5ETmFGdzB5T1RBek1ESXhPRE0xTkROYU1HZ3hDekFKQmdOVkJBWVRBbFZUCk1STXdFUVlEVlFRSURBcERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhEQWxEYkdGeVpXMXZiblF4R3pBWkJnTlYKQkFvTUVsQnlhWFpoZEdWbmNtbDBlU0JEYjNKd0xqRVRNQkVHQTFVRUF3d0tLaTVqYldsNExuSnBjRENDQVNJdwpEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBUFAwV3lWa2ZaQS9DRWQyRGdLcGN1ZG4wb0RoCkR3c2pteDhMQkRXc1VnUXp5THJGaVZpZ2ZVbVVlZmtuVUgzZFRKam1pSnRHcUxzYXlDbldkcVdMSFBKWXZGZnMKV1lXMElHRjkzVUcvNE41VUFXTzRva0MzQ1lnS1NpNGVrcGZ3MnpnWnEwZ21ielRuWGNIRjlnZm1RN2pKVUtTRQp0SlBTTnpYcStQWmVKVEM5ekpBYjRMajhRekgxOHJETThEYUwyeTFuczBZMkh1MGVkQkZuL09xYXZCSktiL3VBCm0zQUVqcWVPaEM3RVFValZhbVdsVEJQdDQwK0IvNmFGSlg1QlltMkpGa1JzR0JJeUJWTDQ2TXZDMDJNZ3pUVDkKYkpJSmZ3cW1CYVRydXdlbU5nekd1N0prMDNocXFTMVRVRXZTSTYveDhiVm9iYTNvcmNLa2Y5SHNEakVDQXdFQQpBYU1aTUJjd0ZRWURWUjBSQkE0d0RJSUtLaTVqYldsNExuSnBjREFOQmdrcWhraUc5dzBCQVFVRkFBT0NBUUVBCm5lVW9jTjRBYmNRQUMxK2IzVG84dTVVR2RhR3hoY0d5WkJsQW9lblJWZGpYSzNsVGpzTWRNV2I0UWN0Z05mSWYKVS96dVVuMm14VG1GL2VrUDBnQ0NndGxlWnI5K0RZS1U1aGxYazhLMTB1S3hHRDZFdm9pWFp6bGZlVXVvdGdwMgpxdkkzeXNPbS9odkNmeUVrcWhmSHRieGpWN2o3djdlUUZQYnZOYVhiTGEweXI0QzR2TUsvWjA5VWk5SnJaL1o0CmN5SWt4ZkM2L3JPcUFpclNkSXAwOUVHaXc3R004Z3VIeWdnRTRJaVpyRHNsVDhWM3hJbDk4NWNiQ3hTeGVXMVIKdGdINHJkRVh1VmU5KzMxb0pobVhPRTl1eDJqQ29wOXRFSk1nV2c3SFN0cko1cGxQYmIrSG1qb1gzbkJPMDRFNQo2bTUyUHl6TU5WKzJOMjFJUHBwS3dBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzQuMjEzLjc5LjMxLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURiRENDQWxTZ0F3SUJBZ0lKQU9VTnRabmVJWUVDTUEwR0NTcUdTSWIzRFFFQkJRVUFNR2d4Q3pBSkJnTlYKQkFZVEFsVlRNUk13RVFZRFZRUUlEQXBEWVd4cFptOXlibWxoTVJJd0VBWURWUVFIREFsRGJHRnlaVzF2Ym5ReApHekFaQmdOVkJBb01FbEJ5YVhaaGRHVm5jbWwwZVNCRGIzSndMakVUTUJFR0ExVUVBd3dLS2k1amJXbDRMbkpwCmNEQWVGdzB4T1RBek1EVXhPRE0xTkROYUZ3MHlPVEF6TURJeE9ETTFORE5hTUdneEN6QUpCZ05WQkFZVEFsVlQKTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbERiR0Z5WlcxdmJuUXhHekFaQmdOVgpCQW9NRWxCeWFYWmhkR1ZuY21sMGVTQkRiM0p3TGpFVE1CRUdBMVVFQXd3S0tpNWpiV2w0TG5KcGNEQ0NBU0l3CkRRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFQUDBXeVZrZlpBL0NFZDJEZ0twY3VkbjBvRGgKRHdzam14OExCRFdzVWdRenlMckZpVmlnZlVtVWVma25VSDNkVEpqbWlKdEdxTHNheUNuV2RxV0xIUEpZdkZmcwpXWVcwSUdGOTNVRy80TjVVQVdPNG9rQzNDWWdLU2k0ZWtwZncyemdacTBnbWJ6VG5YY0hGOWdmbVE3akpVS1NFCnRKUFNOelhxK1BaZUpUQzl6SkFiNExqOFF6SDE4ckRNOERhTDJ5MW5zMFkySHUwZWRCRm4vT3FhdkJKS2IvdUEKbTNBRWpxZU9oQzdFUVVqVmFtV2xUQlB0NDArQi82YUZKWDVCWW0ySkZrUnNHQkl5QlZMNDZNdkMwMk1nelRUOQpiSklKZndxbUJhVHJ1d2VtTmd6R3U3SmswM2hxcVMxVFVFdlNJNi94OGJWb2JhM29yY0trZjlIc0RqRUNBd0VBCkFhTVpNQmN3RlFZRFZSMFJCQTR3RElJS0tpNWpiV2w0TG5KcGNEQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUEKbmVVb2NONEFiY1FBQzErYjNUbzh1NVVHZGFHeGhjR3laQmxBb2VuUlZkalhLM2xUanNNZE1XYjRRY3RnTmZJZgpVL3p1VW4ybXhUbUYvZWtQMGdDQ2d0bGVacjkrRFlLVTVobFhrOEsxMHVLeEdENkV2b2lYWnpsZmVVdW90Z3AyCnF2STN5c09tL2h2Q2Z5RWtxaGZIdGJ4alY3ajd2N2VRRlBidk5hWGJMYTB5cjRDNHZNSy9aMDlVaTlKclovWjQKY3lJa3hmQzYvck9xQWlyU2RJcDA5RUdpdzdHTThndUh5Z2dFNElpWnJEc2xUOFYzeElsOTg1Y2JDeFN4ZVcxUgp0Z0g0cmRFWHVWZTkrMzFvSmhtWE9FOXV4MmpDb3A5dEVKTWdXZzdIU3RySjVwbFBiYitIbWpvWDNuQk8wNEU1CjZtNTJQeXpNTlYrMk4yMUlQcHBLd0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tcmVnaXN0cmF0aW9uLmRlZmF1bHQuY21peC5yaXAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRGtEQ0NBbmlnQXdJQkFnSUpBSm5qb3N1U3NQN2dNQTBHQ1NxR1NJYjNEUUVCQlFVQU1IUXhDekFKQmdOVgpCQVlUQWxWVE1STXdFUVlEVlFRSURBcERZV3hwWm05eWJtbGhNUkl3RUFZRFZRUUhEQWxEYkdGeVpXMXZiblF4Ckd6QVpCZ05WQkFvTUVsQnlhWFpoZEdWbmNtbDBlU0JEYjNKd0xqRWZNQjBHQTFVRUF3d1djbVZuYVhOMGNtRjAKYVc5dUtpNWpiV2w0TG5KcGNEQWVGdzB4T1RBek1EVXlNVFE1TlRaYUZ3MHlPVEF6TURJeU1UUTVOVFphTUhReApDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbERiR0Z5ClpXMXZiblF4R3pBWkJnTlZCQW9NRWxCeWFYWmhkR1ZuY21sMGVTQkRiM0p3TGpFZk1CMEdBMVVFQXd3V2NtVm4KYVhOMGNtRjBhVzl1S2k1amJXbDRMbkpwY0RDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQwpnZ0VCQU9RS3ZxamRoMzVvK01FQ0JoQ3dvcEp6UGxRTm1xMmlQYmV3Uk50STAyYlVOSzNrTFFVYkZsWWR6TkdaClM0R1lYR2M1TytqZGk4U2x4ODJyMWtkano1UFBDTkZCQVJJc09QL0w4cjNER2VXK3llSmRnQlpqbTFzM3lsa2EKbXQ0QWppcS9iTmp5c1M2TC9XU09wK3NWdW1EeHRCRXpPL1VUVTFPNlFSbnpVcGhMYWlXRU5tRXJHdnNIMENaVgpxMzhJYTU4ay9RakNBenBVY1lpNGoybDFmYjA3eHFGY1FEOEg2U21VTTI5N1V5UW9zRHJwOHVrZElvMzFLb3hyCjRYRG5uTk5zWVN0QzI2dHpITWVLdUoyV2wrM1l6c1N5ZmxmTTJZRWNLRTMxc3FCOURTMzZVa0o4Sjg0ZUxzSE4KSW1HZzNXb2RGQXZpREI2NytqWERiQjMwTmtNQ0F3RUFBYU1sTUNNd0lRWURWUjBSQkJvd0dJSVdjbVZuYVhOMApjbUYwYVc5dUtpNWpiV2w0TG5KcGNEQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFGOW1OemsrZytvNjI2UmxsCnQzZjMvMXFJeVlRcllKMEJqU1dDS1lFRk1DZ1o0SmliQUpqQXZJYWpoVllFUnRsdGZmTStZS2NkRTJrVHBkekoKMFlKdVVuUmZ1djZzVm5YbFZWdWdVVW5kNElPaWdtamJDZE0zMmsxNzBDWU1tMGFpd0d4bDRGck5hOGVpN0FJYQp4L3MxbitzcVdxM0hlVzVMWGpub1ZiK3MzSGVDV0l1TGZjZ3J1cmZ5ZThGbk5oeTE0SEZ6eFZZWWVmSUttMFhMCitEUGxjR0dHbS9QUFl0M3U0YTIrclAzeGFpaGM2NWRUYTB1NXRmL1hQWHRQeFREUEZqMkplUURGeG83UVJSRWIKUEQ4OUN0WW53dVA5MzdDcmt2Q0tyTDBHa1cxRlZpWEtxWlk5RjV1aHhydkxJcHpoYk5ycy9FYnR3ZVkzNVhHTApEQ0NNa2c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANGRkZGRkZGRkZGRkZGRkZGQzkwRkRBQTIyMTY4QzIzNEM0QzY2MjhCODBEQzFDRDEyOTAyNEUwODhBNjdDQzc0MDIwQkJFQTYzQjEzOUIyMjUxNEEwODc5OEUzNDA0RERFRjk1MTlCM0NEM0E0MzFCMzAyQjBBNkRGMjVGMTQzNzRGRTEzNTZENkQ1MUMyNDVFNDg1QjU3NjYyNUU3RUM2RjQ0QzQyRTlBNjM3RUQ2QjBCRkY1Q0I2RjQwNkI3RURFRTM4NkJGQjVBODk5RkE1QUU5RjI0MTE3QzRCMUZFNjQ5Mjg2NjUxRUNFNDVCM0RDMjAwN0NCOEExNjNCRjA1OThEQTQ4MzYxQzU1RDM5QTY5MTYzRkE4RkQyNENGNUY4MzY1NUQyM0RDQTNBRDk2MUM2MkYzNTYyMDg1NTJCQjlFRDUyOTA3NzA5Njk2NkQ2NzBDMzU0RTRBQkM5ODA0RjE3NDZDMDhDQTE4MjE3QzMyOTA1RTQ2MkUzNkNFM0JFMzlFNzcyQzE4MEU4NjAzOUIyNzgzQTJFQzA3QTI4RkI1QzU1REYwNkY0QzUyQzlERTJCQ0JGNjk1NTgxNzE4Mzk5NTQ5N0NFQTk1NkFFNTE1RDIyNjE4OThGQTA1MTAxNTcyOEU1QThBQUNBQTY4RkZGRkZGRkZGRkZGRkZGRjAyN0ZGRkZGRkZGRkZGRkZGRkU0ODdFRDUxMTBCNDYxMUE2MjYzMzE0NUMwNkUwRTY4OTQ4MTI3MDQ0NTMzRTYzQTAxMDVERjUzMUQ4OUNEOTEyOEE1MDQzQ0M3MUEwMjZFRjdDQThDRDlFNjlEMjE4RDk4MTU4NTM2RjkyRjhBMUJBN0YwOUFCNkI2QThFMTIyRjI0MkRBQkIzMTJGM0Y2MzdBMjYyMTc0RDMxQkY2QjU4NUZGQUU1QjdBMDM1QkY2RjcxQzM1RkRBRDQ0Q0ZEMkQ3NEY5MjA4QkUyNThGRjMyNDk0MzMyOEY2NzIyRDlFRTEwMDNFNUM1MEIxREY4MkNDNkQyNDFCMEUyQUU5Q0QzNDhCMUZENDdFOTI2N0FGQzFCMkFFOTFFRTUxRDZDQjBFMzE3OUFCMTA0MkE5NURDRjZBOTQ4M0I4NEI0QjM2QjM4NjFBQTcyNTVFNEMwMjc4QkEzNjA0NjUwQzEwQkUxOTQ4MkYyMzE3MUI2NzFERjFDRjNCOTYwQzA3NDMwMUNEOTNDMUQxNzYwM0QxNDdEQUUyQUVGODM3QTYyOTY0RUYxNUU1RkI0QUFDMEI4QzFDQ0FBNEJFNzU0QUI1NzI4QUU5MTMwQzRDN0QwMjg4MEFCOTQ3MkQ0NTU2NTUzNDdGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGQzkwRkRBQTIyMTY4QzIzNEM0QzY2MjhCODBEQzFDRDEyOTAyNEUwODhBNjdDQzc0MDIwQkJFQTYzQjEzOUIyMjUxNEEwODc5OEUzNDA0RERFRjk1MTlCM0NEM0E0MzFCMzAyQjBBNkRGMjVGMTQzNzRGRTEzNTZENkQ1MUMyNDVFNDg1QjU3NjYyNUU3RUM2RjQ0QzQyRTlBNjM3RUQ2QjBCRkY1Q0I2RjQwNkI3RURFRTM4NkJGQjVBODk5RkE1QUU5RjI0MTE3QzRCMUZFNjQ5Mjg2NjUxRUNFNDVCM0RDMjAwN0NCOEExNjNCRjA1OThEQTQ4MzYxQzU1RDM5QTY5MTYzRkE4RkQyNENGNUY4MzY1NUQyM0RDQTNBRDk2MUM2MkYzNTYyMDg1NTJCQjlFRDUyOTA3NzA5Njk2NkQ2NzBDMzU0RTRBQkM5ODA0RjE3NDZDMDhDQTE4MjE3QzMyOTA1RTQ2MkUzNkNFM0JFMzlFNzcyQzE4MEU4NjAzOUIyNzgzQTJFQzA3QTI4RkI1QzU1REYwNkY0QzUyQzlERTJCQ0JGNjk1NTgxNzE4Mzk5NTQ5N0NFQTk1NkFFNTE1RDIyNjE4OThGQTA1MTAxNTcyOEU1QThBQUNBQTY4RkZGRkZGRkZGRkZGRkZGRjAyN0ZGRkZGRkZGRkZGRkZGRkU0ODdFRDUxMTBCNDYxMUE2MjYzMzE0NUMwNkUwRTY4OTQ4MTI3MDQ0NTMzRTYzQTAxMDVERjUzMUQ4OUNEOTEyOEE1MDQzQ0M3MUEwMjZFRjdDQThDRDlFNjlEMjE4RDk4MTU4NTM2RjkyRjhBMUJBN0YwOUFCNkI2QThFMTIyRjI0MkRBQkIzMTJGM0Y2MzdBMjYyMTc0RDMxQkY2QjU4NUZGQUU1QjdBMDM1QkY2RjcxQzM1RkRBRDQ0Q0ZEMkQ3NEY5MjA4QkUyNThGRjMyNDk0MzMyOEY2NzIyRDlFRTEwMDNFNUM1MEIxREY4MkNDNkQyNDFCMEUyQUU5Q0QzNDhCMUZENDdFOTI2N0FGQzFCMkFFOTFFRTUxRDZDQjBFMzE3OUFCMTA0MkE5NURDRjZBOTQ4M0I4NEI0QjM2QjM4NjFBQTcyNTVFNEMwMjc4QkEzNjA0NjUwQzEwQkUxOTQ4MkYyMzE3MUI2NzFERjFDRjNCOTYwQzA3NDMwMUNEOTNDMUQxNzYwM0QxNDdEQUUyQUVGODM3QTYyOTY0RUYxNUU1RkI0QUFDMEI4QzFDQ0FBNEJFNzU0QUI1NzI4QUU5MTMwQzRDN0QwMjg4MEFCOTQ3MkQ0NTU2NTUzNDdGRkZGRkZGRkZGRkZGRkY=")
SignatureBytes, _ = base64.StdEncoding.DecodeString(ExampleSignature)
E2eGrp = NDF.E2E.String()
CmixGrp = NDF.CMIX.String()
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment