feat(972): add --reuse-name flag to helm install

This will allow helm install to re-use names for releases that were
already deleted.
pull/997/head
Matt Butcher 8 years ago
parent bd5a9753a7
commit 9fe7f41364

@ -190,6 +190,9 @@ message InstallReleaseRequest {
// Namepace is the kubernetes namespace of the release. // Namepace is the kubernetes namespace of the release.
string namespace = 6; string namespace = 6;
// ReuseName requests that Tiller re-uses a name, instead of erroring out.
bool reuse_name = 7;
} }
// InstallReleaseResponse is the response from a release installation. // InstallReleaseResponse is the response from a release installation.

@ -59,6 +59,7 @@ type installCmd struct {
chartPath string chartPath string
dryRun bool dryRun bool
disableHooks bool disableHooks bool
reuseName bool
out io.Writer out io.Writer
client helm.Interface client helm.Interface
values *values values *values
@ -97,6 +98,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f.StringVar(&inst.namespace, "namespace", "default", "the namespace to install the release into") f.StringVar(&inst.namespace, "namespace", "default", "the namespace to install the release into")
f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install") f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install")
f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install") f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install")
f.BoolVar(&inst.reuseName, "reuse-name", false, "force Tiller to re-use the given name, even if that name is already used. This is unsafe in production")
f.Var(inst.values, "set", "set values on the command line. Separate values with commas: key1=val1,key2=val2") f.Var(inst.values, "set", "set values on the command line. Separate values with commas: key1=val1,key2=val2")
return cmd return cmd
} }
@ -111,7 +113,14 @@ func (i *installCmd) run() error {
return err return err
} }
res, err := i.client.InstallRelease(i.chartPath, i.namespace, helm.ValueOverrides(rawVals), helm.ReleaseName(i.name), helm.InstallDryRun(i.dryRun), helm.InstallDisableHooks(i.disableHooks)) res, err := i.client.InstallRelease(
i.chartPath,
i.namespace,
helm.ValueOverrides(rawVals),
helm.ReleaseName(i.name),
helm.InstallDryRun(i.dryRun),
helm.InstallReuseName(i.reuseName),
helm.InstallDisableHooks(i.disableHooks))
if err != nil { if err != nil {
return prettyError(err) return prettyError(err)
} }

@ -57,6 +57,14 @@ func TestInstall(t *testing.T) {
args: []string{}, args: []string{},
err: true, err: true,
}, },
// Install, re-use name
{
name: "install and reuse name",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas --reuse-name", " "),
expected: "aeneas",
resp: releaseMock(&releaseOptions{name: "aeneas"}),
},
} }
runReleaseCases(t, tests, func(c *fakeReleaseClient, out io.Writer) *cobra.Command { runReleaseCases(t, tests, func(c *fakeReleaseClient, out io.Writer) *cobra.Command {

@ -232,16 +232,20 @@ func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
return updatedRelease, nil return updatedRelease, nil
} }
func (s *releaseServer) uniqName(start string) (string, error) { func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
// If a name is supplied, we check to see if that name is taken. Right now, // If a name is supplied, we check to see if that name is taken. If not, it
// we fail if it is already taken. We could instead fall-thru and allow // is granted. If reuse is true and a deleted release with that name exists,
// an automatically generated name, but this seems to violate the principle // we re-grant it. Otherwise, an error is returned.
// of least surprise.
if start != "" { if start != "" {
if _, err := s.env.Releases.Read(start); err == storage.ErrNotFound { if rel, err := s.env.Releases.Read(start); err == storage.ErrNotFound {
return start, nil
} else if reuse && rel.Info.Status.Code == release.Status_DELETED {
// Allowe re-use of names if the previous release is marked deleted.
log.Printf("reusing name %q", start)
return start, nil return start, nil
} }
return "", fmt.Errorf("a release named %q already exists", start) return "", fmt.Errorf("a release named %q already exists", start)
} }
@ -290,7 +294,7 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
return nil, errMissingChart return nil, errMissingChart
} }
name, err := s.uniqName(req.Name) name, err := s.uniqName(req.Name, req.ReuseName)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -19,6 +19,7 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"regexp"
"strings" "strings"
"testing" "testing"
@ -95,6 +96,49 @@ func releaseStub() *release.Release {
} }
} }
func TestUniqName(t *testing.T) {
rs := rsFixture()
rel1 := releaseStub()
rel2 := releaseStub()
rel2.Name = "happy-panda"
rel2.Info.Status.Code = release.Status_DELETED
rs.env.Releases.Create(rel1)
rs.env.Releases.Create(rel2)
tests := []struct {
name string
expect string
reuse bool
err bool
}{
{"first", "first", false, false},
{"", "[a-z]+-[a-z]+", false, false},
{"angry-panda", "", false, true},
{"happy-panda", "", false, true},
{"happy-panda", "happy-panda", true, false},
}
for _, tt := range tests {
u, err := rs.uniqName(tt.name, tt.reuse)
if err != nil {
if tt.err {
continue
}
t.Fatal(err)
}
if tt.err {
t.Errorf("Expected an error for %q", tt.name)
}
if match, err := regexp.MatchString(tt.expect, u); err != nil {
t.Fatal(err)
} else if !match {
t.Errorf("Expected %q to match %q", u, tt.expect)
}
}
}
func TestInstallRelease(t *testing.T) { func TestInstallRelease(t *testing.T) {
c := context.Background() c := context.Background()
rs := rsFixture() rs := rsFixture()
@ -223,6 +267,28 @@ func TestInstallReleaseNoHooks(t *testing.T) {
} }
} }
func TestInstallReleaseReuseName(t *testing.T) {
c := context.Background()
rs := rsFixture()
rel := releaseStub()
rel.Info.Status.Code = release.Status_DELETED
rs.env.Releases.Create(rel)
req := &services.InstallReleaseRequest{
Chart: chartStub(),
ReuseName: true,
Name: rel.Name,
}
res, err := rs.InstallRelease(c, req)
if err != nil {
t.Errorf("Failed install: %s", err)
}
if res.Release.Name != rel.Name {
t.Errorf("expected %q, got %q", rel.Name, res.Release.Name)
}
}
func TestUninstallRelease(t *testing.T) { func TestUninstallRelease(t *testing.T) {
c := context.Background() c := context.Background()
rs := rsFixture() rs := rsFixture()

@ -37,6 +37,8 @@ type options struct {
chart string chart string
// if set dry-run helm client calls // if set dry-run helm client calls
dryRun bool dryRun bool
// if set, re-use an existing name
reuseName bool
// if set, skip running hooks // if set, skip running hooks
disableHooks bool disableHooks bool
// release list options are applied directly to the list releases request // release list options are applied directly to the list releases request
@ -162,6 +164,13 @@ func InstallDryRun(dry bool) InstallOption {
} }
} }
// InstallReuseName will (if true) instruct Tiller to re-use an existing name.
func InstallReuseName(reuse bool) InstallOption {
return func(opts *options) {
opts.reuseName = reuse
}
}
// ContentOption -- TODO // ContentOption -- TODO
type ContentOption func(*options) type ContentOption func(*options)
@ -205,6 +214,7 @@ func (o *options) rpcInstallRelease(chr *cpb.Chart, rlc rls.ReleaseServiceClient
o.instReq.Namespace = ns o.instReq.Namespace = ns
o.instReq.DryRun = o.dryRun o.instReq.DryRun = o.dryRun
o.instReq.DisableHooks = o.disableHooks o.instReq.DisableHooks = o.disableHooks
o.instReq.ReuseName = o.reuseName
return rlc.InstallRelease(context.TODO(), &o.instReq) return rlc.InstallRelease(context.TODO(), &o.instReq)
} }

@ -282,6 +282,8 @@ type InstallReleaseRequest struct {
DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"` DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
// Namepace is the kubernetes namespace of the release. // Namepace is the kubernetes namespace of the release.
Namespace string `protobuf:"bytes,6,opt,name=namespace" json:"namespace,omitempty"` Namespace string `protobuf:"bytes,6,opt,name=namespace" json:"namespace,omitempty"`
// ReuseName requests that Tiller re-uses a name, instead of erroring out.
ReuseName bool `protobuf:"varint,7,opt,name=reuse_name,json=reuseName" json:"reuse_name,omitempty"`
} }
func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} } func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} }
@ -622,51 +624,54 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
} }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 732 bytes of a gzipped FileDescriptorProto // 769 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x55, 0xdb, 0x6e, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0xdb, 0x6e, 0xd3, 0x4a,
0x10, 0xad, 0x9b, 0x34, 0x97, 0xe9, 0x45, 0xe9, 0x92, 0x26, 0xc1, 0x42, 0x08, 0x2d, 0x02, 0x4a, 0x14, 0xad, 0x93, 0xd4, 0x49, 0x76, 0x2f, 0x4a, 0xe7, 0xb4, 0x8d, 0x8f, 0x75, 0x0e, 0x42, 0x46,
0xa1, 0x0e, 0x84, 0x77, 0xa4, 0xb4, 0x8d, 0x4a, 0xd5, 0x90, 0x4a, 0x1b, 0x0a, 0x12, 0x0f, 0x44, 0x40, 0x29, 0xd4, 0x81, 0xf0, 0x8e, 0x94, 0xb6, 0x51, 0x5b, 0x35, 0xa4, 0xd2, 0x84, 0x82, 0xc4,
0x6e, 0xb2, 0xa1, 0x06, 0xd7, 0x0e, 0xde, 0x4d, 0x45, 0x3f, 0x81, 0x3f, 0xe2, 0x63, 0x78, 0xe4, 0x03, 0x91, 0x9b, 0x4c, 0xa8, 0xc1, 0xb5, 0x83, 0x67, 0x52, 0xd1, 0x4f, 0xe0, 0x0f, 0xf8, 0x14,
0x43, 0xd8, 0x8b, 0x6d, 0xe2, 0xc4, 0x86, 0xa8, 0x2f, 0xce, 0xee, 0xce, 0xd9, 0x39, 0xe3, 0x33, 0x3e, 0x88, 0xbf, 0xe0, 0x85, 0xb9, 0xd8, 0x26, 0x17, 0x1b, 0x4c, 0x5f, 0x9c, 0x99, 0xd9, 0x6b,
0x73, 0x1c, 0x30, 0x2f, 0xed, 0x89, 0xd3, 0x64, 0x34, 0xb8, 0x76, 0x86, 0x94, 0x35, 0xb9, 0xe3, 0xaf, 0x7d, 0xdf, 0x0a, 0x98, 0x97, 0xce, 0xd8, 0x6d, 0x50, 0x12, 0x5e, 0xbb, 0x03, 0x42, 0x1b,
0xba, 0x34, 0xb0, 0x26, 0x81, 0xcf, 0x7d, 0x54, 0x95, 0x31, 0x2b, 0x8a, 0x59, 0x3a, 0x66, 0xd6, 0xcc, 0xf5, 0x3c, 0x12, 0xda, 0xe3, 0x30, 0x60, 0x01, 0xda, 0x14, 0x32, 0x3b, 0x96, 0xd9, 0x4a,
0xd4, 0x8d, 0xe1, 0xa5, 0x1d, 0x70, 0xfd, 0xd4, 0x68, 0xb3, 0x3e, 0x7b, 0xee, 0x7b, 0x63, 0xe7, 0x66, 0x6e, 0x4b, 0x8d, 0xc1, 0xa5, 0x13, 0x32, 0xf5, 0x55, 0x68, 0xb3, 0x3e, 0xfd, 0x1e, 0xf8,
0x73, 0x18, 0xd0, 0x14, 0x01, 0x75, 0xa9, 0xcd, 0x68, 0xf4, 0x9b, 0xb8, 0x14, 0xc5, 0x1c, 0x6f, 0x23, 0xf7, 0x7d, 0x24, 0x50, 0x26, 0x42, 0xe2, 0x11, 0x87, 0x92, 0xf8, 0x77, 0x46, 0x29, 0x96,
0xec, 0xeb, 0x00, 0xfe, 0x6d, 0xc0, 0x9d, 0xae, 0xc3, 0x38, 0xd1, 0x21, 0x46, 0xe8, 0xb7, 0x29, 0xb9, 0xfe, 0x28, 0x50, 0x02, 0xeb, 0xbb, 0x06, 0xff, 0x74, 0x5c, 0xca, 0xb0, 0x12, 0x51, 0x4c,
0x65, 0x1c, 0x55, 0x61, 0xcd, 0x75, 0xae, 0x1c, 0xde, 0x30, 0x1e, 0x18, 0xbb, 0x39, 0xa2, 0x37, 0x3e, 0x4d, 0x08, 0x65, 0x68, 0x13, 0x96, 0x3d, 0xf7, 0xca, 0x65, 0x86, 0x76, 0x57, 0xdb, 0x29,
0xa8, 0x06, 0x05, 0x7f, 0x3c, 0x66, 0x94, 0x37, 0x56, 0xc5, 0x71, 0x99, 0x84, 0x3b, 0xf4, 0x1a, 0x62, 0x75, 0x41, 0xdb, 0xa0, 0x07, 0xa3, 0x11, 0x25, 0xcc, 0x28, 0xf0, 0xe7, 0x2a, 0x8e, 0x6e,
0x8a, 0xcc, 0x0f, 0xf8, 0xe0, 0xe2, 0xa6, 0x91, 0x13, 0x81, 0xad, 0xd6, 0x23, 0x2b, 0xed, 0x9d, 0xe8, 0x05, 0x94, 0x69, 0x10, 0xb2, 0xfe, 0xc5, 0x8d, 0x51, 0xe4, 0x82, 0xf5, 0xe6, 0x7d, 0x3b,
0x2c, 0xc9, 0xd4, 0x17, 0x40, 0x4b, 0x3e, 0x0e, 0x6e, 0x48, 0x81, 0xa9, 0x5f, 0x99, 0x77, 0xec, 0x2d, 0x26, 0x5b, 0x58, 0xea, 0x71, 0xa0, 0x2d, 0x3e, 0xfb, 0x37, 0x58, 0xa7, 0xf2, 0x57, 0xf0,
0xb8, 0x9c, 0x06, 0x8d, 0xbc, 0xce, 0xab, 0x77, 0xe8, 0x18, 0x40, 0xe5, 0xf5, 0x83, 0x91, 0x88, 0x8e, 0x5c, 0x8f, 0x91, 0xd0, 0x28, 0x29, 0x5e, 0x75, 0x43, 0x47, 0x00, 0x92, 0x37, 0x08, 0x87,
0xad, 0xa9, 0xd4, 0xbb, 0x4b, 0xa4, 0x3e, 0x93, 0x78, 0x52, 0x66, 0xd1, 0x12, 0x7f, 0x82, 0x52, 0x5c, 0xb6, 0x2c, 0xa9, 0x77, 0x72, 0x50, 0x9f, 0x09, 0x3c, 0xae, 0xd2, 0xf8, 0x68, 0xbd, 0x83,
0x04, 0xc0, 0x2d, 0x28, 0x68, 0x7a, 0xb4, 0x0e, 0xc5, 0xf3, 0xde, 0x69, 0xef, 0xec, 0x43, 0xaf, 0x4a, 0x0c, 0xb0, 0x9a, 0xa0, 0x2b, 0xf3, 0x68, 0x05, 0xca, 0xe7, 0xdd, 0xd3, 0xee, 0xd9, 0x9b,
0xb2, 0x82, 0x4a, 0x90, 0xef, 0xb5, 0xdf, 0x76, 0x2a, 0x06, 0xda, 0x86, 0xcd, 0x6e, 0xbb, 0xff, 0x6e, 0x6d, 0x09, 0x55, 0xa0, 0xd4, 0x6d, 0xbd, 0x6c, 0xd7, 0x34, 0xb4, 0x01, 0x6b, 0x9d, 0x56,
0x6e, 0x40, 0x3a, 0xdd, 0x4e, 0xbb, 0xdf, 0x39, 0xaa, 0xac, 0xe2, 0xfb, 0x50, 0x8e, 0xf3, 0xa2, 0xef, 0x55, 0x1f, 0xb7, 0x3b, 0xed, 0x56, 0xaf, 0x7d, 0x58, 0x2b, 0x58, 0x77, 0xa0, 0x9a, 0xf0,
0x22, 0xe4, 0xda, 0xfd, 0x43, 0x7d, 0xe5, 0xa8, 0x23, 0x56, 0x06, 0xfe, 0x61, 0x40, 0x35, 0x29, 0xa2, 0x32, 0x14, 0x5b, 0xbd, 0x03, 0xa5, 0x72, 0xd8, 0xe6, 0x27, 0xcd, 0xfa, 0xa2, 0xc1, 0xe6,
0x23, 0x9b, 0xf8, 0x1e, 0xa3, 0x52, 0xc7, 0xa1, 0x3f, 0xf5, 0x62, 0x1d, 0xd5, 0x06, 0x21, 0xc8, 0x6c, 0x1a, 0xe9, 0x38, 0xf0, 0x29, 0x11, 0x79, 0x1c, 0x04, 0x13, 0x3f, 0xc9, 0xa3, 0xbc, 0x20,
0x7b, 0xf4, 0x7b, 0xa4, 0xa2, 0x5a, 0x4b, 0x24, 0xf7, 0xb9, 0xed, 0x2a, 0x05, 0x05, 0x52, 0x6d, 0x04, 0x25, 0x9f, 0x7c, 0x8e, 0xb3, 0x28, 0xcf, 0x02, 0xc9, 0x02, 0xe6, 0x78, 0x32, 0x83, 0x1c,
0xd0, 0x4b, 0x28, 0x85, 0x5d, 0x63, 0x42, 0x9b, 0xdc, 0xee, 0x7a, 0x6b, 0x47, 0xbf, 0x7f, 0xd4, 0x29, 0x2f, 0xe8, 0x19, 0x54, 0xa2, 0xaa, 0x51, 0x9e, 0x9b, 0xe2, 0xce, 0x4a, 0x73, 0x4b, 0xc5,
0xdf, 0x90, 0x91, 0xc4, 0x30, 0xbc, 0x0f, 0xf5, 0x63, 0x1a, 0x55, 0xd2, 0xe7, 0x36, 0x9f, 0xc6, 0x1f, 0xd7, 0x37, 0xb2, 0x88, 0x13, 0x98, 0xb5, 0x07, 0xf5, 0x23, 0x12, 0x7b, 0xd2, 0x63, 0x0e,
0x5d, 0x95, 0xbc, 0xf6, 0x15, 0x55, 0xc5, 0x48, 0x5e, 0xb1, 0xc6, 0xef, 0xa1, 0xb1, 0x08, 0x0f, 0x9b, 0x24, 0x55, 0x15, 0x76, 0x9d, 0x2b, 0x22, 0x9d, 0x11, 0x76, 0xf9, 0xd9, 0x7a, 0x0d, 0xc6,
0xab, 0x4f, 0xc1, 0xa3, 0xc7, 0x90, 0x97, 0xf3, 0xa3, 0x6a, 0x5f, 0x6f, 0xa1, 0x64, 0x35, 0x27, 0x22, 0x3c, 0xf2, 0x3e, 0x05, 0x8f, 0x1e, 0x40, 0x49, 0xf4, 0x8f, 0xf4, 0x7d, 0xa5, 0x89, 0x66,
0x22, 0x42, 0x54, 0x1c, 0x5b, 0xb3, 0x79, 0x0f, 0x7d, 0x8f, 0x53, 0x8f, 0xff, 0xab, 0x8e, 0x2e, 0xbd, 0x39, 0xe1, 0x12, 0x2c, 0xe5, 0x96, 0x3d, 0xcd, 0x7b, 0x10, 0xf8, 0x8c, 0xf8, 0xec, 0x77,
0xdc, 0x4d, 0xc1, 0x87, 0x85, 0x34, 0xa1, 0x18, 0x52, 0xa8, 0x3b, 0x99, 0x2a, 0x44, 0x28, 0x5c, 0x7e, 0x74, 0xe0, 0xdf, 0x14, 0x7c, 0xe4, 0x48, 0x03, 0xca, 0x91, 0x09, 0xa9, 0x93, 0x99, 0x85,
0x83, 0xea, 0xf9, 0x64, 0x64, 0x73, 0x1a, 0x45, 0x34, 0x33, 0xae, 0xc3, 0xce, 0xdc, 0xb9, 0x66, 0x18, 0x65, 0x7d, 0xe5, 0x05, 0x39, 0x1f, 0x0f, 0x1d, 0x46, 0x62, 0x51, 0xb6, 0x69, 0xf4, 0x90,
0xc0, 0xbf, 0x0c, 0xd8, 0x39, 0xf1, 0x98, 0xd0, 0xdc, 0x4d, 0x5e, 0x41, 0x4f, 0x44, 0x0b, 0xa5, 0x17, 0x49, 0xcc, 0x53, 0x14, 0xd3, 0x86, 0xe2, 0x56, 0x43, 0x77, 0x20, 0xbe, 0x58, 0xc9, 0xd1,
0xdb, 0x42, 0xe6, 0x6d, 0xcd, 0xac, 0x2d, 0x79, 0x28, 0x9f, 0x44, 0xc7, 0xd1, 0x1e, 0x14, 0xae, 0x2e, 0xe8, 0xd7, 0x8e, 0xc7, 0x79, 0x64, 0x91, 0x92, 0xe8, 0x23, 0xa4, 0x1c, 0x46, 0x1c, 0x21,
0x6d, 0x57, 0xdc, 0x49, 0x6a, 0x13, 0x22, 0x95, 0x55, 0x49, 0x88, 0x40, 0x75, 0x28, 0x8e, 0x82, 0x50, 0x1d, 0xca, 0xc3, 0xf0, 0xa6, 0x1f, 0x4e, 0x7c, 0xd9, 0xd4, 0x15, 0xac, 0xf3, 0x2b, 0x9e,
0x9b, 0x41, 0x30, 0xf5, 0x54, 0xbf, 0x4b, 0xa4, 0x20, 0xb6, 0x64, 0xea, 0xc5, 0xd2, 0xe4, 0x67, 0xf8, 0xd6, 0x31, 0x6c, 0xcd, 0x79, 0x76, 0xdb, 0x20, 0x7f, 0x68, 0xb0, 0x75, 0xe2, 0x53, 0xde,
0x24, 0x7f, 0x08, 0x9b, 0x23, 0x87, 0xd9, 0x17, 0x2e, 0x1d, 0x5c, 0xfa, 0xfe, 0x57, 0xa6, 0x9c, 0x27, 0xde, 0x5c, 0x94, 0x49, 0x44, 0x5a, 0xee, 0x88, 0x0a, 0x7f, 0x13, 0x51, 0x71, 0x3a, 0xa2,
0x50, 0x22, 0x1b, 0xe1, 0xe1, 0x1b, 0x79, 0x86, 0xee, 0x41, 0x59, 0x82, 0xd9, 0xc4, 0x1e, 0xd2, 0x24, 0xa7, 0xa5, 0xa9, 0x9c, 0xde, 0x83, 0xb5, 0xa1, 0x4b, 0x9d, 0x0b, 0x8f, 0xf4, 0x2f, 0x83,
0x46, 0x41, 0xdd, 0xfe, 0x7b, 0x80, 0x4f, 0xa0, 0x36, 0xff, 0x76, 0xb7, 0x95, 0x96, 0x40, 0xfd, 0xe0, 0x23, 0x95, 0xd3, 0x5b, 0xc1, 0xab, 0xd1, 0xe3, 0xb1, 0x78, 0x43, 0xff, 0x41, 0x55, 0x80,
0xdc, 0x73, 0x52, 0xa5, 0x4a, 0x9b, 0x97, 0x85, 0xe2, 0x57, 0x17, 0x8b, 0xc7, 0xa7, 0xd0, 0x58, 0xe9, 0xd8, 0x19, 0x10, 0x43, 0x97, 0xda, 0xbf, 0x1e, 0xd0, 0xff, 0x00, 0x21, 0x99, 0x50, 0xd2,
0xcc, 0x79, 0xcb, 0x02, 0x5b, 0x3f, 0xd7, 0x60, 0x2b, 0x9a, 0x67, 0xfd, 0x95, 0x40, 0x0e, 0x6c, 0x97, 0xe4, 0x65, 0xa9, 0x5f, 0x95, 0x2f, 0x5d, 0xd1, 0x30, 0x27, 0xb0, 0x3d, 0x1f, 0xfc, 0x6d,
0xcc, 0xda, 0x13, 0x3d, 0xcd, 0xfe, 0x88, 0xcc, 0x7d, 0x09, 0xcd, 0xbd, 0x65, 0xa0, 0xe1, 0x10, 0x13, 0x89, 0xa1, 0x7e, 0xee, 0xbb, 0xa9, 0x99, 0x4c, 0xeb, 0x97, 0x85, 0xd8, 0x0a, 0x8b, 0xb1,
0xad, 0xbc, 0x30, 0x10, 0x83, 0xca, 0xbc, 0x9f, 0xd0, 0x7e, 0x7a, 0x8e, 0x0c, 0x9b, 0x9a, 0xd6, 0x59, 0xa7, 0x60, 0x2c, 0x72, 0xde, 0xd2, 0xc1, 0xe6, 0xb7, 0x65, 0x58, 0x8f, 0x47, 0x54, 0x2d,
0xb2, 0xf0, 0x88, 0x16, 0x5d, 0xc3, 0xf6, 0x82, 0x79, 0xd0, 0x7f, 0xd3, 0x24, 0x5d, 0x69, 0x36, 0x3e, 0xe4, 0xc2, 0xea, 0xf4, 0xc6, 0x41, 0x8f, 0xb2, 0xf7, 0xe2, 0xdc, 0x72, 0x37, 0x77, 0xf3,
0x97, 0xc6, 0xc7, 0xbc, 0x5f, 0x60, 0x33, 0x61, 0x27, 0x94, 0xa1, 0x56, 0x9a, 0x17, 0xcd, 0x67, 0x40, 0x95, 0xab, 0xd6, 0xd2, 0x53, 0x0d, 0x51, 0xa8, 0xcd, 0xaf, 0x08, 0xb4, 0x97, 0xce, 0x91,
0x4b, 0x61, 0x63, 0xae, 0x2b, 0xd8, 0x4a, 0x8e, 0x30, 0xca, 0x48, 0x90, 0x6a, 0x63, 0xf3, 0xf9, 0xb1, 0x79, 0x4c, 0x3b, 0x2f, 0x3c, 0x36, 0x8b, 0xae, 0x61, 0x63, 0x61, 0x1f, 0xa0, 0x3f, 0xd2,
0x72, 0xe0, 0x98, 0x4e, 0xf4, 0x71, 0x7e, 0x24, 0xb3, 0xfa, 0x98, 0x61, 0x87, 0xac, 0x3e, 0x66, 0xcc, 0x2e, 0x1a, 0xb3, 0x91, 0x1b, 0x9f, 0xd8, 0xfd, 0x00, 0x6b, 0x33, 0xe3, 0x89, 0x32, 0xb2,
0x4d, 0x3a, 0x5e, 0x39, 0x80, 0x8f, 0xa5, 0x08, 0x7d, 0x51, 0x50, 0xff, 0xd0, 0xaf, 0xfe, 0x04, 0x95, 0xb6, 0x5d, 0xcc, 0xc7, 0xb9, 0xb0, 0x89, 0xad, 0x2b, 0x58, 0x9f, 0x6d, 0x61, 0x94, 0x41,
0x00, 0x00, 0xff, 0xff, 0x90, 0x99, 0xf0, 0xc6, 0x3b, 0x08, 0x00, 0x00, 0x90, 0x3a, 0xe5, 0xe6, 0x93, 0x7c, 0xe0, 0xc4, 0x1c, 0xaf, 0xe3, 0x7c, 0x4b, 0x66, 0xd5, 0x31,
0x63, 0x1c, 0xb2, 0xea, 0x98, 0xd5, 0xe9, 0xd6, 0xd2, 0x3e, 0xbc, 0xad, 0xc4, 0xe8, 0x0b, 0x5d,
0xfe, 0xe9, 0x78, 0xfe, 0x33, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x56, 0x6f, 0xa5, 0x0e, 0x09, 0x00,
0x00,
} }

Loading…
Cancel
Save