From 66c103e2e9caf1f9517c811c52f12498c63728ed Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 3 Oct 2020 11:22:20 +0200 Subject: [PATCH 01/10] Initial encryption support --- cmd/internal/backup/providers/gcp/gcp.go | 36 +++- cmd/internal/backup/providers/local/local.go | 29 +++- cmd/internal/backup/providers/s3/s3.go | 41 +++-- cmd/internal/encryption/encryption.go | 166 +++++++++++++++++++ cmd/main.go | 16 ++ 5 files changed, 266 insertions(+), 22 deletions(-) create mode 100644 cmd/internal/encryption/encryption.go diff --git a/cmd/internal/backup/providers/gcp/gcp.go b/cmd/internal/backup/providers/gcp/gcp.go index f6458cb..0fb00a9 100644 --- a/cmd/internal/backup/providers/gcp/gcp.go +++ b/cmd/internal/backup/providers/gcp/gcp.go @@ -13,6 +13,8 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils" "go.uber.org/zap" "google.golang.org/api/iterator" @@ -26,9 +28,10 @@ const ( // BackupProviderGCP implements the backup provider interface for GCP type BackupProviderGCP struct { - log *zap.SugaredLogger - c *storage.Client - config *BackupProviderConfigGCP + log *zap.SugaredLogger + c *storage.Client + config *BackupProviderConfigGCP + encrypter *encryption.Encrypter } // BackupProviderConfigGCP provides configuration for the BackupProviderGCP @@ -53,7 +56,7 @@ func (c *BackupProviderConfigGCP) validate() error { } // New returns a GCP backup provider -func New(log *zap.SugaredLogger, config *BackupProviderConfigGCP) (*BackupProviderGCP, error) { +func New(log *zap.SugaredLogger, config *BackupProviderConfigGCP, encrypter *encryption.Encrypter) (*BackupProviderGCP, error) { ctx := context.Background() if config == nil { @@ -78,9 +81,10 @@ func New(log *zap.SugaredLogger, config *BackupProviderConfigGCP) (*BackupProvid } return &BackupProviderGCP{ - c: client, - config: config, - log: log, + c: client, + config: config, + log: log, + encrypter: encrypter, }, nil } @@ -163,6 +167,17 @@ func (b *BackupProviderGCP) DownloadBackup(version *providers.BackupVersion) err return errors.Wrap(err, "error writing file from gcp to filesystem") } + if b.encrypter != nil { + destination, err := b.encrypter.Decrypt(backupFilePath) + if err != nil { + return errors.Wrap(err, "unable to decrypt backup") + } + err = utils.Copy(destination, backupFilePath) + if err != nil { + return errors.Wrap(err, "error writing decrypted file") + } + } + return nil } @@ -182,6 +197,13 @@ func (b *BackupProviderGCP) UploadBackup(sourcePath string) error { destination = b.config.ObjectPrefix + "/" + destination } + if b.encrypter != nil { + destination, err = b.encrypter.Encrypt(destination) + if err != nil { + return errors.Wrap(err, "unable to encrypt backup") + } + } + b.log.Debugw("uploading object", "src", sourcePath, "dest", destination) obj := bucket.Object(destination) diff --git a/cmd/internal/backup/providers/local/local.go b/cmd/internal/backup/providers/local/local.go index 4b0e987..b686067 100644 --- a/cmd/internal/backup/providers/local/local.go +++ b/cmd/internal/backup/providers/local/local.go @@ -1,12 +1,14 @@ package local import ( + "fmt" "os" "path/filepath" "strconv" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils" "github.com/pkg/errors" @@ -22,6 +24,7 @@ type BackupProviderLocal struct { log *zap.SugaredLogger config *BackupProviderConfigLocal nextBackupCount int64 + encrypter *encryption.Encrypter } // BackupProviderConfigLocal provides configuration for the BackupProviderLocal @@ -35,7 +38,7 @@ func (c *BackupProviderConfigLocal) validate() error { } // New returns a Local backup provider -func New(log *zap.SugaredLogger, config *BackupProviderConfigLocal) (*BackupProviderLocal, error) { +func New(log *zap.SugaredLogger, config *BackupProviderConfigLocal, encrypter *encryption.Encrypter) (*BackupProviderLocal, error) { if config == nil { return nil, errors.New("local backup provider requires a provider config") } @@ -53,8 +56,9 @@ func New(log *zap.SugaredLogger, config *BackupProviderConfigLocal) (*BackupProv } return &BackupProviderLocal{ - config: config, - log: log, + config: config, + log: log, + encrypter: encrypter, }, nil } @@ -82,7 +86,15 @@ func (b *BackupProviderLocal) DownloadBackup(version *providers.BackupVersion) e b.log.Infow("download backup called for provider local") source := filepath.Join(b.config.LocalBackupPath, version.Name) destination := filepath.Join(constants.DownloadDir, version.Name) - err := utils.Copy(source, destination) + + var err error + if b.encrypter != nil { + destination, err = b.encrypter.Decrypt(source) + if err != nil { + return fmt.Errorf("unable to decrypt backup:%v", err) + } + } + err = utils.Copy(source, destination) if err != nil { return err } @@ -93,7 +105,14 @@ func (b *BackupProviderLocal) DownloadBackup(version *providers.BackupVersion) e func (b *BackupProviderLocal) UploadBackup(sourcePath string) error { b.log.Infow("upload backups called for provider local") destination := filepath.Join(b.config.LocalBackupPath, filepath.Base(sourcePath)) - err := utils.Copy(sourcePath, destination) + var err error + if b.encrypter != nil { + destination, err = b.encrypter.Encrypt(sourcePath) + if err != nil { + return fmt.Errorf("unable to encrypt backup:%v", err) + } + } + err = utils.Copy(sourcePath, destination) if err != nil { return err } diff --git a/cmd/internal/backup/providers/s3/s3.go b/cmd/internal/backup/providers/s3/s3.go index 423d29e..252ce83 100644 --- a/cmd/internal/backup/providers/s3/s3.go +++ b/cmd/internal/backup/providers/s3/s3.go @@ -10,6 +10,8 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils" "go.uber.org/zap" @@ -27,10 +29,11 @@ const ( // BackupProviderS3 implements the backup provider interface for S3 type BackupProviderS3 struct { - log *zap.SugaredLogger - c *s3.S3 - sess *session.Session - config *BackupProviderConfigS3 + log *zap.SugaredLogger + c *s3.S3 + sess *session.Session + config *BackupProviderConfigS3 + encrypter *encryption.Encrypter } // BackupProviderConfigS3 provides configuration for the BackupProviderS3 @@ -63,7 +66,7 @@ func (c *BackupProviderConfigS3) validate() error { } // New returns a S3 backup provider -func New(log *zap.SugaredLogger, config *BackupProviderConfigS3) (*BackupProviderS3, error) { +func New(log *zap.SugaredLogger, config *BackupProviderConfigS3, encrypter *encryption.Encrypter) (*BackupProviderS3, error) { if config == nil { return nil, errors.New("s3 backup provider requires a provider config") @@ -96,10 +99,11 @@ func New(log *zap.SugaredLogger, config *BackupProviderConfigS3) (*BackupProvide } return &BackupProviderS3{ - c: client, - sess: newSession, - config: config, - log: log, + c: client, + sess: newSession, + config: config, + log: log, + encrypter: encrypter, }, nil } @@ -208,6 +212,17 @@ func (b *BackupProviderS3) DownloadBackup(version *providers.BackupVersion) erro return err } + if b.encrypter != nil { + destination, err := b.encrypter.Decrypt(backupFilePath) + if err != nil { + return errors.Wrap(err, "unable to decrypt backup") + } + err = utils.Copy(destination, backupFilePath) + if err != nil { + return errors.Wrap(err, "error writing decrypted file") + } + } + return nil } @@ -226,6 +241,13 @@ func (b *BackupProviderS3) UploadBackup(sourcePath string) error { destination = b.config.ObjectPrefix + "/" + destination } + if b.encrypter != nil { + destination, err = b.encrypter.Encrypt(destination) + if err != nil { + return errors.Wrap(err, "unable to encrypt backup") + } + } + b.log.Debugw("uploading object", "src", sourcePath, "dest", destination) uploader := s3manager.NewUploader(b.sess) @@ -237,7 +259,6 @@ func (b *BackupProviderS3) UploadBackup(sourcePath string) error { if err != nil { return err } - return nil } diff --git a/cmd/internal/encryption/encryption.go b/cmd/internal/encryption/encryption.go new file mode 100644 index 0000000..5a0facc --- /dev/null +++ b/cmd/internal/encryption/encryption.go @@ -0,0 +1,166 @@ +package encryption + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "go.uber.org/zap" +) + +// Suffix is appended on encryption and removed on decryption from given input +const Suffix = ".aes" + +// Encrypter is used to encrypt/decrypt backups +type Encrypter struct { + key string + log *zap.SugaredLogger +} + +// New creates a new Encrypter with the given key. +// The key should be 16 bytes (AES-128), 24 bytes (AES-192) or +// 32 bytes (AES-256) +func New(log *zap.SugaredLogger, key string) (*Encrypter, error) { + switch len(key) { + case 16, 24, 32: + default: + return nil, fmt.Errorf("key length:%d invalid, must be 16,24 or 32 bytes", len(key)) + } + + return &Encrypter{ + key: key, + log: log, + }, nil +} + +// Encrypt input file with key and store the encrypted files with suffix appended +func (e *Encrypter) Encrypt(input string) (string, error) { + infile, err := os.Open(input) + if err != nil { + return "", err + } + defer infile.Close() + + key := []byte(e.key) + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + // Never use more than 2^32 random nonces with a given key + // because of the risk of repeat. + iv := make([]byte, block.BlockSize()) + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "", err + } + + output := input + Suffix + outfile, err := os.OpenFile(output, os.O_RDWR|os.O_CREATE, 0777) + if err != nil { + return "", err + } + defer outfile.Close() + + // The buffer size must be multiple of 16 bytes + buf := make([]byte, 1024) + stream := cipher.NewCTR(block, iv) + for { + n, err := infile.Read(buf) + if n > 0 { + stream.XORKeyStream(buf, buf[:n]) + // Write into file + _, err = outfile.Write(buf[:n]) + if err != nil { + return "", err + } + } + + if err == io.EOF { + break + } + + if err != nil { + e.log.Infof("Read %d bytes: %v", n, err) + break + } + } + // Append the IV + _, err = outfile.Write(iv) + return output, err +} + +// Decrypt input file with key and store decrypted result with suffix removed +// if input does not end with suffix, it is assumed that the file was not encrypted. +func (e *Encrypter) Decrypt(input string) (string, error) { + extension := filepath.Ext(input) + if extension != Suffix { + return input, fmt.Errorf("input is not encrypted") + } + infile, err := os.Open(input) + if err != nil { + return "", err + } + defer infile.Close() + + key := []byte(e.key) + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + // Never use more than 2^32 random nonces with a given key + // because of the risk of repeat. + fi, err := infile.Stat() + if err != nil { + return "", err + } + + iv := make([]byte, block.BlockSize()) + msgLen := fi.Size() - int64(len(iv)) + _, err = infile.ReadAt(iv, msgLen) + if err != nil { + return "", err + } + + output := strings.TrimSuffix(input, Suffix) + outfile, err := os.OpenFile(output, os.O_RDWR|os.O_CREATE, 0777) + if err != nil { + return "", err + } + defer outfile.Close() + + // The buffer size must be multiple of 16 bytes + buf := make([]byte, 1024) + stream := cipher.NewCTR(block, iv) + for { + n, err := infile.Read(buf) + if n > 0 { + // The last bytes are the IV, don't belong the original message + if n > int(msgLen) { + n = int(msgLen) + } + msgLen -= int64(n) + stream.XORKeyStream(buf, buf[:n]) + // Write into file + _, err = outfile.Write(buf[:n]) + if err != nil { + return "", err + } + } + + if err == io.EOF { + break + } + + if err != nil { + e.log.Infof("Read %d bytes: %v", n, err) + break + } + } + return output, nil +} diff --git a/cmd/main.go b/cmd/main.go index dcabda1..e4c325e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,6 +17,7 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/database" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/database/postgres" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/database/rethinkdb" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/initializer" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/metrics" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/probe" @@ -71,6 +72,8 @@ const ( s3SecretKeyFlg = "s3-secret-key" compressionMethod = "compression-method" + + encryptionKey = "encryption-key" ) var ( @@ -226,6 +229,8 @@ func init() { startCmd.Flags().StringP(compressionMethod, "", "targz", "the compression method to use to compress the backups (tar|targz|tarlz4)") + startCmd.Flags().StringP(encryptionKey, "", "", "if given backups will be encrypted with key, must be either 16,24 or 32 byte long") + err = viper.BindPFlags(startCmd.Flags()) if err != nil { fmt.Printf("unable to construct initializer command: %v", err) @@ -332,7 +337,15 @@ func initDatabase() error { func initBackupProvider() error { bpString := viper.GetString(backupProviderFlg) + key := viper.GetString(encryptionKey) + var encrypter *encryption.Encrypter var err error + if key != "" { + encrypter, err = encryption.New(logger.Named("encryption"), key) + if err != nil { + return fmt.Errorf("unable to initialize encryption:%v", err) + } + } switch bpString { case "gcp": bp, err = gcp.New( @@ -344,6 +357,7 @@ func initBackupProvider() error { BucketName: viper.GetString(gcpBucketNameFlg), BucketLocation: viper.GetString(gcpBucketLocationFlg), }, + encrypter, ) case "s3": bp, err = s3.New( @@ -357,6 +371,7 @@ func initBackupProvider() error { AccessKey: viper.GetString(s3AccessKeyFlg), SecretKey: viper.GetString(s3SecretKeyFlg), }, + encrypter, ) case "local": bp, err = local.New( @@ -365,6 +380,7 @@ func initBackupProvider() error { LocalBackupPath: viper.GetString(localBackupPathFlg), ObjectsToKeep: viper.GetInt64(objectsToKeepFlg), }, + encrypter, ) default: return fmt.Errorf("unsupported backup provider type: %s", bpString) From 30af0d5b010d7def4f53bc5a0434a3c6e5090742 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 3 Oct 2020 11:28:34 +0200 Subject: [PATCH 02/10] Small readme addition --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ac85c60..8a57aa6 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,12 @@ With `--compression-method` you can define how generated backups are compressed - S3 Buckets (tested against Ceph RADOS gateway) - Local +## Encryption + +For all three storage providers are AES encryption is supported, can be enabled with `--encryption-key=`. +The key must be either 16 bytes (AES-128), 24 bytes (AES-192) or 32 bytes (AES-256) long. +The backups are stored at the storage provider with the `.aes` suffix. If the file does not have this suffix, decryption is skipped. + ## How it works ![Sequence Diagram](docs/sequence.png) From d25422c3eaee5b944fdcf2d9adcf2ed5cd1aa05f Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 3 Oct 2020 12:46:57 +0200 Subject: [PATCH 03/10] Generally enable encryption instead per storage --- cmd/internal/backup/backup.go | 12 +++++- cmd/internal/backup/providers/gcp/gcp.go | 37 ++++-------------- cmd/internal/backup/providers/local/local.go | 28 +++---------- cmd/internal/backup/providers/s3/s3.go | 41 +++++--------------- cmd/internal/initializer/initializer.go | 22 ++++++++--- cmd/main.go | 33 +++++++++------- 6 files changed, 67 insertions(+), 106 deletions(-) diff --git a/cmd/internal/backup/backup.go b/cmd/internal/backup/backup.go index 94bbc9f..72ddb24 100644 --- a/cmd/internal/backup/backup.go +++ b/cmd/internal/backup/backup.go @@ -8,13 +8,14 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/compress" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/database" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/metrics" cron "github.com/robfig/cron/v3" "go.uber.org/zap" ) // Start starts the backup component, which is periodically taking backups of the database -func Start(log *zap.SugaredLogger, backupSchedule string, db database.DatabaseProber, bp backuproviders.BackupProvider, metrics *metrics.Metrics, comp *compress.Compressor, stop <-chan struct{}) error { +func Start(log *zap.SugaredLogger, backupSchedule string, db database.DatabaseProber, bp backuproviders.BackupProvider, metrics *metrics.Metrics, comp *compress.Compressor, encrypter *encryption.Encrypter, stop <-chan struct{}) error { log.Info("database is now available, starting periodic backups") c := cron.New() @@ -45,6 +46,15 @@ func Start(log *zap.SugaredLogger, backupSchedule string, db database.DatabasePr } log.Info("compressed backup") + if encrypter != nil { + filename, err = encrypter.Encrypt(filename) + if err != nil { + metrics.CountError("compress") + log.Errorw("unable to encrypt backup", "error", err) + return + } + } + err = bp.UploadBackup(filename) if err != nil { metrics.CountError("upload") diff --git a/cmd/internal/backup/providers/gcp/gcp.go b/cmd/internal/backup/providers/gcp/gcp.go index 0fb00a9..6c9f593 100644 --- a/cmd/internal/backup/providers/gcp/gcp.go +++ b/cmd/internal/backup/providers/gcp/gcp.go @@ -13,8 +13,6 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" - "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" - "github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils" "go.uber.org/zap" "google.golang.org/api/iterator" @@ -28,10 +26,9 @@ const ( // BackupProviderGCP implements the backup provider interface for GCP type BackupProviderGCP struct { - log *zap.SugaredLogger - c *storage.Client - config *BackupProviderConfigGCP - encrypter *encryption.Encrypter + log *zap.SugaredLogger + c *storage.Client + config *BackupProviderConfigGCP } // BackupProviderConfigGCP provides configuration for the BackupProviderGCP @@ -56,7 +53,7 @@ func (c *BackupProviderConfigGCP) validate() error { } // New returns a GCP backup provider -func New(log *zap.SugaredLogger, config *BackupProviderConfigGCP, encrypter *encryption.Encrypter) (*BackupProviderGCP, error) { +func New(log *zap.SugaredLogger, config *BackupProviderConfigGCP) (*BackupProviderGCP, error) { ctx := context.Background() if config == nil { @@ -81,10 +78,9 @@ func New(log *zap.SugaredLogger, config *BackupProviderConfigGCP, encrypter *enc } return &BackupProviderGCP{ - c: client, - config: config, - log: log, - encrypter: encrypter, + c: client, + config: config, + log: log, }, nil } @@ -166,18 +162,6 @@ func (b *BackupProviderGCP) DownloadBackup(version *providers.BackupVersion) err if err != nil { return errors.Wrap(err, "error writing file from gcp to filesystem") } - - if b.encrypter != nil { - destination, err := b.encrypter.Decrypt(backupFilePath) - if err != nil { - return errors.Wrap(err, "unable to decrypt backup") - } - err = utils.Copy(destination, backupFilePath) - if err != nil { - return errors.Wrap(err, "error writing decrypted file") - } - } - return nil } @@ -197,13 +181,6 @@ func (b *BackupProviderGCP) UploadBackup(sourcePath string) error { destination = b.config.ObjectPrefix + "/" + destination } - if b.encrypter != nil { - destination, err = b.encrypter.Encrypt(destination) - if err != nil { - return errors.Wrap(err, "unable to encrypt backup") - } - } - b.log.Debugw("uploading object", "src", sourcePath, "dest", destination) obj := bucket.Object(destination) diff --git a/cmd/internal/backup/providers/local/local.go b/cmd/internal/backup/providers/local/local.go index b686067..8eb594a 100644 --- a/cmd/internal/backup/providers/local/local.go +++ b/cmd/internal/backup/providers/local/local.go @@ -1,14 +1,12 @@ package local import ( - "fmt" "os" "path/filepath" "strconv" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" - "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils" "github.com/pkg/errors" @@ -24,7 +22,6 @@ type BackupProviderLocal struct { log *zap.SugaredLogger config *BackupProviderConfigLocal nextBackupCount int64 - encrypter *encryption.Encrypter } // BackupProviderConfigLocal provides configuration for the BackupProviderLocal @@ -38,7 +35,7 @@ func (c *BackupProviderConfigLocal) validate() error { } // New returns a Local backup provider -func New(log *zap.SugaredLogger, config *BackupProviderConfigLocal, encrypter *encryption.Encrypter) (*BackupProviderLocal, error) { +func New(log *zap.SugaredLogger, config *BackupProviderConfigLocal) (*BackupProviderLocal, error) { if config == nil { return nil, errors.New("local backup provider requires a provider config") } @@ -56,9 +53,8 @@ func New(log *zap.SugaredLogger, config *BackupProviderConfigLocal, encrypter *e } return &BackupProviderLocal{ - config: config, - log: log, - encrypter: encrypter, + config: config, + log: log, }, nil } @@ -87,14 +83,7 @@ func (b *BackupProviderLocal) DownloadBackup(version *providers.BackupVersion) e source := filepath.Join(b.config.LocalBackupPath, version.Name) destination := filepath.Join(constants.DownloadDir, version.Name) - var err error - if b.encrypter != nil { - destination, err = b.encrypter.Decrypt(source) - if err != nil { - return fmt.Errorf("unable to decrypt backup:%v", err) - } - } - err = utils.Copy(source, destination) + err := utils.Copy(source, destination) if err != nil { return err } @@ -105,14 +94,7 @@ func (b *BackupProviderLocal) DownloadBackup(version *providers.BackupVersion) e func (b *BackupProviderLocal) UploadBackup(sourcePath string) error { b.log.Infow("upload backups called for provider local") destination := filepath.Join(b.config.LocalBackupPath, filepath.Base(sourcePath)) - var err error - if b.encrypter != nil { - destination, err = b.encrypter.Encrypt(sourcePath) - if err != nil { - return fmt.Errorf("unable to encrypt backup:%v", err) - } - } - err = utils.Copy(sourcePath, destination) + err := utils.Copy(sourcePath, destination) if err != nil { return err } diff --git a/cmd/internal/backup/providers/s3/s3.go b/cmd/internal/backup/providers/s3/s3.go index 252ce83..186f035 100644 --- a/cmd/internal/backup/providers/s3/s3.go +++ b/cmd/internal/backup/providers/s3/s3.go @@ -10,8 +10,6 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/backup/providers" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" - "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" - "github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils" "go.uber.org/zap" @@ -29,11 +27,10 @@ const ( // BackupProviderS3 implements the backup provider interface for S3 type BackupProviderS3 struct { - log *zap.SugaredLogger - c *s3.S3 - sess *session.Session - config *BackupProviderConfigS3 - encrypter *encryption.Encrypter + log *zap.SugaredLogger + c *s3.S3 + sess *session.Session + config *BackupProviderConfigS3 } // BackupProviderConfigS3 provides configuration for the BackupProviderS3 @@ -66,7 +63,7 @@ func (c *BackupProviderConfigS3) validate() error { } // New returns a S3 backup provider -func New(log *zap.SugaredLogger, config *BackupProviderConfigS3, encrypter *encryption.Encrypter) (*BackupProviderS3, error) { +func New(log *zap.SugaredLogger, config *BackupProviderConfigS3) (*BackupProviderS3, error) { if config == nil { return nil, errors.New("s3 backup provider requires a provider config") @@ -99,11 +96,10 @@ func New(log *zap.SugaredLogger, config *BackupProviderConfigS3, encrypter *encr } return &BackupProviderS3{ - c: client, - sess: newSession, - config: config, - log: log, - encrypter: encrypter, + c: client, + sess: newSession, + config: config, + log: log, }, nil } @@ -211,18 +207,6 @@ func (b *BackupProviderS3) DownloadBackup(version *providers.BackupVersion) erro if err != nil { return err } - - if b.encrypter != nil { - destination, err := b.encrypter.Decrypt(backupFilePath) - if err != nil { - return errors.Wrap(err, "unable to decrypt backup") - } - err = utils.Copy(destination, backupFilePath) - if err != nil { - return errors.Wrap(err, "error writing decrypted file") - } - } - return nil } @@ -241,13 +225,6 @@ func (b *BackupProviderS3) UploadBackup(sourcePath string) error { destination = b.config.ObjectPrefix + "/" + destination } - if b.encrypter != nil { - destination, err = b.encrypter.Encrypt(destination) - if err != nil { - return errors.Wrap(err, "unable to encrypt backup") - } - } - b.log.Debugw("uploading object", "src", sourcePath, "dest", destination) uploader := s3manager.NewUploader(b.sess) diff --git a/cmd/internal/initializer/initializer.go b/cmd/internal/initializer/initializer.go index ff2e2ce..92fc8c4 100644 --- a/cmd/internal/initializer/initializer.go +++ b/cmd/internal/initializer/initializer.go @@ -12,6 +12,7 @@ import ( "github.com/metal-stack/backup-restore-sidecar/cmd/internal/compress" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/constants" "github.com/metal-stack/backup-restore-sidecar/cmd/internal/database" + "github.com/metal-stack/backup-restore-sidecar/cmd/internal/encryption" "github.com/pkg/errors" "go.uber.org/zap" @@ -30,19 +31,21 @@ type Initializer struct { db database.Database bp providers.BackupProvider comp *compress.Compressor + encrypter *encryption.Encrypter } -func New(log *zap.SugaredLogger, addr string, db database.Database, bp providers.BackupProvider, comp *compress.Compressor) *Initializer { +func New(log *zap.SugaredLogger, addr string, db database.Database, bp providers.BackupProvider, comp *compress.Compressor, encrypter *encryption.Encrypter) *Initializer { return &Initializer{ currentStatus: &v1.StatusResponse{ Status: v1.StatusResponse_CHECKING, Message: "starting initializer server", }, - log: log, - addr: addr, - db: db, - bp: bp, - comp: comp, + log: log, + addr: addr, + db: db, + bp: bp, + comp: comp, + encrypter: encrypter, } } @@ -172,6 +175,13 @@ func (i *Initializer) Restore(version *providers.BackupVersion) error { return errors.Wrap(err, "unable to download backup") } + if i.encrypter != nil { + backupFilePath, err = i.encrypter.Decrypt(backupFilePath) + if err != nil { + return errors.Wrap(err, "unable to decrypt backup") + } + } + i.currentStatus.Message = "uncompressing backup" err = i.comp.Decompress(backupFilePath) if err != nil { diff --git a/cmd/main.go b/cmd/main.go index e4c325e..8b66f81 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -113,13 +113,21 @@ var startCmd = &cobra.Command{ if err != nil { return err } - initializer.New(logger.Named("initializer"), addr, db, bp, comp).Start(stop) + var encrypter *encryption.Encrypter + key := viper.GetString(encryptionKey) + if key != "" { + encrypter, err = encryption.New(logger.Named("encryption"), key) + if err != nil { + return fmt.Errorf("unable to initialize encryption:%v", err) + } + } + initializer.New(logger.Named("initializer"), addr, db, bp, comp, encrypter).Start(stop) if err := probe.Start(logger.Named("probe"), db, stop); err != nil { return err } metrics := metrics.New() metrics.Start(logger.Named("metrics")) - return backup.Start(logger.Named("backup"), viper.GetString(backupCronScheduleFlg), db, bp, metrics, comp, stop) + return backup.Start(logger.Named("backup"), viper.GetString(backupCronScheduleFlg), db, bp, metrics, comp, encrypter, stop) }, } @@ -145,7 +153,15 @@ var restoreCmd = &cobra.Command{ if err != nil { return err } - return initializer.New(logger.Named("initializer"), "", db, bp, comp).Restore(version) + var encrypter *encryption.Encrypter + key := viper.GetString(encryptionKey) + if key != "" { + encrypter, err = encryption.New(logger.Named("encryption"), key) + if err != nil { + return fmt.Errorf("unable to initialize encryption:%v", err) + } + } + return initializer.New(logger.Named("initializer"), "", db, bp, comp, encrypter).Restore(version) }, } @@ -337,15 +353,7 @@ func initDatabase() error { func initBackupProvider() error { bpString := viper.GetString(backupProviderFlg) - key := viper.GetString(encryptionKey) - var encrypter *encryption.Encrypter var err error - if key != "" { - encrypter, err = encryption.New(logger.Named("encryption"), key) - if err != nil { - return fmt.Errorf("unable to initialize encryption:%v", err) - } - } switch bpString { case "gcp": bp, err = gcp.New( @@ -357,7 +365,6 @@ func initBackupProvider() error { BucketName: viper.GetString(gcpBucketNameFlg), BucketLocation: viper.GetString(gcpBucketLocationFlg), }, - encrypter, ) case "s3": bp, err = s3.New( @@ -371,7 +378,6 @@ func initBackupProvider() error { AccessKey: viper.GetString(s3AccessKeyFlg), SecretKey: viper.GetString(s3SecretKeyFlg), }, - encrypter, ) case "local": bp, err = local.New( @@ -380,7 +386,6 @@ func initBackupProvider() error { LocalBackupPath: viper.GetString(localBackupPathFlg), ObjectsToKeep: viper.GetInt64(objectsToKeepFlg), }, - encrypter, ) default: return fmt.Errorf("unsupported backup provider type: %s", bpString) From 6fd223b9da11cf0f959892558d56b648e17ed142 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 3 Oct 2020 13:05:43 +0200 Subject: [PATCH 04/10] typo --- cmd/internal/backup/backup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/internal/backup/backup.go b/cmd/internal/backup/backup.go index 72ddb24..064b659 100644 --- a/cmd/internal/backup/backup.go +++ b/cmd/internal/backup/backup.go @@ -49,7 +49,7 @@ func Start(log *zap.SugaredLogger, backupSchedule string, db database.DatabasePr if encrypter != nil { filename, err = encrypter.Encrypt(filename) if err != nil { - metrics.CountError("compress") + metrics.CountError("encrypt") log.Errorw("unable to encrypt backup", "error", err) return } From 2a471064dceed53bc136638b6852ec75c5bb934c Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 3 Oct 2020 13:35:46 +0200 Subject: [PATCH 05/10] Add encryption test --- Makefile | 6 +++- cmd/internal/encryption/encryption_test.go | 42 ++++++++++++++++++++++ go.mod | 1 + go.sum | 5 +++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 cmd/internal/encryption/encryption_test.go diff --git a/Makefile b/Makefile index 5143474..cab51db 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,15 @@ DOCKER_TAG := $(or ${GITHUB_TAG_NAME}, latest) BACKUP_PROVIDER := $(or ${BACKUP_PROVIDER},local) .PHONY: all -all: +all: test go mod tidy go build -ldflags "$(LINKMODE)" -tags 'osusergo netgo static_build' -o bin/backup-restore-sidecar github.com/metal-stack/backup-restore-sidecar/cmd strip bin/backup-restore-sidecar +.PHONY: test +test: + go test -race ./... + .PHONY: proto proto: docker run -it --rm -v ${PWD}/api:/work/api metalstack/builder protoc -I api/ api/v1/*.proto --go_out=plugins=grpc:api diff --git a/cmd/internal/encryption/encryption_test.go b/cmd/internal/encryption/encryption_test.go new file mode 100644 index 0000000..97a319f --- /dev/null +++ b/cmd/internal/encryption/encryption_test.go @@ -0,0 +1,42 @@ +package encryption + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" +) + +func TestEncrypter(t *testing.T) { + // Key too short + e, err := New(zap.L().Sugar(), "tooshortkey") + assert.EqualError(t, err, "key length:11 invalid, must be 16,24 or 32 bytes") + + // Key too short + e, err = New(zap.L().Sugar(), "19bytesofencryption") + assert.EqualError(t, err, "key length:19 invalid, must be 16,24 or 32 bytes") + + // Key too long + e, err = New(zap.L().Sugar(), "tooloooonoooooooooooooooooooooooooooongkey") + assert.EqualError(t, err, "key length:42 invalid, must be 16,24 or 32 bytes") + + e, err = New(zap.L().Sugar(), "0123456789123456") + assert.NoError(t, err, "") + + input, err := ioutil.TempFile("", "encrypt") + cleartextInput := []byte("This is the content of the file") + err = ioutil.WriteFile(input.Name(), cleartextInput, 0644) + assert.NoError(t, err) + output, err := e.Encrypt(input.Name()) + assert.NoError(t, err) + + assert.Equal(t, input.Name()+Suffix, output) + + cleartextFile, err := e.Decrypt(output) + assert.NoError(t, err) + cleartext, err := ioutil.ReadFile(cleartextFile) + assert.NoError(t, err) + assert.Equal(t, cleartextInput, cleartext) + +} diff --git a/go.mod b/go.mod index fc109ab..6867a7b 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.7.1 + github.com/stretchr/testify v1.6.1 go.opencensus.io v0.22.4 // indirect go.uber.org/zap v1.15.0 golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc // indirect diff --git a/go.sum b/go.sum index 3d1a02b..3549608 100644 --- a/go.sum +++ b/go.sum @@ -384,6 +384,7 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -391,6 +392,8 @@ 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= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -744,6 +747,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 260ef8b6957e01564d1300ead8f069c0ccf38ba6 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 3 Oct 2020 13:44:27 +0200 Subject: [PATCH 06/10] test with 100MB file --- cmd/internal/encryption/encryption_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmd/internal/encryption/encryption_test.go b/cmd/internal/encryption/encryption_test.go index 97a319f..7310994 100644 --- a/cmd/internal/encryption/encryption_test.go +++ b/cmd/internal/encryption/encryption_test.go @@ -2,6 +2,7 @@ package encryption import ( "io/ioutil" + "os" "testing" "github.com/stretchr/testify/assert" @@ -39,4 +40,15 @@ func TestEncrypter(t *testing.T) { assert.NoError(t, err) assert.Equal(t, cleartextInput, cleartext) + // Test with 100MB file + bigBuff := make([]byte, 100000000) + ioutil.WriteFile("bigfile.test", bigBuff, 0666) + + bigEncFile, err := e.Encrypt("bigfile.test") + assert.NoError(t, err) + _, err = e.Decrypt(bigEncFile) + assert.NoError(t, err) + os.Remove("bigfile.test") + os.Remove("bigfile.test.aes") + } From c06211f3195e4e4b410be11e1ad08b6019ce5aa9 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 5 Oct 2020 08:27:01 +0200 Subject: [PATCH 07/10] Remove input after enc/dec, better logging --- cmd/internal/encryption/encryption.go | 29 ++++++++++++++++++++-- cmd/internal/encryption/encryption_test.go | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/cmd/internal/encryption/encryption.go b/cmd/internal/encryption/encryption.go index 5a0facc..3bbe500 100644 --- a/cmd/internal/encryption/encryption.go +++ b/cmd/internal/encryption/encryption.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "strings" + "unicode" "go.uber.org/zap" ) @@ -31,6 +32,9 @@ func New(log *zap.SugaredLogger, key string) (*Encrypter, error) { default: return nil, fmt.Errorf("key length:%d invalid, must be 16,24 or 32 bytes", len(key)) } + if !isASCII(key) { + return nil, fmt.Errorf("key must only contain ascii characters") + } return &Encrypter{ key: key, @@ -40,6 +44,8 @@ func New(log *zap.SugaredLogger, key string) (*Encrypter, error) { // Encrypt input file with key and store the encrypted files with suffix appended func (e *Encrypter) Encrypt(input string) (string, error) { + output := input + Suffix + e.log.Infow("encrypt", "input", input, "output", output) infile, err := os.Open(input) if err != nil { return "", err @@ -59,7 +65,6 @@ func (e *Encrypter) Encrypt(input string) (string, error) { return "", err } - output := input + Suffix outfile, err := os.OpenFile(output, os.O_RDWR|os.O_CREATE, 0777) if err != nil { return "", err @@ -91,12 +96,20 @@ func (e *Encrypter) Encrypt(input string) (string, error) { } // Append the IV _, err = outfile.Write(iv) + if err == nil { + err := os.Remove(input) + if err != nil { + e.log.Warnw("unable to remove input", "error", err) + } + } return output, err } // Decrypt input file with key and store decrypted result with suffix removed // if input does not end with suffix, it is assumed that the file was not encrypted. func (e *Encrypter) Decrypt(input string) (string, error) { + output := strings.TrimSuffix(input, Suffix) + e.log.Infow("decrypt", "input", input, "output", output) extension := filepath.Ext(input) if extension != Suffix { return input, fmt.Errorf("input is not encrypted") @@ -127,7 +140,6 @@ func (e *Encrypter) Decrypt(input string) (string, error) { return "", err } - output := strings.TrimSuffix(input, Suffix) outfile, err := os.OpenFile(output, os.O_RDWR|os.O_CREATE, 0777) if err != nil { return "", err @@ -162,5 +174,18 @@ func (e *Encrypter) Decrypt(input string) (string, error) { break } } + err = os.Remove(input) + if err != nil { + e.log.Warnw("unable to remove input", "error", err) + } return output, nil } + +func isASCII(s string) bool { + for _, c := range s { + if c > unicode.MaxASCII { + return false + } + } + return true +} diff --git a/cmd/internal/encryption/encryption_test.go b/cmd/internal/encryption/encryption_test.go index 7310994..06719d2 100644 --- a/cmd/internal/encryption/encryption_test.go +++ b/cmd/internal/encryption/encryption_test.go @@ -22,7 +22,7 @@ func TestEncrypter(t *testing.T) { e, err = New(zap.L().Sugar(), "tooloooonoooooooooooooooooooooooooooongkey") assert.EqualError(t, err, "key length:42 invalid, must be 16,24 or 32 bytes") - e, err = New(zap.L().Sugar(), "0123456789123456") + e, err = New(zap.L().Sugar(), "01234567891234560123456789123456") assert.NoError(t, err, "") input, err := ioutil.TempFile("", "encrypt") From d08d566bdcdf482d718e302fa8d6559baf252a89 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 5 Oct 2020 08:40:31 +0200 Subject: [PATCH 08/10] add the ability to download/decompress and decrypt backups without recovery --- cmd/internal/initializer/initializer.go | 8 ++++++-- cmd/main.go | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmd/internal/initializer/initializer.go b/cmd/internal/initializer/initializer.go index 92fc8c4..3f087fc 100644 --- a/cmd/internal/initializer/initializer.go +++ b/cmd/internal/initializer/initializer.go @@ -136,7 +136,7 @@ func (i *Initializer) initialize() error { return nil } - err = i.Restore(latestBackup) + err = i.Restore(latestBackup, false) if err != nil { return errors.Wrap(err, "unable to restore database") } @@ -145,7 +145,7 @@ func (i *Initializer) initialize() error { } // Restore restores the database with the given backup version -func (i *Initializer) Restore(version *providers.BackupVersion) error { +func (i *Initializer) Restore(version *providers.BackupVersion, downloadOnly bool) error { i.log.Infow("restoring backup", "version", version.Version, "date", version.Date.String()) i.currentStatus.Status = v1.StatusResponse_RESTORING @@ -187,6 +187,10 @@ func (i *Initializer) Restore(version *providers.BackupVersion) error { if err != nil { return errors.Wrap(err, "unable to uncompress backup") } + if downloadOnly { + i.log.Info("downloadOnly was specified, skipping database recovery") + return nil + } i.currentStatus.Message = "restoring backup" err = i.db.Recover() diff --git a/cmd/main.go b/cmd/main.go index 8b66f81..5fc2347 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -44,6 +44,7 @@ const ( databaseFlg = "db" databaseDatadirFlg = "db-data-directory" + downloadOnlyFlg = "download-only" postgresUserFlg = "postgres-user" postgresHostFlg = "postgres-host" @@ -161,7 +162,8 @@ var restoreCmd = &cobra.Command{ return fmt.Errorf("unable to initialize encryption:%v", err) } } - return initializer.New(logger.Named("initializer"), "", db, bp, comp, encrypter).Restore(version) + downloadOnly := viper.GetBool(downloadOnlyFlg) + return initializer.New(logger.Named("initializer"), "", db, bp, comp, encrypter).Restore(version, downloadOnly) }, } @@ -262,6 +264,7 @@ func init() { } restoreCmd.AddCommand(restoreListCmd) + restoreCmd.Flags().BoolP(downloadOnlyFlg, "", false, "if set, backups are only downloaded, decompressed and decrypted but no database recovery is made.") } func initConfig() { From 930d86d5a4861961ebaa0e71f2518947753d5a24 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 5 Oct 2020 09:15:25 +0200 Subject: [PATCH 09/10] fix lint errors in tests --- cmd/internal/encryption/encryption_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmd/internal/encryption/encryption_test.go b/cmd/internal/encryption/encryption_test.go index 06719d2..43f0ae1 100644 --- a/cmd/internal/encryption/encryption_test.go +++ b/cmd/internal/encryption/encryption_test.go @@ -11,21 +11,24 @@ import ( func TestEncrypter(t *testing.T) { // Key too short - e, err := New(zap.L().Sugar(), "tooshortkey") + _, err := New(zap.L().Sugar(), "tooshortkey") assert.EqualError(t, err, "key length:11 invalid, must be 16,24 or 32 bytes") // Key too short - e, err = New(zap.L().Sugar(), "19bytesofencryption") + _, err = New(zap.L().Sugar(), "19bytesofencryption") assert.EqualError(t, err, "key length:19 invalid, must be 16,24 or 32 bytes") // Key too long - e, err = New(zap.L().Sugar(), "tooloooonoooooooooooooooooooooooooooongkey") + _, err = New(zap.L().Sugar(), "tooloooonoooooooooooooooooooooooooooongkey") assert.EqualError(t, err, "key length:42 invalid, must be 16,24 or 32 bytes") - e, err = New(zap.L().Sugar(), "01234567891234560123456789123456") + e, err := New(zap.L().Sugar(), "01234567891234560123456789123456") assert.NoError(t, err, "") input, err := ioutil.TempFile("", "encrypt") + assert.NoError(t, err) + defer os.Remove(input.Name()) + cleartextInput := []byte("This is the content of the file") err = ioutil.WriteFile(input.Name(), cleartextInput, 0644) assert.NoError(t, err) @@ -42,7 +45,8 @@ func TestEncrypter(t *testing.T) { // Test with 100MB file bigBuff := make([]byte, 100000000) - ioutil.WriteFile("bigfile.test", bigBuff, 0666) + err = ioutil.WriteFile("bigfile.test", bigBuff, 0666) + assert.NoError(t, err) bigEncFile, err := e.Encrypt("bigfile.test") assert.NoError(t, err) From 7c6460d1837ad552512317a74edf7cebbadae32f Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 10 Oct 2020 11:37:22 +0200 Subject: [PATCH 10/10] Add encryption to sequence diagramm --- docs/sequence.drawio | 279 ++++++++++++++++++++++++++++++++++++++++++- docs/sequence.png | Bin 130 -> 125694 bytes 2 files changed, 278 insertions(+), 1 deletion(-) diff --git a/docs/sequence.drawio b/docs/sequence.drawio index 7a8b920..4c65863 100644 --- a/docs/sequence.drawio +++ b/docs/sequence.drawio @@ -1 +1,278 @@ -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 \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/sequence.png b/docs/sequence.png index 61b177a975e31891194ba4d5004f36891029fa04..28c3ec84cd37677b458bd838fd8fda70ae462c19 100644 GIT binary patch literal 125694 zcmeEv2|QHY|9_T3_B<)6kV5vEVeEUTEG-hEgc(ehVeFB$sO%zZX{8bgWyz8@TPQ>b zV@n}h$5Sjb5=0p|bF48(h>9>)^Nzv11z? zZZ2jfWsWq32}vTv;6h?ZGjkzRBnl>Ej)0qqiJ6N_iJO{$%fLN0SQN$_gGMdf2N#8l z3c;X%2SlZ|A(RkE@E=TE7>STNv~azN1=^PI5OHBq&;Xx447LrS3_fXMY@J-eZ&yjA zF;Z+h_@rcKXN}fFn`&Sjx53rK5fZ|nL2!%4&I4MS+u$nTvo*#F4SuPk&8)D{Eh<

gCT^G!s5^u2vsn; zD2#~(&cp_^WNQLCGJnZlFbYE8iBS6(!qCAGXqYHc%1lTSjy4lQqDy< z5sY}&34=mA5L#Qf(-DiccEs3yebNkTYYWEjs|!tVIIPRpmziU&iLbZNm>qcYg_{Tu zgih#~nOGD1@#Qi-49d}x@Bo-7$>lrI7z<0nqb0=&UznPhSy|w)PPT;SZG$7s=YJL& zv@s#JMY!I<(gcNdA?eEeWZ|$_(6H*fQmCMG5yoSo_YRJ3!~vRr#d&oT1zO``iE%{h*qN9? zm%9Lw0Ou?nZLGl&q*Oq|tyQqrSR6RE#oB_4l+CfWj>J=7j6~;uz$js%BG{1VVSv?8vc_0I zX4e$!=!mreBZam_DM4lkoWt6o!B@&C69>zAeSs7Ld`+-Vs24z)6WgU4c#* zfD^z)Nr(}ScR<<$X*u-e4yXgfgS}`R2B;X2(1ml$q11n>C(!$WXMri1pR^w;I(Qu< zj9|rZXloNkj5FzdaMABc5uvrcSPX~^7Hx)*1W-Om{|H7yoG8G=CLB$07HCJpUEo53 zJpj{h0+}A-Wp+@rK&BSW(>Kq75k2IW=Li!{eX%eLjeftQz&8nt!xs!G^#8&Tk@j0y zN>b{}&%#>~yXSy)!kM9$yoHS`v75vTvF7FuXfQrs-gMsbEgIYT&i$4#gb_jn5@Wc~ zM-t2TYi{QUKITW}?H~0$2vNf85#|?xkX(2>63Zt>j3P+A4;(=dK;jJij`xu;H8C}T znTeU2!6nSaOhttVZIX=j7smt49}dz0GaJ;B2>|hm9i&Q5HrARLbF?+^Prx$Rkr)DN z!f6uY@K^Bxh~fyIZXsSU!&+OL*g0TK=c5hC+ThS;P9U~*M(;;EECh?tS*(*I)B)fq z2|?ierBLv-XlWPYE9fgTtPRGDV5@$@=q|_uG5(tmWI#uM!VH@b+<_Sg!XV@L!)WK< zBZ&y9g=r;7A`HG%5*GtqQb|NEhYwyNiNq+3L==}u9f`{&*iqmF#Fe*+?*M~KDtuU+ zqb1e?YinXnDt=#Ejb9ZBLd5#dOT&-t&yVC}VW3E({UyUoRP>(?lEvmRpy$sbHB)P>nH3PI zAD9Lb$$gvOzeRs%+zW-KV$D)+;SepcN?g%M&>VhhtoaKgmM z?{6xfl&~bA7RAIQf!awT;SvOXf$$KRsMJ@wDEXVp_~%bSNPGj;e_0v74{)RiK%Mw9 zgsE9%wunfDU@^YEoWL~v9GD_b2jN*l#ABk_`sYv(F&HDU3V;y8x!IBWIZ+dwnI(j2 zmzW2PIWPri+xZ(n5d6Rk5)!*?p%l=cQM3Q$ z`1oH2hJFNjehiWpj2$T$A~L%_jeW$4bTrY&5Uuf7;D_MeNYRfJ0cH{9aalN;pCQCZ zLcRYX<3CMR{7}1pS~|W##>AN5E7@2OLQ>IKj^xpjz7rT5k|5y=edl5_Z=?P%vUmU8 z)(NEGzrqYZPuxLaAcPT@)jTbwWfmSnLf8M#I((0iKg-gSm__)3741wF~XpcczQxz2&6s^#A1fH1Ze2cYkE z2!WbA<$rJH-k+VUmA&+S%NBE$b8O|r6?0eP#fU@1tv@BR9iF}1zqWg1^<~s*Wf_L z5sUlBsny>|y8K%d0D%zuI>#VH%>VsO1wcrNeMOaiEv9fuiLWvlggA#Nc0W*#FHW17 zRh0TVtBCkX@BgbYiWvOs=fEYuicyyI>)Y#z{rWkrB+dXqDT#-~!TINM7sLpU#HH9_ z9Tw_%7By#ylOYBrpz0MAP5)I;g2RI1%!ML%C|hW5jj=ljqK*0L9PoK3@$(OAzkciu zeiRfe^!IPkia%5P1taoAq}&m)5|%i1%jWxu4U^0iR7C7#2Q1v)1)#PRiV-L3zqR)3 zzneWmA_+$FSGjEo;-ZJ;mqH>z|E2VLiFF_eLH|c^|0%)!-RNgg(SMgm`bn01apA=B z3kkvVlb9-ExtAyaCG!iOzQwsDLi01Y<+n@pe=Pz2Z$vbIN)iznz`uk&e>0?8q#6kp zNDP`bh@l|L%n#7QuSQ$q;sj{@&2xS(dXgX#r{CPY*vlUTm&;WK4<{t=N#q@@5VN($ znm{Fw%PsnU0oi{8h7i}3fYL9x6o}BiEGZG6Utu}FiUf+k=Zn4m6-!D8UWQZ$zHciD z7yhLl5YWSNR!t(L5W;ZM!tZd4gxn`o{5+3r z7Uq$}N)hq)|FSiUtH()`=s%`%7DkekviYvRUsRo+#zsVPpCEY%0yH6!JQy*UCY3y* zG!jk1ve7t1O&}3I45(1VfV|xC`Sk$E zAQyN0_?A+%!JtskPA1|48)w%LaWxc=jzcS#-|}HCq4W{&^W8^gnNZzIK*kh(FyE;s=J} z@48MgLNNJrX+VVJHyIdWC`y#%f7o>rcjF+zP+xdm2$PeTDI!t$zrvjFZ;Q9YLjOp2 zNUi(tQjNcCTgAQ>w4YzqMMNk>iCi|@O5BQ$ME1by9jN^E8^I%SjNdxF->47&*312^ zjYh=5BKUtVT>q!7Dne3nVSnGnEHM(=T$m735{2RiW@-u4Ufk!2;Nid5)(;Hxaz$`r zODiADtT7AGnH|{K3yR;M%{2d}6#jO#&+o|RZ)S5rz7hBzQqV1qBp&};K=)q?Ga*&F zj5}{4h}+W;ByzDZhbY=V5XWDQ6TX#v;&Xm3PJoHRge3vFy7==o^(6r|`WBa1k~${7 z!e449@xp(uXq&jIoy6EXn#^xzzEDQt0MriJVh?Pv4tBZ)8_@nu^;`aA5(#T7MYQ<_ z^PKH(IsuZJim#b3Ng$F7O8K9ugnzfB;+vd-1YA-WMk3n;(I(2|UkWe5CIAE`N) z!=;wEsUPU_vbh!l03i`_uoVF(20Er3xdGr4tR)G4mdiF1@E0qM5ZOc$s zDgpZziu^^xzpRBzYx9;>_`mySFqRU^UlY6Awv> zp#G&qFmX3)64$43$g8CV znIJI$u?OF1D~V7n19|mp(HjwA5cbCf9?M_>uz-!^{*wX5BFaZB*&!1eUTB2>W+b?{ zZxJEZ0e`X!{4J8-2hfWcgwQ==v&7YqMEUz=kM#XbYN4{B`C%YFhhUxvao&=+aLM(A ze*IirNZhK2@GxQul=x1|5*HHUX%h451QMr<*l8(9`gSiGlli^c3Hv4h0fADn3mY!{ z2Px$5deU!VIzW|>{OPTEV@i+{^~Jv#Mf_`2U>E2mN<`e(^lvH=w0XkUI}V5w?J`j| zeipn#3zNQSim=b?ViCzQsSbch-#&@Z=^rW2ckcLl4_ZJUEC9RjD=Trd3F<>UBo5KC zsLxVPo3J}G(1buu3SQz*g!ii*_t{)zX;nqn}ENJvNZhscRI9xkN$kSi@Fdo zh48oa=WCIdAnp=I6pf$P9>V++L`;&nSsAgRWz(H+C^kZef2=uQUr+4U&$%7qC=*_a zcu0Jw-_aYOsbBu+;R5UTwJ%+))sI2c0*~f#)~YGdr-tE^)qHVam#4u3CJW48i|aFh=!{OmEYN-ckZFq87!s zW1{9{XJ#_n(pw*74-~K*H$PU@=r>UBs8^ud^3hq#soHA?D(*F!dOf+nH`mdHUwio| zle7@4WAp;%sC=;uA#DY76V+ZTq-R5JQ>i>;5~ZXgoBzenc{G1(8<#1i0@qxV;%;io zzGoy~ZaJENZOe{WR#D%?uqkWKZIoF~W?vq&mRa=3e&#EhwCjual%7C_ts!s9gAp61 z^EpesUgReAzND2wc-}5~_MJ3jHZ5PesHjRA6n)?%UoE-Tn(3n1Ne%Nj3=gI?KNo?k zH?WAh*Kov8Te6+f;Kb-Ffeo`SR2a)@G(?1Gg>#Oc%W!xO3($-ay?n*!DMJdAVzw5t zafkUuH*=SD$h6$Iak#Q=(WPrN1ox?GY}qhl!>POSCJp=I*eC{pew|@9VvIY;JiSML z;z{_RNa47$ZT_&DRClBf>Uj(-qe{9@4D;xqq0P3EjSfNFRa%EP_-+(G$TVGeVygVX zU}0a}Yn5+cne6_|YI$2& z@hMpx<)9k7%~lnEI!tLD6;h06e0p|juqaxpCqc(^yqzi*Jh3JIY_siy%9f0#V<~0V zqmS^X9=aDnwb@mXLHZqMto<`Kbk7AB=MP}Q`m_pt(tWy=vf@{N5j#AS=#hv)#T#ev zMH6r1Ywnta%~5{BdH#~k?zd$}>vRTYKV-KZLB2jpA=MS8lJpU^-FL21qHSk9(xxjp(GxexuvzxC zkSU*56FU0vMjwTlPqi(|X0OvtGTtY}mxFU}9Vgyh4GqHgxZjR(BEFQOEfWxbcD?gr z*LZvxFZ)M&O?}87XuGMCEDf(*Nn?x(SKU~~z~TX)>F%=hJN0OT)$R7COI3+<@?9G< zS~AcYV^i&q11iKDjJVB8LYxdHsW?1dgb(TJ9o99EF4|bI;hZrR4&51i{Ruc+8A8)D(Gnai#1@ z-z%-67XSQs41P~6{5qJ4IUv~QpRyW0H+XSXow4zFU+Uq5v)9gP`Toq*OvLv)lZk!XdYi#U~hR0ahLvDuV3xJqK%^S zaRp+vhB2)$>kvz^!az=E7cdVFXhBpzkZ%{g%_>@xt?q+Dfx>z3il{wxa7-QzD{Z<0<|D8glPoWy=@qYT39Df2aZ-8qX_G2b5U z^G<$tyff|ODfk9zk(1M}^o*Sh1}@6EmxE#1E|8iPkpQ%(Ce<*Tr<-#SRbDMKC_91o zW8A2e%sThE8SB#M&bkIQc(YcW3jV3Uee8UTOIyo5tysE13S^fjuo7^~7o2(#6vIhr ziC0C(UYmu!m(@LkKX+4oj5pC^f9b$j?<{}Pt6Z%XSQRl)30Z(%3vT%>i4g8)Rr4P zV1SO&Eid0U;!B4myI~U`%3=4AOxd8C)zG^A*bGJ&{Rw9)(~x_se)`Mv zr&eHv%MbrhfL|4&4CTzlTTCc!^1SZnAxii|rqg6(o!emEz5C9o4YA<->93vizHdu# zZQ$3XE#%KM_?06u;FW1|t5@w;Ry33#Dz-P*US@FjTCVaeZ|3QfZ!9Rbb6rYh|I+x4 z)84}oXPMB49#VTM4`lj8GQFq|COX)o)CYDvbls(T8ZLyV_Dm8g4I4?wGmHN6^?Gs) z_fbj(8^$NiMd+cv?kx ziGU~e$nb&xnv2XYkUmdsh?bQC{P)%l(eTCl(~(tx>sNi}`t!vi`gH4yMPeRT8hsfq zQA$C-#KHBa6Y$vd;#DKSlD=gZ&#Yo9-A;Zu&oSJ-^Ogu83$AP@LRuiBguYG zb!R;`+%F{#q%PN`3q$vCx=yx_fB@}XL&lC}U2o5M)P611t=TLLWgCZa43EEJ??Pj} zt75@)Fo4F+Q}7`8yJ>%V#z=QoCim5mv73QXO zkj>VaJZO=kXPhTR}~2m_uX+w{RcS~_;5rf?3P+zmLa>*$K}HMtHJQk_AFYbpT@ zPA*QbboI)l`)+er2tTksX9FCiN5=F>MTH8Z+yR%w`iEZ3FSN%G<>up$cSq^vxy}Jw zg#z{^T)bZY@yuL=hVXW+;HTNG$LEcX)bJCQZr~+$uVi3Px%qH2CRvpo8}4fn9HsiO zgTJlVgi^tDZWX21V8Ph=&mWpAtnL)>fO}J(BdTRbKwwu!PAm8V6`GQkck4D3!3{rM z=dLkStuW^yH9hng9j?k6Zj;?|FiHCYzeKC+Rqjb_;Y8ANFh=56CxM|X%l}v<0A3)| zx@hLJ)_sSz6Jxvj>Qm7LqxC7dMb9K=KUOQ)njEatfJS}9yYuy3Gjy$%gj3+a1?Q$+ z^3y{q*+(txCqNKY3Id|RXGo5@IN%?W5mLK+=f>K+DuNJIl85Jz2R}0TOrCO)zb!5h zp?qoQN7wx^lXaoY)29oVnWkZ8&vs_pwixxHUVLt{5|Mg$$*=25pl}2fA#w$5+#)-@ z?ue^N?$9Gz^f@hL__p)<%D`*MxiGRlvbgA`R=V+`=j3}hy8I8HX=8^cf;fg}q&4 zEiT4m=6+K-0nQWa+*yr1>~lZdZ$?3(_$k&yH!c@l4UsOt=l0qppiC(H&6ZCEAVeqy zK2E4IULx9V6$c%o+^4;~>i0iYh!i=xIw-8$8a(^b?RwO~2zJ|?;!*ZDB}Eie430V1 zhSj!qh~CbXf;2P5fH~B*tFrEH$!392xz91~I#0!qf3h@zy#}F2ZpT@HB=`7dt{cTH z!vdX5BP1E%<66P6!WEv7S9deHdHp=@?k>SKW8KeIn4Nw~MQiqntIDt9*)4UY1IhfV z8?a8w=xjY7@29$JkD~Y1QF}ho7Em2Z){5tWVp`CD%_DBzYonhgJ5p@{UX7|0j0?{> z-aXFO)|<9vTI`XU=sI^Q$fzV_({-1@)<^6w8#+7Vxk!&%Kx4FM6 zl1DQJ-_#18`DV+Nx>3+}&ePSX6GQl7I0yl=^}U}Df?)}XnFEnBZhE-nfdsptr}GJB}aor&SNx%2u)6N6Wei;4Lf zGalbIAf!6P+2v!li4wR+3f%g zw67;;PvrKN~W*)~SROT(PljZg*F1&qar8o5{;nE(ppgpn6O518C%F$#(L_TJ99y5j(OG?oM{o z6-d)2`-@_jh-UomT`SmTaAQi-Tx*z&SvR6m%AREAc%N3}@qNCvYlAxx6@8Fu@K zRfqhvN|ax8L$ko|SGL=~Pk>x|=gnE3yxRrc~hHI#+aIKcxa^=RAlHuX~$l_lRb|hrz9T z@H(~p2r#-yd$%YWtYF0Lbc?}?6CdYLs+>Eu7r~hm#>`5I8YWa@tHTc`u4QQT@%Pj@678<(-;-Ia{BR|fw%KfjO{5|OYaOAYf}CM4e}@z z_7UI-c8z6w<5`lQ911IDEO+M|4+_PZ1!YJMn6(!GN+2iO@QnsCaX6KYBKUH~-Cm`k z9oLk@pBe55GeE2cQP3ZpX#FR^-c`{iUQtoI@Eq|ZA~=bOY^OMH_1-PY1%gk!8~T`> zHupz%q|-#!inzYhG4%RyuOTmj9sbcMex%oqt{%xHhNGgTgqL=A7>)uF$abwk!; zwI`QQ$=iK7n6`XgMYmq`VH8LBHgqi^cD+c50;$nwbh2)cJIMbzg6pvBMX@o>T(gRTvLMg&uFziTM2t28SsRv zGXlQZRQg7-h{QA32dY6ME|VPr6TY9zrmdbSZogrD`#6&#^NqdNhFQss>QAmA3l!M4 zmu)S=m*Z~dqaJ*%SR=Non75OPizmLI#kn~*K%RYobA-urx1A(Szz7>PMY5A(P53sm zJwh_~hM11@mX`TDtYNgUS83vU3y2(+j9JuFc}svSJE}}JqW$WsM6DDi^lk%AenHOC z9Gy58!4(@GQyK*1r-z45y6vQ9H*4f8Reeu8raZo#LRqhs!A@Lt=q^R`i&JoF>OF0R zCl0%QykgJnD<+R)iCoil@(yQd#OIE#GSQfFCua^YZmGmTfoscZw-+lq zPgXVx*16THNwK5R(;=`olK!WKvY$I`(UgYd~dd7~I=*R$S`+i*LUbQ4XDS`9+uSe%}DhLscxa14W&Zctau-t&n>3;sPmSzgb6?vd}lyt zOdBN0l%8{zLf5NF%y%$UM3Y5@(`g<62s`;{lBsY~0gzDP!y+eE+)=KQyyHd$^E7pF zRuY}hZSMJ)-Js<0CkaXq#fQ)08IP1EGO+4Re8jxIQc5#x8YpydB=h}*|I6D5$`PLx zZNm8Hqr0PnKklY(Y@_#i$Mhnk;@$DA^Jl#QLiBK#!uev!&JB9Q`bL7iou`j=j|87L zu%O=R2gU_uCwxc*wEQ^-TshSM+Pk$dcDH)poCE;w(pG>!1VuX(K|IWGU4E2Yk&*4F{clk`!G|Hv+CJj>fIBsHZ(JQ3S&xr zZK1L2wqe_kQg^KYjY-*E3E`*%ORdwDgkSrbXM0IL`{VJy&y z0a%qsi@OOzJK>h5qmj{+ZN9=Smngi_Kp<4T(=#t^XTHma*R|!_Y`vWpS@ z_@>g$?)_X>)kDt%lB|{Enpxe}WAT1U5NF3d0h_EWNxBDoew8}A7Ox7Y6(p5$B^j6R zJk>=`A4oah$}(;8*uM;r#k?TAkItW)ol-tA3n)BZ79Pzoxv@7ofD@bWYAo!%l~N7} zE_Q+9M5Ile;Jv#2aN9SM21k8XmUno)yBtuCs}SM^Z;I8Gf0P!oNoIE-tI&ZlRg8n{ z3-&U-;zV{XD7dbm7d1c46}AP49dLprhYgLoU*~S=5HFqsOe_j8fYC0kZY6GH`%eI7 zwE|*rz|)iS0d&bI=TDigPyx6gFJ1JsjNcrv_~pk^Qh5;1MO7O4+yIEXrkipQfYSI| zTQC4eMKN;&_~P*Va-PWUcy`9)+!Orkx|DZ9RvSllmd%9vT9Ef(XC=e4)4Ylu@d5K^eE|>z4ZvPBL@`Ud49H&4^JnA`4&d<2@c`W#7y|)wf@UoIDZ2JfUN3(x z7_-A~H^v&6$38{Rl}%%F+Wq0q{rb7>{_NLIOnn~su);>`qO3uc>_^R501@9jY6sL> z^n-!CiWaY-Vk+9LF4N<~^wRkNgk_A@8$w`rD?rhi%|Usu4jPt$kaY`(=lJD{eutMm zy9H9W@?LO^fY{PB2=6>E@X3MDTk*P>4Lo8U)i_ zXl-Tjcs|~na;FOr(UA^SQYGPS0F--4`ziol6HK+S(W;9Aoa19}973C|Y1w9H#@f&| z*LL9`#0jBik%CV(j?^GSVSxkVFKK!L3=Fbvh$`^(e!KJB<5Zg*!vq+6o3jTUDZLH zujyg!5Nj_pU&e6%9IA$Md*ruMZM5^wpX^Pko$wpkP;Qau_`bulG+*WXRi5$47VFGP zB>f2p(WlAs-RAbP)*NDQ)2n)$LsJOGGr-NM@Q2KT#f{!x)Oujuf67%|YbaE@mygS^db1Dy%E819UXBTv zq}UCfZE1&P#$TPVC>b|;G=>S^}$;!&f88F=g zc$(HD0eeC^W90y+m0P6iFl>GiUVn6t;Z65=X}ha&g&QjNKdW%aaq6qDouRqFdc?K; z361B*t!>1YqfFdzoQDS4R0W8kM`y$!!ok2P0}%RjcGqP9=#EXP?5W#SD&zDSN;|m+ zuX6M343>cCFu==8WW&yfN``-!Pw4pYG_Noz94QyLZq<;ce4ZnM@qHU0pt_RcZP%1q zj~^dz4>%kw=QQ)FI!XW2`^L=VPXjH@_vpiut@&;gC%?Vu9w&hv;GuRj$C6=bU&OAY znuM@NMqk>4Josk#Xg`~!2M7CUjYds5uYzdj7dq##TZ@il&Ey&Pxu+%=*T*9L6_L=a zubi~cSy|2hIki%v}Ekr3g#s&5n57=FIB zFRtQa!W2kh3O4Xy@os7nhZ#9?_N8r#IFWz3$I^-+10TD&@O5Cx%cjUm<#$rP>@v=; zO{lW)87Won@$+#}uF zJwj8gLk@anea_oa!Vz<B)>{HYH0xO^-5 zj3o0wmCRry$j0SeliHdAKFhKp%!8(6O01OMl=V|}r$;tNxL(~l2ISl6T4MHu5r@Z+ zkIW5UO7^LG*V&V8Zv*CJ-c*%_b020CS-WEE^m!od?>}+xQ#GZR^DW9WX1u^TzO^Y1 zKvjkc>gaa|9PHG#w@BR#J+*R99tiWCbm`TEwyRqv3QM9YSC4WXr7V)4E^n=T@?^)u zlO?cNnGabynsTab*7yA6IVbYj+HL#~H>xUvSut`B7pNYa*tsb+HWb(^yPJoxt9Pg%(=girJ^P=Y93<%&HAKdtOQy_Ni;|X>_o!a7M42 zr@&WKw##qEa$5}EilK@x*fNzba2+Vbm~cxXjh_DAhM#Br>f7!CJorZI-C{7AOL6JioZhqvbVT6H`*Gti9i zXjr*MD^-47tbMtj)SD}R6!*kSB-oV{M2^}qt)h}ie}CRjG>bAZ&%KbL`sv-q$g$h$ zk5%L=j=!cSJJ2a45H*+mv-Z`Fn2Qo@x8klQ!2>wXdnG(Mj8VSZ1`(a~k-||D~ z3)FQ7-m5JhqvC0p~=y zi_rkkbmJrxY`M(vxA*n6r4-*|jWE`lDl|nMk5cD6N9om+g&D{ZI8wXP*e|%IEK2@1 zv#N2o{FRqEHV4P*=FsgKWm{;E96O|*%6JdgsQyGyl(I(s;n?uo2cGZU(~VjgcRsc%VH|sT1<5tkeKzGFl#+4Sy!HpW3<}wa!+ok<;mu^H||1#A*fj3P>sHu zZE{YvpQ)tP2O93zYwt7A`H*uiL_@dzcfO%I64REkfla!gfM?v}+F5CF7BYJZE%Er0f9QAnG<5{ORZ=7+0!eS7dw;!XpInimx z2IT^p8-d?%t^hWszjx~O$;TxUuOlDtGqz5jj|^!L30oevJ?40ce<$obWX4UqZdR>w zb276BV8_xJm^XP8S!WEjs6>s{PVN=Z%T+%I($PM7UKv~(4LF#V*Q(XDjuQ0EI}0Lt zL7+XDG3Ie9By^wMDH_k4j5|+~36H{7e+UqNH1mQd)`MC))>*!$*sYK*0w|D+TM#{3xgua-(Q9>(@NheO>s(76(A+7?@D$_ zC7gVGM%?*&fH(3;7Vf=)sa%7f_ZVg3o&)Dz0%kn(@O>zvP7J|2Q0meOvOQm%%CU+6_BinT2B8KuI2A8hp>tNC^A4PS}UaXO~l%7vFJ zrn(DqSSp9IEZeId(5HF3>Xh&A?ObPaP2)t+m5s%WUiyB>4J;m>>K|rx_Q-V?o-Jw1 zeMFh~T+X6*GsqKUyunq7N50$ppqkvL+Q|w&F1Ti#ycMb*IgF3oU&<4xnR9d3wtMn* zW+_;@y@M0WJG0lZE(|^*o$X@2dfllwYcfYV>!p`9`3m) z+xRNWAzaRao1f##QNLpiX@}=VhXX-&|x`+Kzbxg?EsraLVMHaiHx#G7K85`A&F1!dvy&;pl_%2;J^Y`=5UUJ zAJk8XyCjHLE4P|bQJLA5QhN2!-jfZG^6*s=aaCy>e;5Qpq~K$|BA9tk`Kgs>k2j*i zPgGl-xDiz$zs1~#D@-18S^Kw1M|R&X_}ui!hc#?ssCj6}%VGZ}bk5cfyEnxsl?m*U zpS}JmfIY(&0a|k~ z7!{3W1fjx9RN4-kjM74xZ|5#|!!&n@6SF3^VzM=GmK<5`Ig;u&DL9>XBFA|GO|(b_MQCnzSfR+)E~vk*V(>)Pe`d? z2l|}q=Yq7+%Lj$0PRFeDSDb{bOF6U0#WNrqL10)x1+End(T#o zZ2+}z>XX_dJ1L-t$igcR+$0CZ4Z7awD_Yz~L4({o`czVlJ~P8;>3lvxA!HQyxK&zi zl6z-C{UIyet>dUpjZHE8&f+t9LkC}n<#Ncn+D$TyXfCvesIJ=wx@}Aoc}7?5Ax~iW z`U&C7podj1?pg{eoU{v3oc!cFZWq3l#^@eHVGZHjYbnKy96@(M{Z1KxC<6?Y??6DD zzI`38S^^EKvHadMJjZK%);sJJ6~v*?dSabHmC|A82buU5;^zxjVY{?8H);-6*7Hfbu zHQM~jjzJb%*x*BI_6<JojHt=VEYS6Bw+o%tF@vsilh?$(g}j&%tI0QkKzv?8V@6QyGWY(9jI&!VwXs(I@teNY=P($v$Z}fX9h6GgX{Ij|#)@D9p+PMyJaql}48(M|ZMtU3P znm}%68L7vgB8#^`B~y0**L&d9e9v@W*jQ&Mg@upmLG6#?ke%!j8bKt@7x?`X2t9hzCd z1*1W=<_IXet%%&NGp!_)9G8WuRRg@C;EBmk;UF`1n_r+(Pq$b%+fJ_V*e!?oB7^3= z)f>_!_tbOQKXuDESl4EF{#kr*_~guCE!xqb@SKiv(@Pr|>qQKOSLJUT2P9$?DA>>_ z@|?NmJ~jXc1Z6|0@4XjW$&EdRPX)0d)Ic_O3&8PdMxGPh{7;_i@yBdgd+U{6ROCF( zw|fTtevq}N%v~T&a!+f-j?iHTOZ4=%#is2ds3)pb0b9N4~&;>a2g@-D!1 zhJo_X28(+whY{pZ-CupGq2AVsw<&R4A^mEpcf>Xw14*8Qq-w!Z{ewKNEC#-JO za?*BIKHKReAFPts1Y6?-ntjs#s<(-*#M^~3QBMX?9$_>rJO?bIcBzLv1SJF_epHOY zhG}MnXE%<-vES|zuz3t+3X(rGSV#prc;&O`CQO-yYqJ2Y4rac;HqB8ab8%#GP_qkPQSiuabeY*gSEMO+9T;kD zGsj39%p`)1dz_WR2?|lPSFq&EouxSlMoC!dqgmgro%f%uGCfJZjxb8h{>D6UHIpg= z$uQ~i`(iV(L12V@q`?Ro^Lo>?ZhlIcVxuAueQDyZlkQeSGYZ%v|G;;QZ8o0|7g0YJ zVbPi&;Psp42lyFv;Zwy6pyclk%R@?R=)&-7yqJES#~+b;*Jr)SW7SUqgUG2gt zXObXKgb51C5YqDEF{5lVy`&BNZUfCx-)wbQ@v&y$rYt?J53en&f2|ml-o9n>u}l1k z29ZZY6+3hwmnWvC-grJq;T+5t3){;JoLL{GXmRt^n4|Y>EW6i;Dcnyxi?XujRC{el znAUYBCH5n5F^J8AX4Is1;_-6v~sZ(}WzlGF<}@oEjV9q$u@%Dhle zwaFaoOdgzYQ@SbYb8 zJ&4BCCY9~i5Zc!HEco0?R{f*WbfK~%I}IFPsupY;f6$*12vO7-AQ>)IP!h@^0xX`b z;JFg0$|oH}D75*v)WjLnZa;Oqo}2QAsM}eGs7|>xHBXMl_134f0erDN`pEH{8v(J1 z1EtIJ*(Ffv=dkNs8d$^N^X9N!@k*_#A^=UYp=AyuASaO1!&tp>p!vjD3mT*)Qa7Z5 zRSid^o%{JfMH5IloupwwfnvBnx@rpNg`)pu)+k7rl!1a50l!uB5uP)XH1fy6+5{*K z6mmnts$R2J*Y7zLkDBuE`zl~+wnBx`qKO}a<^Y`ys+tel7p06H2{wV5&9 z2g@A}g(%Frj>T8YPd#5rXV3+z{;pm#_L}Hk_x|P80PY*z!ql@aZ6|n>FE}46xEtOy zGip8*4Qj64KyC?23ppZw>=>_03U|;62H{J5($cgl{RA}Z(_$ZN;69fv+2Gd7v0aNU>88yelP3U( zgM(!Oc@}R$o^4-!0)T^19TZ=nNTKVwkAqN#1fcv>Bd?iJ`sx^k*>M%&2mNrVPcKwb z{H>r;M~4$qE&A7>^j-*4(usMUe0|lX4-`*2dGtY*f|VWTz+f7J$}M>V(2Drsr)oo( znCvr9vPc%Rqpf~Rbo_8Z;OV3eZiXr|$|Abro(4*G0}r0~Q2EJHbbC)cR$jszEZ%U= z1tqGK9BA_S6(uErEyY3!W`C9e(zh+H;eVQBP_dRrDSEDvGmG7OieQPO;B{vS~vL znRt4HGvWmwm6;0_O^<|V4xdYwyo1=frsyz>-x-0my`rmU059QoAva8_(Cy<}VF7vT z*P;?4V}osNl^34a=T1ax!ma_X#MsebZ0PC6&_ZtYkVsIan$sg4d*~ut*q)1QpDN=$ zJol^#g|EK2?s)}B{{*;KJznYil)8EjL?sV;HtMdBZQFfM#W*+-BQuzv`Kk9+h1`^W zm}6hP7C^K*(J~Ou!9>2i|0)I#Wms+ZeFEjF53(l!1NX5gU1;n%BYd3QI^D-Q>!n(V zm0)gHM9n=bJqfRNj*GRj?rtm$_wh5Ji`3YXVK)0Uh2VwSTn64WK4sg;6~pq9D)I5! zoexb|*t|Y@vomEr=>dhf?>x>hJb$X>@gnW~$GQz1YD4jy<8(EEWo)Cj-W+1YB)%I5 z#b`o?_Z_!>iqbn`@5Q~7>ogem^r@*E`>wuG5#xIa7AIki@Gp-H^}^n?c7`elgE%iV zKHrr|1em_G&v8haLr1K_b9d&wNj?JQ^rowTsM>}N@!tZ8Z-&gZdPXl(BV#|6dc$4A zXpiVIzebH4FxlU;X|C7G!BvZ-w6B|8H0n#Tp zwVyCbD?W^=8z>k%BGEp?b4D);N>9h1yuCyHqwASHY9H|<;#FLdya{%`@uB*t`f2UxxPce%0f$5FL4Od%g|hMUCgfTYK*VHd6hCt2S(vt1VUa z%H5i-^lY`;iY3Ft6 zPrT%QjlDI(Db1IHb|Uas!fr<6uTq@r2j$f7t$E$a-(PAux&>`Fa(4BW;Xqajku4ELhU|W2R-fB8Uwv_ByYHU+7dUnn_~Sp` z*0)N%*99t61q>?okoylSCS9P-c;?{U<2)W)Y>0ZsSOzk|y!HrCfj#D7zL{61`Hy18 zCIgdGYj?}n;#Vux@U7-J1_jISuGys6uS%?0%er?+@U-1_>+PYK>F4Ua)bg@qbHxJq zeTRI#KyK?nHu8YMNfF1RN@PX&3EDQm1ynfN2gqXSPIEcpl^IQ`2Yf_g5xWGH$J<5Q z$2l(>()ZllCLe^KE7Aiq^3m!v$F{9uVh4vM*YJLPtRkd2WY6hkfi7kA5>XwJaq8V_ z&EzYFv<;fMJ;czk=2m*qU#m+3wcmF$EN`Byi&>s(zHM| zXZXWM+g?+%zPrga{)F5${UO3P@nF~79pg&BiXO>iqxO13tP}fFJ{@j*unqv{5PcqR zAzoD*daGCL#gn5>LTUn=PI>NIK2 z+F_$d(5XXaz8rP<0IxPzZPZI8y5YBpR-pPG2cr!2mf3soe(9FLoDma#mPeEvp8AAw zj^-Lib?8SaWtDb~+zNdz$L5Ok8QN>st$kth9n_7^&cR6iy?095*jYRhXzja#SFklb z`w%W?&ce9PN9Ap_vJLq&!5@0Q|=5^IgKmg0A}FWv}lE4LNbT$ zE6k-c#l44u4oa_{ImR{K-La;R@8z|P!5Jk-=hivQ%%^LMixB~9HoZLrFPl!?SZqND zOGNndwRJaYJ^+=LtvkW+zf#7>ja-5-npT!&Gr#JPTfK4(SN-*Lq0#4z7u$}iyRmfF zK6er9zj53Z1baq}nz?H>t=XLU93Ch@f9n+fu?Xit>J$N__1=ufGx;lbj@*jI ztJD;;K8UgQi&HDNOs9v_R=uv+v5``a-J%S+-?$nUUzaj0k3CC9$uVO+t(J&9JJY~*bHg!j@m zBEN(8-8(!PS{6V<)x7=jm4QU(?Il-i!)UxWcxI?G39wS)pZTtQ!?$hAgPQ2N00r}-9{gd znTnBF3qc)~@KkwbbdPK!s#KCn)J~++$DJ?g)azm@SF4g$nxCoc z^eLtu=Y(3U7Ju8_q=cN-?36lPkpKQI+nNN)Q|54(YH)HuJ9?P9VlSYY0|dav5!H!Hoa1jSh^jJ#XTp%jwQ ziobG}oMV69%Ha}J>vRFJ7NE!I9nBuP>ND@??|8dE9DK1&QaavUUw`PfF<2CSnEm;6 zC6E8d-dBcI*>&9tZV*ITK|)eG6r@4AOG4?8PU%oVQV>Ksl}0IP6lo9%k(81UNdYM- zm5?~|Mt$Drd+U7H`F(!tX7795Yt1$1m}88ob|_^JTc-%NjxlisMk3rrq?8TP-NVYI z@n`!1qbL|OCOI^^sNYTPLpSAhX0JFs-6;GT+i@+cg4D9c9NZVjMtqy}1L}-HM(}kS zYX$hvXd&3Vgug5JsKqi5O{m~8xU<^+RPZ5^m#%bMBT@f66;i?5Mq{UEX?7my*1W~? zNvMmDDVAN=L~jUo_+3@oUT&_{e`sFdIhClE_Z#u(lr)gbe|o%x4hZ5=qDR(Iz!IKW z7))Q->^1xR78}l{?D~tT>^OIxfb{Z{&%cQNf+LDgf3H6WxXXkP?K7SKh`jKG`vD*k z1$F~XC0Nn?=)bX-2|vvTbTZ`?cu7RH6~BLp61%|FMfqa@rSSg)DF1r^8t;4Doxq$&r;LLx%+d+-5wHdFaxq7iEe&EOQitPW2=vdFV>uWs~w-!2z+zHOU)oU;X2 z)O}C)dnm4{3r%tdh!+G@6*M4l8P+w^h^BvE>*;9osip!!hE-nO0;qNGImO_f;y@|F zjd=EUA44;XUOmEtr$1#Js(OB2(0af>Amf^Ff>PO(fQ4e2YOjRWHrc9eyl-_ z?%^qe0)hxVsI)zPQg_79#o4uZ-yocj$5`69q51Hbxc5xf>wOYH>8c@YJ+T#8hZE&I z@F0V0YqolMR*zcF0cbpQyVPgYg=>npsbq5Hn_h_B)H5q}A1^-RgWgI#_LnZZ;ZIg{ zEk!%ideOtXJ>TsVTMLkO8>yU~!zQNRA&(rUiOr?SZ`xP>WZJ+Tke=^Xq^=vbMee^f z#kXb1t;$T^BlAL=Smw@~7OaN0S>E;(FxGGZTa6D+xu2llHqS=Cqwv;%{6IG)*Z(fh zz4=f#=|FjrqO-Ri=@=XcM{J%2vGeR>rotOiG_k*k<%|-SvvJXS5%KS1DVMB>)*Gsn zx@~9vw_Tt8B=6|lVG%Bg&nhqG3y!KK5n@K2b2$qg$-*cuI)x+hh-NJ_OOwv=x#s~t z8>llm$;5cm%=&{jbhCm>H;Wa*T-OY;wA#IMgP(IYWlbCKc=0wxGbulsvJ){1R89+c zhPidcJ#4oF#OCO)WGy&)>`*;{AGJ5wVCZ*@=cWHxG{9Gw7tDUnEy%W`V z0#pAqT8hOD=CSi-RePSypIJcO{Zr&)l0&fgn_nyOW=Y>OSez3m_9XTCP1n6tlKE8F zp0HGBy}dDE20(L8@KY8$td?KRz}AAI3J0vSC!s;t_ft14UyJiD?yMtM?<<@417jue z1K%D$dqlXO^uA}nE-i^>Ge>u8=*S>5wf&{bguv+8GEFyb%9DH(S)OSmnnecR$lE4O z({2r98a*>2bTpdQZQi6;zvwAfxb)eb z_YJ%AN+mGugAdXtxo81k+Ih-PA;Damlq7%3h{es=>nZa5$m~fEJgUH z9Vxp;E!6?57{JlZBtLeDnxgXsTXw^unPIW5J$Wgx-NTTh_7KZjAz6!4M$`7I5ImW9 z-#?!0V&AKVGibfg*fiG@?Cs|LE+RPvq=#5yRRM{Hof#Z5K^ODbC-;Ev(qHLltZN#| z@EKsKZ|x8F3pB#hy=A3@AK1)!zp6-afCrexFFJsPGhLwr{B($JEq4;EQ=+X(=frP~ z8)#l)K!JXg6ngBp%xhO)C94JkTkKjf@F5q2s`6)cFTBCEzBp3$^rdxQ))M0zpNBY4pT|Gn#9XD!i7zPky412|pNx6)A3r1# z`b$W~Wj4~l+QN6_gzGFle}gmc3faj`LCT78GjGYaG?y>WE|61h}OGnCnKK`qP+MgJoK+e4pGj$+%4KcX7R?yunZS zL(|~=jiT%E{MHMXiwxpFdC{g>edIY|w~EA2WsNp0A7yJRUK-PY=H=seRgd>RB(8w3 zC;iSm+2V(yUgjc58_kcUYW`6Ghph)mn8YsaW=c{AfXcR5rs6CVbM zu%jZ}0nm5XyJ@#)LW_%_6L!Pnle@MqkSepaON`3D^(%EE)jEY^U0IY(y2u@bdBpMc z7TPK&z(!xUK~0`%_dpadZ=*ZVE%*$=LIlD6SP>?|$LBavC$TMhZ?7HjTuy*Z2pT=>!J1JED4ZG#WNCUh4X+W{dXRR1PB z`3N~}S;LnPNsx_o_3s;NwGdNU+3EJDLWpS%!)WBuE)^|;yk7xK&Z8ei80cL*1IjLK zWLE8bQLf;N?uZ{7K200~^?sUr8M&`6`oOM>fkeX4GSyvcaiYE! z=|4n>Z1RVEM`Z6{Lg5_dmmzHh@5t@`9gvU5aJ(9M6D`+n>lCEq*04KIp$pq!uBdXt zMd&>rDjmm=_RBurOx;|9zEDhfLzH{SWt>R$r?P_eB!+J4$NGK%eWI_49SnZz?Ck^L z#An(Mpsp^Cst$hr!qLx540tk-;)K88szNM$XBUj55i3ATlTRF%beI4y_o{}H5;-v3y1zpczT58*eSaDN=-N*p{$ zv|!?L8v$v$M0B?<+c26bV4 zzivIF`|_Pn=CLZzpy?ZN*|it^9;PNt-%mhvSiQ_FW8F6g+r~4DcEU}3lY)3(qXy+s z?#CL0;fs$Y>Zq-gwEn>l=jsI>2zylAHi^KOKTy z(VUmhRM-}3>$AUgzPLs1YyFR~5o4`y9PGCM_Z)Xo%EJ7UyXOe7Vx>YTDOmFx@rd^k zpN7l_RICWg&@Mda1lcs=)MT;AlIdUif&i=h4O(?kE=gHFmgXmPlmro^?2UxHRib$c81 z-@Wl22yLwAa1`Q$PyqhorEI07sl+#Q`>&*w)|*Ao5PR>9!RJ1G#3d1i{(V{x=8rRR zo3VuZ_Sa}-(%)A6u$%J^!vrekotAH0C=F?G;b@yV4W8DTh!g&on;yKDRBGdbIj#WgS5z5%u$D;@6h0H$J!--&gC08?AD1JBw^sA>C+MTPA0O~1|@ z&oA$rhH|!!u6q55o2d7yRTjz?LHZi(NWhobc|Vv(I6B4w1V=_AShTWslU`zaMU zGck3#7X0%j17Ib=Ue`C>_*9^kxu@@GYV%7M=OuFOk4TR6_`l{z)p|3OF7h_rz!j#B zCi$S;k9B=kijRnNuGwU4BO_jEtVI1=B1D&+za6T7cNa7CG&2Yh=9_e1d?e05?P7~Z z;m5+i2Y>ZbbdF3F5~vbox;E{T+o<(^R=7M7jg8|9pe7!xsKbj?IA`|?{Wyb{Ie&4e zZ5NbOi+qL}OU{rSRMB&iL%`-v>Nr)?f;~0SmBza)uSz( z+|LG?>3-(FOPq1Nc|o7*>BB=^h}4tALT|HE_#7%+oEL3YwIanwtVouJW)tTxz+=i8 z|K}9`6;W!EUwEdjcLhSK2Q}!t=*R#_Vb9-vCmV~Tg^9QYVVM?}nWC#Jb$SzeZ`H}H zUE;{mtNz0KsIgV#V~)hNesy|Mgy^6ha{uEe`kYD%&^>e>)q z`Q=_t>vcBL`rwVqB-nIcZ2o5?H==tTJZ4mX_Z{NclkKCxnvK*I3QG?6fVpZ~&n+ve zIC48|g6%)o2(RM5w4m(IbjMU1LyP(|oVdu$@Aka;$ln<)7o8mAW`bB?ya};HztE~{ z2-yfp|9K<)sZ?6ELBtVXY*>4@$cm`LW>$+W@qW*T2Y6`SuOReyK%Q``tT?cXf(44E zTFL*s;yt$FEvN^>-7^J1M^GNCuv@4|Q((>w*Do?464Iv@LamPm;BYd-KNhyu;Bh-X zvxg-={hyW`>KjG3#S9693G z*S+Sx@2Y*P>PHfjHcbr|V8u#~?QM|w7vfC_oES3Aj1QBNvwPuz>T;|wOPo)gujJ|L zb)1xmWJ8k1NxD|Z`>D!)?ZQ#`%=rug4idd;0k@ZYc2a(Vix7UxD{oXZB`z8AO~m*& zTKBGIy^V)>XTYuge61C$fvVv7#TVoRH^?3nn?M~(ncphOmKaO$E{IG*LDHxb*Jb({ zw=CF=wbjZrS6lz!i=cxqt~SrQJ{d;neO2p*f+a7_b8c>?HweBUh&{*H4IK%?OCKrY zAFVwMcI{i?4KQ91V7>bqwSI2(hHP$3j`L5yOm_Xd&JBjgLwS%`695`Z?T%tkI7G5C3|mfBqzR6kLo`da?ogzj_k# z%B-)GNKanE0nEMLy;!U+>z>auH_+ut39~E#D%@N3zLSi8CDtW-OJ|a=J60y~2Bh1b zXdBsmpDASlcYNY}cXB6^{EM3N4Jco!rh<##vwEex6DhPFs-LtII*qcAc!=KGaqH}A zwc)RgS3qgoevEtS{rWRo95(?rnI{}zB18q0V+cKUYw935#HmHj62px0@-qcgyJ8v;o4DPV z1~IFlXjj?WUb}>J7c&#lfHG|HT7m3(*`K!q!1Z5mr;LY!Q$HgR3I!EJpt8q$cQgR` zv#m4Yb}v~`?K73YF=)Nxr2C_R6-$%!)h{Ci@xEC_h^{@AG;oo|%9WE7a5YWec%k)5 zZQ{aM)lkQsxgB&iV#;W2R6>2P5e*me>w&719WjilBU*+b=mZpSBY+o z+s@UwdP|%$RsRU}q19E#0>*1;_7&S?4>2el$y~I8uXEfrKtl5F{9V9l?z9|7mn_R7 zd+;8V&Ww9(i5RhxiTTt~La@>DN+&Bh(C#ZFdi1EtK)^kWN*lTQ8!(~>y(dLX_bvvD z3xqjZ;0zIl7OLJ3#YlW`p)Bu{+kna(=-W$I>K`21C^EqJy6VUd{`I{czcOEiGyYB_ zlN}^rGfZ;(Lo}@#1G+B5`5RAcX0Yjh2OOo5d*^De1Q-)$jiCyqbNR+&8gRsL$$8`v zi(xkXysWb{1;j@E8}VAcJ957uFIyKDTJYjvm~x%C^=EaR{kgtWE2~KdTz}YgJpomnFk?&h!RfP+NtE-JHhdrkcW;q1s(8 zifL1yj^On29E(4D;E1AWyPH1eS|OG-d=aOXg{HLud=V!GaiJ3ZPIVYSeATY`q?qS^ zJyD&LtvvQ$@BLMeWyQ%GY}&a(6Q7DJ^w}0t{V~+#m#K>kByMhfP~M8IEPnUW^iL=c zfE}Vt_3rq34(hsd$m#gTHoo zDR3eF>~NJAdX3g|bzJOpGB4rr=rlT?`-}IrJT>vk`+m1$V~- z#FmpD^-wet!LN2nZpyCT+X`7EWxe237?Ex8euph-hR*IBB}N$RQeIMj4aLShH)jD zJ6{G|7w{INCmm2?F7ihoZ~lT&ZM2p_K*b-No!8!sFUAgj8U-So?eqvlm75ppet{+< z+_=afr9Fb2R}m4D-+{-_eD`_ak|PmBu}nT!aNQ{XTC@CoPUStpIw2Z$o9~kp<>HR=n#dyF;=ONU_1f>BI2_x{I&RS=n&v4 zR$yI53C<@;4Q&H|boDdhF&STnO@`h;H`Tdw4Tl=J^k1$p55pytBx1@S#D%7B^#XZW z1)8bS4!&F6{Mm-J9{n}$%jE|Le*-w_0Qw388no&YC08(cv-`ZvTUQp5J;ugOIM7z2 zRcz#I^VM;(p`O0S*`e+#DEB|Z_s2u_J58fp0N3*CD{CHR(Y89N{nr7;Fl20P*b@1w&19AP>faJEl}IxbHp&=NJUH zEFUoq!w&lbD5V;7cxKv2wDe4CU`m599dUdan8ao+XuprpyUyF zunKS=LV2K6pjBkPG??!KT)TH*-LrfcWZwwjyJ~|o<`J+Ped{b zKQ}LuKLBJ3Cs?N1+TYe~-j#iwyOECBk6f!ZBj6v*Kd6#ENbnwsbGE_P`!-A-T$tzf zA;6M9otwD6g^)C#o~GrU^gXJN^`DY5LWt*bR8?=b>EB|IW!-oWN)vwP3#^-5 z&R{-MgMp@tlvTQ z5ALfV@|B4CLM(|tx;)v~*jWRl++i1o@U+_gEgBpkNfM{I0*$7tPA~7m(^omaCd^Dp0sGGjid}F%-V}Ko6kDNx z2IWnDWJ6O7Q7$9 z!L}Z>pdGc>iI_4I*)Dw9uegc0$0ATtgv@C&d#8D!Nwjh0VGFLZnTrd*3IGmp&OH@OM%T`BKyB2$R8*$k3~WX0`0gv#Z=|@umj| z_tPPT^LG%ZMn#SA4Cg`TVT4y$B77ah*d3_8fHpBJJl94v#Cy(}Ax^{3+hAlB~ zlh;Fw1AJOY>3S`7i`Ng#b>5A?AoGM5oj9N>T%-_i?Xkq#M7`lIj{ADtJZcU<>KVAW zS2sO(A=}qz3GEK@k1%U{N?fWWpYW`UGlE zq{cOCWUEPWl=)V(u8=k^gue#o{*{?j@_RqdmPQ8MW39W8bAj!kPs`rCL$U}B88;w@Hp>Bh?9;5#vrcL zt6^QM3!ZOIB~u0d6#RaYXb?EvcVNF>kO(+06{CYCUbo91wa|hea`oB6F)P)RK>Jo2 z$EJ&-;r=-;74E{)uNfgwc8cbGw4O~n$@eXDq5NCH7u64m3Aj1}m|LekziCb63hOul&f2yV9uVq{*`UD!V>zwwa_G4!v;_iQb5Gv|LKC-5^xY-@qu&9YG_Oq5Y z%Hq%Sdxv2_V*96t%h4?|j+zbRmZ=>neO{)|rp>b-^D^=2`9SK`z3!$PaGEMF&NK)_KM3CfU9 zct*lT0@{l~R$Iv6@`Y99-$Onx4y&O2`on0UM+TiI5IhG*^?x{s0Z@AbGV}5W;vPKn zJoF9t?{@;~R8oa*$c$Ia(z0BCKC}Q0QRg`Y%2**#JtbU^#h2R{n#`?gm$V@?=<mQ;b z?>O5WJdIa6J!t!V`l*d~;iF6MH4& ztt5n0j(;1CM^Ssn@}#uyoBPU(KiocKzLvmzVz*-z($O{1oFM$gEoh3yfIe!h{_&Kg zr`r@;BO$Y6GeJ3(DSEz%!V;zrn{digF*3fm6Z>D zD5A11^B9w&5dCk(t?M%aW92!V{5U0y7SYSskV;ac^u`rO$qw2k^Tlc-?+qEj>HEay zgL&!^_oecp{cmo?>lQ;k{5pCaB()>=D$eVQI$#n8k2C^LB7#S%zdGO&mDHEff%h=? zr1CZ_;ZaXu8G@dVE|*5INg@9yrpg%q&dW>p&MaNY$iDj7+*&=EL*POHS+ z6_Lk%+*e4@a|Q1^CCOcE^Cw~D#2p4YD^V&7MVKvo%IhpayU@rt;1Keq|5-%4!+xgy z$5yakp@`$PH>AeC^S97*N&EO7-?9C4G9Z$@CY(~R|DMbf8EoSOPPz5nt9+&MXr%Ty ze2v@7!`Gny#VH8d$Crhm)+|AA^0 zdQ3(_ZB$qE>Irm<`b50B9sO-Dq;hBpZ|AqrHt^lB@N9Xfm?@nhs8SdEJ?89*4-d2C+hmKO-X(_($?1TDQ5hq)DAQ5Y+!1sh41c5v-7CiB zAAcYHGn{WsUS_@NyUeEIgb97bbk0b^gaIzn)Cx&y%fDEahCY{T1$brA(J} zkk`S;TQqta%NmI-=uS%ukY!z~^uO+<&f09L6Cyx%PnE#b5#4=ra8T1zH6d9uXvgE^ zoX}uzrQ@U#_==NMLqh)<3LQ`P?fq~J%xr=E2(v3N-eqa*^G|ee*m%TNZ{o^oadn@w zikUcTBK0camqB21%4K+t*)Yjs4tp7vWFb89c96na4c_=)i*-+=~qU>Z9Q zb1xcku~~#*Tl`W~cPej+*)ni|0l( zbq5tP-ic|mh4>m4(_JT}Xi?e*dKYC0>hSY=?u%6ILAOt+SMN znD@~+(WJl#@c)xSu(16aC<3%Er?;nF;OmLK!|OD@mz##Wvoq{K+~^D;q#u9B3eD(^ zk2(=gsq(EFVJg`;HV>r?S*wh)^Yb%rc{e>C#E`4L@}IJ*_Yghp&03N9-74E-Wi43z zy#Jq0Odqfdkxon*T?P_FbmGISocT7K3#oXkyr*MITsC>tdbTXLF8BsI;R5VoaUDP+ zCC@`XG0ItRmAX`wzInQ5ah_hB9jkrMMfs-qI^+{S7WbawioS1l2R<1NnR^4DqA?;Y zLHvRdyra5{E9~JPGTU}j7QhSRpXBO!@4EW%%h4JEd(5HvX2$Fv;ce{Pic3e3fTUC9 zCl6Pv(~$sw%g&F5TJ>p4;hQqt>1YkuQCX zPjHySX)gGcYsW-_;P7awaiba3Z!8ytJ=`4C1^W9GtG@MRf6r}@iRD4H+!Hee>Tpny zB+`lCr$M$d;r~QiFZu|h@Jun(8$sYYt~<5AzL5&|rUsx`C$W9~ksQNzhlsf&cug)M zO!*Rni1+>jdwYRE>I5so*QNoH1RImy&T&`X&@QsGA{l^Z4*x>9tH&+?E^J6T;z$t? zgvOnMD+>K?xi^ArlryRq_!lxTHVu@<6bJ1g6rAAu< zXhL7a$>=Wf_;hb)f=fzgVqfQubWiG>h^JfG$K&ozG=r-AaM9s6b4*Wr;mGk8V1CUTIY^wUfNNHW{=gO7psQ?@U%=An5CEMTifT2`g z`&I9*1yDIVQKM#>C84M8VSI{#qD$^J^Q7O@i*@UixdWK!XYkYeR-C=C;|cOhlI_w1 z_|)6ej^0JrrPg)NN3Aa4qFJzhNgPt5Xl##1)^T`&f*=oiLdym z6h07v+UK|jyT!o=JlTK7T{T&W7@8)byHELUe#OD39jW)@+TDQrVlmB9IsH_az?tOq zbOB|PTyP=R=n>)&w|Sx63R0dnic}c$r@kGi3dy=;kdSka89oUrF5i5kzwMF>Ok8m> zw!pPoD|^h(v{HXl!cw~iZllM=2_L*Z5c~-(^S=M4qYyf21f_Zp)$dY0#ZYxVt-A^& z>kY{8Lzt1L=!n>%br|Ob=JMnMz03t<;5FTe=8pp5cjm@f1L@P_8Pz79;3`0D=P7R+4*UhxvU-U$nKUx5E7^BpmVwtR>4Sr|S?NV{e5Wvf~05Q^`HsxsuKD z@VpU2B>VPV!3NsO=%4ZQMi!E`wg}8i;(&qelFQ!h2E2KknptyCrNNw5` ztVn`R;CP7pS#X)s^jd;1&}bc8NsWihuW&p|?-Jccj4Ap74mjo{!mP}A5)M5c8i~{c z1*X)CY$bK&wWlaXP7-`+H}$s{{k{c56+JCPf&G`xc9i)wtx=r>Wi$7y<{oC$wI`uP z=1&#~GlhX=;BA}P$}&oi7o=$A*B%o)>a6=4F4ARux2n<8Tho=w_}#-yKKeI>v>H8J zTelR8sK7Ac`%#v6%tWg4KakHGGS1yCGbY-HrYePlr z9lkeh`*FBp7Al>8A~(FI|JFy^75mYEGALLK^SZ~t5G0)?A8M|AV1Xr*9djowE94=8 z2G11sImIVxnfprQ&&)Yhva$qm&xS@xbH_37rcLhoF8C}=d|ek___Q$LI^nsxP9Crdm)LbFMQ-<^ob+l-R+m`s_#NH`wP3i zEj;|59v`N^A3h~_7Kx`=BWH)oiR0sy`cg*Rtqv^bOc!oGA^*&@lNLs^$7}at@KJ+y zP3*wEFf(o{tT0XPnK&M{D+kr42Uc@4Byhl-!$L-hS4ztT z)pe`o!#U9B3MUH<2&YE+5IO=EhuTT8>&<)Bh@?q!-69RoB#7{+?1Nq$9 z?oh*R?SjOmxxJ9?Y5_7c+Q@j!wYz zX+k&-8!5$GN-`qt#)Y0#HZU;`LM~GmD2E?xdLXbp;!y&@!2;-#SlRSFsVkKG0&+~e zA7_LvX>N7gCFMnbd}vU1_`*fzLT}3K@sHBVA|@1oD;xyVxZcw!geSI$maJMcP{6Fmwh?7hufp57g~q&)TJ!Dl4#>uZ@4&k zsxz}QN2I9~8mRBwG&}S~v8(>zk@gqQ5z{U_Dl|CDr6`k2xPSfqi-u4sztp@!gP9Y| zucrd`+b|Rnx)G4FE@`U>yvqh72*m_Legf}DxZG5)=4971m*F>pqVkmVczm5@9ISs-1fFB*%F1WZM0E;*8UWXzWe9b?9=G1-Vdo0PeDBt1h!gK z44hz97@NSMuNX?i@C-6^jWSai-B!gqt2B_KG6!s>DA=IwfDzLn zQ``_zvkO>bbRvvJ#K67KpjyM|?ji$=af3IXV>Im?PID`(B zz-h<|e>1ito~xy!+|&jp$11-%W9xsLc)pki5CtT!GVdV!~g z-JsTvGxUkZ?r{BB6*((Mt-Tw7-ZvVt}IfNF6ttEx@J{ak%XW<0k&V*}_ z^6c}sAAz|j18jwOAc5*7uXRP~|W+qMu7u?7-~~Sl-gJ$hd5%mG)lxT$*$T@FBx9 z$=OfM-^Gv*!{9f?GW6h(SYGfJ4#7uXS&;T-_prl;1G?~`X0U>+>Dq;61Kx|@{X?)K zM)E9X-*mLLamfYm9DD`Kq;G4J#$OwLLJgUq&jX__c3?DL>fwb(FR)SKiN&KcCTMa5 zuTIMbiT#Y9(4gqHyehv7)SmcfKa+SkTpyF91IVCtxB&;^YAumlc*M$%#A@YJP_l5bznwhLbaZ zdyi_uDP+vuJ{Z{5+`fq=st9IevyR~u{0T5~S%nio@=wU;Qia_6`LPfikHdPJfXP?4 z^t)vn;qusHoP~mF@DL`}CeeTX^xP!fSgR+@?Rn|ArTLsU4S0k zHVAS|HvFy1j2nIW!TRJfYx&+y|FBAVgscGd?bjR}$NEwoX_oVcxC3h34>0Dy2^X1s{k!n(**HmacI0|kA#aB!pZy5U14@?=cB49-<%Mg4 zb7#B9hx0Y%mWE3%(abX&qiq;h*v9W^)!%jZPXjwux&rA_WCnxdQlump(ASN${8%6S zXbn7nGiNhIC+w;%)}fHo%hxJ;lF&0{Tyhm0h-}w@`}M+PCH~7Js;fc;5oruNrQhN7 z^k2nh=9j?MG@wAI?>Ou8M+}Ys=`dyE&(r z5zTSx9ooB7WtfB|+9hcsunQHvqw?R{T*+&dYooY}C`33)ByJr6EuhE|b0627e4*y) znNwk?!Lg?=Pd)Y=oNdNq=Pn)n4&tQ`E)?df666xk)`L&zZo`eOOG>1Z=a@|!fY9W>wBk&%VOc-KXG z?%fxb-HO#;sZrEFufSx)`1kWcv^(d!e3ytwszD|+#BaFEE24S(aEorIY8mbDrs(G( z@%1v3PmSxit99;Ow^0vG58qO`o3HI6gtdcm!%Bnim)^fXF$ z2!6{H?E6%X4W+lKL~fUI%9n*+m^CqZ6q}_s5!~G+_}#?yc8_MM8eZbZP|ad9ySOu zc?cYf{z?q%5qdvoNq zuH@k2V;ZSUS$@CzRvw!Rljdc=R;D0YqS13d38DmB@0}2kIdwexeYmFypR5~7D%)-$ zEC&f(_r=##KiT)YjRPZp;;8imtsKB_D)5p}8w+ybUh|k4SG7cMlFJ_flgRiHvp#>7 z!rj!(79#KQSif@0@jkzKrX57RBPvyj|BTA>@(#9Wh_EW<7$nx`=m+PXviDqDpS(Sb zYxsIfMb=@@B`qMRmeobrxkH%sRffRG zw{=Uw2Sv@qwtG#jW7(XMz&ozj&)h8X)DM%4InNGarFDrh=gH<2LDzCZ@0Dv!R#+i| zK58FgW2flZB7-o0luezoFcHKSWbPYG|yMM?OolMC3!*9IQ2qqeSq-P4yjz@x(Hoz*xjuZ zQvY2h)u@HKJQCZ&@O7Lmd@}14>-z(-YR!>X37IFGSX7wBs)33YcR8?d_WH%~oG?wh zQf#V=0t@eyN4g%;8>%}DLo@s8F1GtldoX=q+AzyC=EobVhHtD;9S_vV?<))QE$>k* zEtb)a(CKFOUB@cXnQtOB{H_l^UTs?46hU58n?c$DCIJ2^@6w-7~wc<9R=zNOu=tihWXYe=`+pDqmQ866IvT)-xw}tCrCFl;4xnQZy$C zZi=l9oICyNT|ndX@3q%w#)V1yk3@gKU}?tUKI)*SL5&l=iDD>g3gq>UqMkqo#Gk= zg|X{d5-ZzBQ^JA$XBp67rOI6t)&)btk$N<$OyvVExC?>Pa6?vZY_Bu^@N2bL&C zEOs^y)XWxh{TQUZ_#Yg#I6ti`1c(7yi;(iIHA>9uLYB7A}`zU5Wr0XJ1jo+go?WpnbYF7)$Is#mO81j+O zCz?Ge&XUR~UAWnI=gH4@BsQ$#MKOYnV)T;jdg(N zEE=C^p~3qNvfY3-(7`5K^kvDoyuoJr669L-c@Zj*_e$ALWH*MM->`sGhWqC06ZzNk zV-E31g^LVpwE*>fnkbDhG(#_QK6oN}uf~XO2(ngx2ZN*vmpR2dFskd@yk5!o#Q`|3 zHSTuxYRll%mH>=DIaaMgW~B1!%ytSaY>em7*Sb^}Aj(bv8FTjb*+=KOB%v6{b=0&S z%*(7a@xpCv&UOKF|7bw#Rew%veN1VXjySoGchCqHtqAM%J5dA7L6g1ITm%1Oum_4h zeMih-jw;j{pQqG^hrrvzo=_}3f9@rg>5LushFnI5;CWwsjTgvXQtBq(uIC6`qtYBo z`e*Fm&0cqhAa~~=O4<)OZceuq>oO`+AieC@H`>^OT-!GFCs3Ujphwmi;}x|7{nI6m z5}=r?Wku+lk#ZX3wd{h|W;|rwtp2jWpV-8jI9@})IwQu2z>;92KU>La^pTz$I|``; zb?-zuKB@(H@U%TpjNsAi2`c39o=V^611$nG9mc&oGCYO(94C%X)FP$;Y?MTYor|s1EvIzXfDk%w z=c3+9c>mlpaSns$Iqq#YQkt0pdui_jnrLQM`?Ymy$fQ3_g;nBN z-&QIGpvR7dXu{yc6`ql1QnwGdd&(LvhZ<;t%EK7@CrnMqjOQ~K zgs!_c_hc(2YKY!NiRC)(Ty>JPiI7`S_nEa=heAdD-hiJB1~~}_GET0cwOwI7@aE@l z{yY|C(li5NZ;=pHg)#cCNX;)m?xxgXBT)5R{P5<~%u;=(@$cL`V ze+!c{fn#pwE?ago=i~-MNG}1~6hTcq7*GGnNx$4& zfkPV^-|a@v$rqa?i%eq%bM0>x0WP^(t%? zAXonkT^KEH+|5V*!iQcdEB;PDd z*XcwIJHE&olhD@_@A{gXD{s$Q?bY<00IIg@F$keS|dJ z3Lz#eF5m49bgJn*+sn{k@1&S*DPIUZL6IKtxlYgBe%)8M&6)NVC%z1X=h@;0DPK_ry0kF298m2RM#sL7aG5vXBvU{ zrucLboA@cW12t`)!xh5aBk*Js>>b|6P{bALTmj$zEU7>HIxEclD?MPX`qEu#@`N`5 zXeG@rlgUVd8J-{{>ID&D2M=*b%Qg0znjIN2HuJ35yUZ(0Nm;cwNOB`n=- z17)4aAN*EiGl<>>)#&8(O5HTz7`{%bn(I0Pzq04CNe(jsy2O>8YCJh;tT1;9|3Dv%)>}$-)qt&hp4p`GK$y4x%pJn1Z+-wcydmpZEeM{;V0qRBP zm^V&j>h~@Re`Vid9prdlwS&L>P#$?rQz7Ac$mMNM>1vLJT;A>Mn#2Tfd8egxo)L|( z{nnF(Z~ZEC!T$uswUh4&umb+T#{?@lQXc@qVP^Vgn6A|4g-b*iH!m9D&DmJZp2lhq zfT*1G0;%6)5O34IZW|E4f(oGdg9@X5zKMdog|OqF;qM-}A6t8x&TwIEgwC=Ek)b!b z^51F@d@y)+Yy$7Dqmsr#I-z&+JXz53qPv}pgtw@~?;SI9?Kx_4>&ipd_1FNDl$Dpe zB)QhlB02s7R=J@=^cRc}A2v8br-pphIe#2J^V4t5$!~8+zn<3@nT>HP;Qrm@_#tw9 zhy9mdi0$%FHTZRm4*Ws}KDRPHkw1-tCcgjGv2vV=AS@LS#2g%C`LhF@y$b&+@ztpw z5twf$K(wh<6}$&m5En6DPLaw8kRGgLR4Yn0VFnwXB!8GRKtLN{L1>E<5%yA zZOr|CrEi0jCkMo{ra(z?>a)9Zanu5Fhx~}J7jLz%l$kaLQcmH0R zl)R0n=bIMFxZm-JA9rQQ#bdfL;GHAo!9y|Rl|S1_E%wk$>E|t%S=RpD&FPbM-R}Eu z4ZYy=Eo~3tI|)WimvdTKUS%r0H2LdD{Bwo%f8A&g|3ratDv%)(%3RFHmzH*Fk>#Ku z)#Buf5ahlOhY`n23rX)`LYGO6UOJED6oBNF3pC*~HpS=Bou#LcX3BeZ@5ysAX7-)E zoXFql{vGVtx&9XHF5}7O3qQL0A=ioUHcTS;46YA};03M;8abn?z>n5&4@Gfdl}_>& zrYKDrJhDMeT1YEvuRwgqWh3=^aFVn-ymb-o1;U$+ zb~=KIw`QZw=RK{XyB=J?SvN=%3abysOCb38Sxg;<7Ce zS^fS}Sgg!NRSsbr9YN28Rw-iSgKY)K2brwXF>pxQp}OTj=F5nH8%w$Ot_xDhcxt`? ze0p(`RlAtdE#&Fr$qIo)Nx|)O;nt+z=MDktR;+ z5Oge(=%mj49{r^*gvt6}mXLjX8BZE{HxfVnq#Z}gW$*;1{MxY&p<_Vb8b*q5`vk%6 zscui9-2rOAVuQ(BR_hb=+ZeRwzWi`8Gyh)wSN~=8AIjy|LJy|gX<-T^iC z|NnS(RbP$Z}Qd%mjM zoBQLw-|z45U-#WP*L9uO^?E&@kM;C^hPbp7_fPF+llLgL>V&A7lNTXH()Mk!rtcbv zteZ$#jChd9wI5=*#4faR5cWL;WZY_0Ip1Yz<=VErfB=lQB@007@IdHX`6;L>cY*Dq zb9R}{EBYM0!*$X`$iPyj1^tli41nz#_T`hiWMCHVD9T`ixw0C@D~?gspr7PnhkV>* z2M{t|1crzMRF+^mb7)xdxeH|o;A*b>TbWwOb#EuuseeXVbjhvZ8`aXjJ z?gE$$x2Fcvu-|V5^?x=T+vgV?snezc%qC5oh9UzqAvGD}<%0bj&+Wbd6{-(bU^ z*AmiL07p+m`(+v<{MboX3^Ft57T~2=cl5z^o(0J*9sd)a_JL!iSg8vFrCirN zpdVTj7k_{cokE0bvOD(%3MtdNkw?-&IKR4i!6g_GHN`XL-EDRvF)Vp?De43S&%Z^h(ag;I%y#UM0os5|%M zWv2k@Rd`kTkWaleRq_0N{l_A}rJha%x1j+db74YAsEJbmX(Om_L?BM9Q%yTj%yJZ- zWdb;(&VGjAwQ62TXKq%pk0$U~w(?Z_L=`xT9CO_dgRv5}&Q2Eo#s6P4Sm*z*qMh=1$3k53oXJBu5nCdei5?0^oFSzkU;E0;`J^ji>b3u?H~HWOuqd1 zJfsgfbM`z8G&J(9avp28W%HUtP)cD$2m^Z*F2iCRoSI{#BupdGN5p|Lf1 zcE#=q^(st+83hzc&l_BkCj+9MvKmDDy)>tm5OUU0=!T@UeY_<}OFH)q1rTk`Ksf&_ z_@>Ln2jTl8aL=xX9#6PAp-N(VZT%*)thJ}hi=YlR<+y%AibCPTF3CK-hi6WQ?bWi^ zaiJxGj$gkF_}2q1QO+D3m&2TILigMPF==sXS9HarXtK*zDwQ#0a5oK@$~~v=Pgv=9 zPta|b5Ddp92J<7PE^^$B9g(&iT^6`09;pZUe6fPUoCbA@Ht!7crHpR{`W z(1Bei2khLWehH3&H^B}@)+h!c78Fz zpjqusL>3n_uYlYvt|5Y*YLz?LJm#|cl{MI4;$duwZkUUGm3m+JRaynf)`0$z(WI1- zu`AbT3nzG9^1Or4n8TGM+`e<#olSjo;el`;P2j4|lYDC3d8oxbe?N=EE*&$B6rr1o z-_Xe19Z)DA4Ld0L`om5<>jUs*CiOLj9YkVyGe<0M$SAuR-w#tOzwi6u%z2@-aRk4e z-Z+BI%FUt(;216IJ;?D=3B6OenV>^6%EeCCB1){c5|lwOd-L7=)S4uCAW*g(@>}6D zA2V9~@Ye}$`Bza0$KuZlmX$oC`}R;@viefO9z&kFl_O4 zy_SX`=w0@$pQw1%+;MAF%F#zyhxRxlWg%U)P*WV_3a`y=Z#zY0?84^SgEXg-CcM>xOh%`t9 z94D~bF^O4!;B(3!eD9#j+jJ)E1blmJZ%BRg%_BR=tcunj^#X6T&noQoomc+rUQcU& zoM9=S6_EP6YFilfN2pRwv0Akz>$zo`iqBwIH``2h=pn?b%UpU%LRo;m(>UV3o9=n>oqq=>sUORszdYFHe1yFbXQWiLnC{ml0&6&cVB6vAawR)I|LHeT= z#V9=Y$58B=Y;L-ES3@8qtF!OL-pB| zl6j-KiKZ*e#*ETGZN79QiaR6*axI}iA8#*ovo=G2=LWsm-~J9f=kGszE%7W4jacx@ z&MupnrXJT5xnmss^xArVp?QjA4Q%HLiQ*TuKx%-h71N^`OG1W)sv=d(&I@oDe*N?f z1U)Sf5hQ$buYUIBXW&Je%t4&PS16grA2`>AZta5oPpLM3_sPR(nDma>7KaI7`A6aK zZkM9{wMfRQSM3{KMxZo|H;y@`4r9WYMj)a?O3$UH2bF-X!xLHp9;X?5+rxYpPAfT`X zO-uuE9*Q*3Ob|KOeFyR_KeCsBc3%T7)e;-cn{>IO50H9(lpr<@Ov(C`xS9902VAIQ zz0gD~ROayvVyAZ43_^UdJ2;IqPh@F*g;SxKKfx&WK|lDFV(bJb++gt2Yms8e>NC6p zA-pKga*o{MJ1VVEfW$mh8+n!Qo;v7Pp~=B$C|MRfu|m6dk|ma_%L`qP&K(39;Q7o` zxhKRxw2N{cUhnGlhR8oG44ukQRg@}AF>qsBMmiUCT*`ob$#QG}TSwVwb9u zKX=CAh*$)t0=p|x28immjEd!!z1qKa7_U!1HkSWx0}sHEZ5ax}CTI@QB$YnIpS6#f z|MU)xD|_IR>fF3LKxz*}jKrH!+=j0B25K`{WLB1bB!FO#(h)_Zk%p7YiQ*mVo~ed0 zpaQ(c1?O;hrq*kV0r-+VNP55Q*K5zJ-+b{E&izEAXg1`c2*e6<$`=&FV`pGc(_wg$ z`xjtI#P#~mK@)f!#hLFRd}RE*98m<6Ly%UH(pCb)r<&lX7Qz33A}tm~-q;HFZ*gGD zXkbt31EI&=%G>wOK7GWX5f_OZ|5~asH66#>6?<>(H;=2v?1N=+M#m$NAr(H&s5wFO z@lGz^MuXMh`bIQbwc$EjA@J2QASdj$x_&+find;!>cow zP$(QnlGgREUeaz)J|_uxICZqSkgZ7v{6f2ta1BigAlh*!!PmWh5{k5*pf@nE)%E?$ z+>-+5QsRUR#lmrzR&)R06NwOja+-xCbPO7hZNwHc1%A1PMcHQIy(U}9&Yp*X2xZ&{&;I6D!kMStXWY%^bg|_wGp;bNH8J*A<3S4WZZ$<4eca^b^=(P?mz)t zPMw6PjAEpLoJpsDYrYh7D8JS*B|lRedwxX&9iAgFzVNDzqL3I88;vrPc*0v0H(VcX z6U;u(i@ALRH_o5HU863^8MvK>Z3dDgl+b9&wkw!!&-vx~cMgjUgx^;e781^;Vt23Wm}o#aGufdSpurX*I&kq3x zb0^-tX-s`4rYywH8tdb^HdNv6G7vhw@P1MdTh%`tSn7YTmR!gc&5*3&!oUduvflT{ zQx&}DgvsV9TtD|4vat9BL{;$}`SQ50ahRk4!_jb9bL)1o#lf|+WQwgvpDF-(v16kv zeeU#MDix<4csQoIPB6szrQNlHMc(%TjvlMBkZF;^dBpq<@rFmGxxhe4vhVCIH>z#ERj3DVaW-MuK1hH&MxyY5 zr^>o>hwyPiwh(U+`xK74H-YeuXP&j=8}Uf`C`HzxJm0bfs#M%w<}Hv@srM*nBG0hs z@DJ9bcjOFz7`Xu$a+Tg)G}5PPIdBka(L_6VGu)saL%sKNmyNsp!(joZ8Y76Q$P1?h zzY~N`MiVY*5tVpPXN+*W!9Chma9HmF-J4EADVAlklfJZj9p2qZ-OG z+911fAkz6lCohw1S4i`1w+TFxiOm;*d9$SY1Agc=O;M@8=wC<^J%HL2skdf~_U*wp z&O25rT>4f($QZbNOqwUMx8mCNtG4;i@x$RILZqV%V>^4XlEMEZ_23$b9O_k0^`O5X9WH^+HvO6buR zYmoUEl(`b$KxG~#3Lw~fhN-16T3GQ>%>HL$oP_h9*KfLnQ18Qc z!_Z%ioQ@;$1-Pp#&rn=AtH6pvHG*KC05{4r?V==eqL+Ehi^}H4cX5)~$c?JlZF4XC zr>eN-9)%C<+1R)1oW?1Ru6ldmG*r8mLm4+}+rK)(KQ)wlAp4B^Qr{AyP)|I?N@NB= zIlpZ#@9{dYiz?&ce`!ZyW?sgtMOGqBbpinzLtr!suR>R5j_&pAao2(oR+uKYMeqW@ zEFt0Eolb~J39`6ym!=lg1N-GrPpE0e&8(s)62^L~4VpR=iqQ~)rG>`kGSzoKf3iPg zOMh&5YW02RgJ!E5n;b*O$*B(PhxPW z7FZ`+L?E$xr32J|XXm`>ev7f#Q2#z#=%IsQrV}5&{eu6^3F(mTutV`L|GB&4;j~?a z=D`Bk_Y>Ji*-&LpR5k}ysOHlAr!n|1J-*MM0Fk@0j()y<;2Sxw8dZ|4L3bPm9K!M zECZIZW3ww9e)W%7$}c~ra+e*P3dQ}9kJzN2zpfU*L7(-+4f%wpX&3!CATqO4U z$2Tp2N?1S*iX23V`%D93rvbe_lYKn(QI_y311D~{182@5!~ubSEc_o(a%{h2EzMW3 z4q*X36-5bBm1?)79PZ#G2eu!$gq8o%&j*@~Sk!>5LfSzY1g)WH*e)T@XIDODLLKis zUC?M1L{QaeW(n)$D{wHHYpW|+_5D+XH(s zz5t>g0S8qU%*H`x)2VdRwxk1>kW@(!bVxasCDrc&&ztTtr@nNe=Ei{pDmDm=XSPbFgXieB(G6_ zaQZ>~br=QZd$rFpp$VxN1FL`s&~obx+1*L_{?VC|`>=)-3!$;Yg86C;L|Kg8peCgo zMwwzQP{>_2qQ4AwGubJ@5<3vzEXEVAMUj#%j>RKO5#$JRPIhI5BRZ(br@g>)ZsKm; zDm3M@gDmjYcgZwBrVA~a7|zj~m=c;rsU7=1_1Y44@_;Jh5C(p& ziS)W8Ufd=)6m$8XixED&DM3pX9jG2R>2jf(A7WooUSOIKdEXU@U|dGeD#Ck*X%_&5 zx8lRQd}xgUZ|jLO0GZ1|#*I0fr0p%MDJdwu`@Ae>W`*{XtbrWwP2Mu}82o~y%`%db zoja(aNW-iAad6XTA<$NcibVt!=pR$r0uVUSf~&z;g1eTG&t!P=`o_Ln*Zgze{qs?| zPI&(EYsm=KsP`-a2*4EW442(XO2Wpr28DDBYM1xckS7ABe^F8+X4V%#Z&$f!hq!r= zn>dgFbe!q1#hIO*Ukc3n$%yU&X>P^CYW4v5b(`SkwHcQI;BNvO%;o*2ZS*ss*M-HD zfZe3z@UCSP+N#->#p@!Ga{nf@XV(b)wr6Kz+LS33v|M$TBD)fxU3pqft#GLal!zvM z74Ah$d-a5%HKWc5M6pP(tDxaL25n~Mng`7&mnZQI84f0?AWG>NE$G5NU45xc{^@Z0 zbB5c{3g{p4-KCv!>tipS{9JTTTP>OIH~1Pzp-H^ZjD+KsG6vn%@yPnq!EpQYz_X8B zgmGkWLIT#|MK(<};#`m6vblO2*zU%uYJwG(8dKuRfMK zjTA3i0XuN!OXN|hRqioyh<=O!96{~K1u~lLne1Bf=~2$CbIQS7b^wedttbHaaQZ5U zDN7!$L9${jIM|!PS$Kdk>f1Nn7FssjLQXM@(4HSEqFV0xo!c6%)48~l{XzLB3IyZJ zwrb$VPkI}F>?_Lg0;9;8`wkC9!W}Pmr7jvGBJW&@o*n@eW0$L%kQm}7{6Pgo%QE894yx;{T zs@RTSkb_O5=>~GJ@3$ZIR$F2Of!GpQPJ5n`0EXGWxiAF(xzerpeUl+Bk}29clbU{` zPs8HT54T#3lo4!^ZQDpTPMzY-Q)lv;Jkc~1ie_INm531l?pMoRLq}{N;*As_NJkW` zbeCra_KL~fa-}M85_7%e6MJaMOe9EID^J;bHsAt5j{Mlp#p!WwAjnOBLhHY=@*E%S zDO3Xpkee%p^`h2#SrSS?NWY9!zoIg=gH#-ANjD~nQhfp5)ZYZVe}^|SY9z+Z!`DBe z;Bq%Ls>4)xSV)#hhL*%b6(X;q^w0wtQQ-rQ2VImO3MvS!Gv{g8;N@rGxIm7#m*xJLZRr<60rB_g2l()W zJ34#{NOTf4bm68hfW7L*&G4LrXJ>;(CLEop9~E~z5I$dN1e!vAFbwN&O;Pgymfd-4 z)r}J{lgE2%E{vWt8GpK8)LS}-y>Y?vggLnUL~i7ZpNGf5vp``$b{?enO}>$B7y^p? zz~Gxy`&?tL!IrPp5!Wy#r^a%xAOdIwO+;MfT&Y-np#Qih z{E{OZEi(y>DWk90@}0s5=;Oi&a?VmGhEG5~btj90JoFSN)zc%x!^wc5P>77yqz{7u zH@fMDz{fGUQfhJ<_DmBgdu*MWyy)|}Sjdu_2E3X)7Sae{qo zz8doEEM8`3-r@%+SgV1_Y#eGa>q+X+MW7}v;E66`J`Osia6Ec4RA?FA?1w{Dfd|!2 z`(V{?KSDUR+h?g#(ml#mm(Nhdd`W2BK@c7WqJmQ_B&C-b-n_)g_^sf zP46XP1}hj%36tTe)Gyo z*lfyqo?21t+)8+m{Cs|68tz=3t>Y)yfi>7@rx{O{I-`E>MTx?)wfolPRG&r7Fc}T` zBQp@Cc5o81Qmkg2Rt{3gT4E_UCGu@5*?WEIi# z1%oqxALEko8Klqm7m=``?a2s@Qo9<(qnt)*b}9SrD)c5Y)ik~!=<})IEd?t7b!Dd1 z{DS3JY@~X2UzB?fNaXke|3lTrzY`q0 zP0DxTSmE1)5&*PPuu+CA)14a^cwKGRTUzJHBX=C%pX`kX zFX50BQ_t~_31wi3L0i+#pUlfoXA7v6)Lgba^wbH6lJ%r_w~bf(_CpcoF-f>YwUt5@ zoB*N4Lgxdb#Qc#Kq~*L0c~n;lATb)CvL>xVsC?@SUeSQ46X{>aTK49WyEiV>LmApu zI19l%y2*p!ZW~~wPF9+MaIX92D0I1;h0uXO=Pl;L&51NCqz_m;SfQ)rPN#J(wjWtP zkBBiRS|7y9eBhWbP7|VCIVGqNGElA;(z zr(snj>}lUSeYr-COTt>GC+df!9UPD+imZ+eyhEtI{LK~{x3i(%a=ni+E8-wBN=UXZ z*ZlD@1-Uep)WbLnzXD#Vvov#Xx=Fc=v!SC*zoE*3V#Gw0cD~zosPbIPG7uD5KJVK& zVhJG=*qwVGPe5e@huy~R^y>fYPWZLkewgi7qs?t2)#MieCzD{0eH2dZ&3}j8@`^lULcnM}3ss`QAoI3_0iv?6t zj?-ccaN+Ek+$6-_NEibZ|En${3+^Kj_CP8+Pn7nk6gZ8ylJ zn!N_Wy(YY-JRrXsT*wnQjJujo`aSVw*n`#r3S^?O?afy%!sE}yuA7%N8+I_-fi2Ud z($qA(#XH~n$NYWVF;?d0UL5U-$a=X|?#n*}{Z;xnKI~`i&@k{9LIQ&!S5t)m9Ok9@ z=K$P@3vntR{@@3h=IMNmnJSuEc{ZL^K;_GVNmJ#cL+p5dn(THLAdoXh$w#J zEsM`&qpSIKc>HpLos z1|rYPj*BeY?e`1-wR82=$k5(69DVX6?MBf3k`jd>bZS!%=5D*(cr8k#oGI%f#Ms?k3zkTq+&E5hi&)>{sKZf40 zZ*E6Rq*Mqt4Yu6Vj(LzuD7GYB-ecqQ_4A4dT%eb>XE;IJ=M|uc7Rd-`#^j`fs2oIB zs7U$n{#;qb%vM$7hQR8UZD8@gSL}x|7u#7Vi8K|5$~2T(@|9f}yyE)(3`RnYESh6F zQPOYmD4C&$MZ0o&foQ$W>ai#HZmR2X8al@fr(Gv6`Q(0c!bC-`*+-|GnCOcG&wIg) zXAt~Q^!ZUWkr{N_VzAcaC>0u7%k;?vjNL~$J?*2PH_oP6Lo`982v5E~Bz^=RBj`Fe z?|J7YUr1IRs;p82WJ{yNaU|TYJ(vPfN%SafHg^^WyT+_GYvaC2!L`Zr4VSr6M$v4w90)SEimwdubJH98R0^*2SOl*53gg^8p(F zYKqak8W^<$&W$hNe*P3wAZ5laEzwg0Y88e+K$1I}%UlP3w#UD~l49GBx>Rb=J9=Mh z2LvWNOB!DWILPIqN0!s!JBuanL9xlS1GKqvpv`sN>;it1$tLbn@l&rJlfg^pjsn`y zb7l#QfFB=b_4)<``#PoUNLm?m3~l-5$L=!A$l_^RS@-3e|AK@idb_NS>NTKiGAt%; z2GN94^%l((MCkJ-a!&3;(_ROy6ZLC5JpkjWh}&~|&xwQ1C%LSq$669lj{lrS^-;U& zZ&WfZxC>J!&3xF262Y6>q500jhJ94b^U2QYCF$c6>3(!M4I8 z?Y9in?K3y8g_5vkE`a^X`xjjODPixVUfm6HZ(lip*Smj%_PGB7(k3nN(tmI%%%``s zYk8x%H6?rgv3T-1*0EOBlNJ=CO6#!_I|-Ko-kNA=0z8X?r_|8+FD<}Ssgo0Rv-r#s z5cI|l#kQU4K^#tXTfaiv)dT>&sWcG<1kYYS| z1qFI)LAg_uW?11?5bvX;C{j1u-qMhD06*<7e{ZQhcLXLCw{B-=8Bw|lwZz~(^!?>#@ch0lGBkO>EVSze{Rfg-5M z+)`t4K_#uh1F#xru%tCX*3THE=)|BJIO@qaF?^{!IMMEFy>v2Uu-L1YcTWt9GuO=r zFpB@js?C(st5L`+xOXAnvwS6(Pdt*8K---#*Wqn(Zl3Y;GirNI-AgNf1c^WcuK32! z0C$OSIX;xPe_waV0w{kmn;xOp@)x^yKA&WGYU82*if`|i6)CSq;oDTqLNAj=;9;0O zcVY}DqF+M{wqvB1ti=36+wu1H8o0fh_1mkUcbt`B+g6?j5NgIXB?XUjBsmnV+Dp7h zs-#IoJthrFn|F}-IqCJ`UH!*rls%lz$rtvbezSZT&Kg}H)eD=&Ksa5 z3P2Df`^u4GG90IBapv#?6!61Ob2Qq(;=Q~X-HA_@GcdIw$I$i**?Eg1!vH!Cz>9XG zc_FbZDURTC2e8Qp(wfTIy<{%qDSZH5AB6!W3>Csk2VrL0+_4v6zawH?hTiQ6;I&Ay zf~=z#0Y$H*(MW(LlV?H&qhGiIVs%oh-7_jI*p=|f8O11G-#E}Hh*$aV89D4%?vy%;>;mW2W zTK-tl533_s*iGCKW{%kyM(C$w>Q!G-D>QtcS}cgJF%EQJr0$5RtG61fY`JMClre8h-QkC4+aX%bv(p%_s1JCu1iz~_; zJh$@&!M4~--JcVL3{OarWE@M8)*bX+^OoN(!I>03F30J(k9!?`!BY84`)U_H8DlvI z9sAt$v!CE+S<^z8yw(}V^dqvb?Jjg-{3EKRiJ17+L4)+>ossAFsna_X+|~R&_jI^3 z%|m7a`q_qql~NQ14BuVHvDBOd8Ht+7mA7m0vWbiO;HgmiFK=Rr)|*)3uav8gj4zE(dBRj+jX-_$bkFUQ zn(w8PnNdg?Dq!2nvi@BCHhZ-{DC3)si763rcAs+K_p7f%vr1Clu!EB>)ez#k4rqYWSKzRE{NQ>F=Z%~bx{Kkq4+9vCEAuIzj2MVWwN&5JV))#n zWbX68S%|{8r+Nj3H{2&*1GZK#Qen|L5yCW#yuZJGwsjdw%4QV4yjTAblaL-tlq2VI zON%GFD-6~sn6k#3aPCT?7w9Oz0^HfWRh@$ud zi^{q5wn{^gNzn}8Xt#sKo9AR4?-{4L6}(EBM2(G*p9;;@8iN@F@yM$LVQG7?&2+5$ zlmMLF2`-2P$VOB_JQ@OHBYlAm$~}%>1IvfJI~+|2dw0VvOhtySQKkPKMT}ubG1J)$~n<;Tp>{uT?rL_3w|R37=o6K zj9-Y?-4kXE7-szYef+ZdP*ShOgFK)KLO!xow})??@I>xLm_4?&_vJlZzH={4_7?!( zdhZiYtHu@JK#vTOnd~oGuSI!U0HHhWTi|y~#wB}|bCg2?V`P38cR=W{(lVIuTvkrQ zFLj#BlhfoRESt=Ac!nw&2!bYv+9V0zc73dG2{`VLW~2(H9P~g4N`uF(TT!UpM0_<; zjc_iFX-lEOOA}urX6Bw)(D$s1Me6XQXTZWTVWc_UKd1d#S6DwXx9E&g^MoEv5aqEDK@S#t9hA64XaIgJAv z&)?vP3&&^Pmw$Y810kJjb@X1?+pb-jNy=y>eUZF4PoJAOQCFqgtQr3Tg6vM+(@_TC z?a`If_fKi&_kLw`sW?aIAEHn<3@Yr`QhT{-Qsq6Lta4q+;AIZ&gx@Rm7@byP8ab7S zO%t@b>%02q{_;O+7fj!I!T2}p+$|J2kZ@AujfT5{Wif4+f5i?AO#od$1ogqfdhDKz zI+C?vrtK2GWQw8zsR^s#pF5;!125PdxhzD?u|uh@!sr#(iG#hrD0 z6++JN@*=x9HnSy%SWWJZZS_i-$FK@RpLH6Iso2hkAAe&`Qk8$p76N~-jG4`>3Pcn`oN*uyh1$H=y-?WUaSd(OZ~?@4b;?;8CB4YX^yppz5XDsg1y zTh|bzd+_)6s-CIx@fMb<=|!XW;?vV?Lz{55_PwZty{}*~_uQKZ>!>2tZ2kxuQX%Y0 zvhA!Sk>PiBE_c<&EkgJ)@)D*67pT}HjO=+;lXk7!)?qzGT#lpR2DLDJ{$ zLU3TXTriZASl204T>Fh)4zd&1(pPfU6(Ksb1X;7zyI2#=EJBoz7VvIkm(*?fbiiWu zLR(T6yL!Q0#w-c!Fs2nnC2DEuiUhQZYuV^v=+Yy~S9n!|?+y0PsgN1Yz^ZQn;wMv; zqhtoUvEq0V_dw>vtMp%>;knQkXe(X#4hGC6y!CfZ1X;r+;kEsZ92w^6A}i4P$C=e% zyGX|Ap_HyXuX}~$T|T{1o7|wWiHqol?97*BS|Qc+aui{H&91Yy<=+S0 zMz8Zp3YdQhNElFer@u5@K**AOvmlKi9%0sPwbf+dq|*^fLNk(ttVfe1G+S=s4o*!q zMsbUx2EaZR09c#@pwhD#4m1A~d=>K5W<*QEdHn2~HE!@`_4v;oy5IakF3$7>O@}$< zm`Q<{ezB<{di$5RPNdZ?1*Ku;HG=s>6H)T!5=VU^tzu^eZ}g!@UR(M4{w#!k zW2ZM`w>LfGzt@3SBa-Nv#+YpB&Mh>aM>jv~KccPQn&>R{TffWS_SMB)N0<~Ya4U*y zF`>w0Btr8Uxo%&(@nE@)Z&BKNs`!=m4P~n z>P{4mCzxW`dkGvo)SOFRh0e2cVil*?FZ9SCbb5*5O6?4sJpM}@jwHgLWvX@aHX0c4 z+n*u(H*5dTBYi{fml*Dsiu0`F3e)em#2xru>h|A72Wo)?+VnO2+NFYfkE*Z{+xyiE z7eoDF%DPQ^sTCA%kD$z|IaXe}uO$g#8}!Q{fjR;x55GVG#K3=bFA%-HMhKeB4f#oj zz+RSuvYi!h9NI96X)o@s0anhuvp+hvey^WfKTMNwmo%ap4ul@Ncl&@$ z$F=GR#Bz;>@inCB9Pzk!{JnGfDFh)xlj)n@{CO~LKq;FcF zj7G)M;w{OnPS+?!*v}N01r^)8(S~PpQ&%#p z@ln{@d8d4a!tw zw?L|rnX4%wk^6Nj{YT8msabiz81O`WSM6rsI`fli`A-}8tAVa&J%{19$8H=(J2i>O zYGleP@gkJ+37EJ7G0wp7bAwhiBG%dB#q8R>XN{ihPzAZ-W5=E=WWhB$OR_WgQbdA3}fn=H@A!*^Zgz}9f# zX;a_Z3{`r+RuGcN1G&w{TPXhq)jpZgxyo|%1zP_pKD;k{t)k3pUfw_jN3!g_ru#2bbhti1q-05dg`v3rQi9`rLo@W$d4{m}U)hf51og}W=MAx4?dLe~` z+foU1h8ZFxFX)$1FR;Au4HUk6y1*X}EzflZFN^sCwl`-!Y>2o-V*Y#X!7tL`YTMN{ zicttkEhC&&dwx)?4?CduDn^MQXuFXgLPw@ro*E<@*i!}fPOt)}V%GwXjxjx%=c0${uY75Pj z0x4-(qW7HC!DT7eY}YO`&d~?iTs`Rs)I?)`ga?#+mcYB#)hZ=cgJWDN^C3lI-5HfqyK+PRZ$3nrPpmqCSSxB?~B$6e>6y`opy?Ms!7 zK@lwE4o`lTg^E^4LFD<|iHndZ4|Cr%Kh75DvR+9)Mb0nlcF;e`!(qg>C0_XZ!@wW& z1U_a(!jd>H7#>%?z&wApMF=c=Aa&>W*hDlTbL-Hn+h>sG>9bIH$gXu)vHqs37@h#d zR#gka?6B=Uquz0wr&Osx}a zd}GC77gos9-Jfxk+~Im2uz)IQX&ss!#$ZqZgcT>7ww7)G74i|3FD`@!rjeKoXH*`{{2@&1$yxcORfJB`>7uH=7I$FU2Z; zcI4*7*-zdK8McyOJXhKSeCdss9nD#0N7^eva8C{SKEIRWf0wh8saVW9EsaC?>Gy_C zq)43~^7WO!I0mj$ou^Ki2}o7WG$=6h_%@ElPEs)EJH(-`GcKfXica_s;O-r)n>SLN1s1JVRbxScU_JNv9q{90@Q zw(ZJai5{D;u!pnsh!=zodXO!^R)WTGOi8wDlGhBuz=0lJG^c*iGj0x_yt3+R%}N`L zX$wzZ@*=2dthduRgZs86gwlSqtG*E*9~*kkJ5utK{b2 zHU2*VYnyfx?B9(I|6U{iZV_4bUAsKb)XUPamL|cGB7Z`A8`2J^Y-b_1T(4LY{!p?0 zzc@>N<`Y0}Kr$&?00Be>l(}Le){Rcb|5h0O$30`E9L!S<#uM=ya__c!>0R=<>%dN0!6; z+Z)d{Xt@rv@y;(;j15m(x;3lp@h`KQX{ zWi(?3#p@z@6`<0uyPA!PvczN)LVLNd2<&#u^lD&4A=>xs9t`g+h6K zJ`hbXBIw^fb>L3Isj#`igtfa^N(I|Q7(N@j1eHd3BKU?ba)3@_5_A>_(W_h6G^|Gp z)n2;(^)D^Jf87^?>Io8;VN!e(hy}Rx)by&r*nAeo=hYt)z#mJJ=q$`Yh99W_Ux2qX zM;anjmYAgi=oHTbtYN!~hFO5zX4mDZZpu$NmnBGsLpQEwuJeDX6i~`Xu8GdWGY9yw zrjmo{*GaP!KsgWxLPshsO`Y^2#0h|+^wc9G!%9$>qKbYQ8mJ^1MVucoQtQTpy`%|E zu;4$0EI!Ecs)U8q?cD%PMI##%ApSxyGH)H8Mllj7+r5~20$2&1^d*$b9RK{>vny{q zs&WXb9z$p{QWe5X*}Ww>K(ODZ3uLuaGhmW~5H1i)KN+z72vCY18G=>f0c+9%Ja!aj zVRx(50!V(U@h^uD2SjKsKHKsmid1s$$k3F#;xX-VS;g&gxfk#U#?s0Ysz?zUhNo(XH^EY&88(U%*b1h3^nQVWffYe7H|sfNtd_iu%rba_&%(EG)CWt`eV z#Vtf{B06X0MC_@%6jkmiqydQi(>#XT2;UD=U_K4&qO+cmLScJ8Q7}{l4;fYgWTP7P zC+&xR|1=r=JqL8NjM5)Kz$6F--}+lUu=!U1;Dqi=NI%S9)MdUa?eule_BZun~48ttE_-fZVKQ}Z*LyFaa z-ftPkFJLF=pxS0pF)*NkdCTHIppVZgwjVh2n(!SkSGnAP&6RGpEi3<=F9MeFU(O{` z4BWo4HX8LqMthuNZyUSrGV ztK#s_oiHFkWcfym>vrG$RBYza=eqBc+ud`A5mrF&H0h;dNQuRUvHhMjs+^hJb^Sxm zRx`6wbELbyA*Hb-P(YyO3k)~5D${LnhWsk)$u?zj&bVWb*O)lF^G0Z108BClj9kx| zAMmH%ELFV&nVJ9)CVx{ccONH$MD1Gn(P$3x|Z}CIYm$=}i7#7>*P5Jk!$H zL*P#l_IvelU;bNl7b`QMWrDs|H{Q${lOoZnj_1MQ6)4-{VcYpI*sAQZlV;MakA6Q-~XsL@!W=Gn191EydL=UuTA9o;fOww$zmKZ ztz5$^{aoQkOH*5yY-XssPM-2T9uT1x6cJ%VL89ijVq`WJ5Sf}<@&5q6Z^OLUp2Ks{ zNl#wet0w!+TFYQUwcP=`wZ}&ox8HOQ*9xNFp6N5tZxqxeq|zX`J4u{5%U4_~OZU~W zb9ZA@wbC^XNkpgbD2nBc&7D|V`25jb{`uh3AD-=fkB?Qc^%mNcIa!H}+@FS1dW z=Zo4EV6JFK0POJ1#i?l#IS|Z|JZ3}NWRkQN_9?Gelc73uqfBe2`ACUs-G*X{|A zvzdr)XCC*e=Hj#%v2x-{kebn;ylGy}RbkU1TWv%OXV~`ZCG%s#Gj@AoEn0%5dCQn>it@af<2n72WYz_$D`#*Gwm>a$oh^ko>f5A~>bT*B+uQ0~1znsnkuY!fJLy7( z0&D-{ompwOHgCRo^X9Gnxfzn@TMJoe!i&Ze+2eal4O3F@y(s?Fm@3$ADr4cKETi#S zR(ZLO-QH={6He{xi7g_}T2pRDCFqt(&IIJbaFS#P)?5BA(@yb~%y{av*TSfXr^gw> zi<*)n4wO_s&DDq%w(Fz}>-Dqh3lFX*b!{x0wC#tnNq(kp=SPk+jpuU|mZouJUb@ZW zqW~yc*8_dgZ?St)3|wkyq_9vHT-5GI8jtu%VsctmjzQOO7KQf_`D)?JH$ml>#G>yF zbw&0=a?!9CEm9YQB7X)on>gJ z$s3RqPBt(bbA1P}^;W{k_io4g-EfvhZn@0Y=BHP2ZB^i=lY)>znI0<93X=~P{keCl zxY}p$-&jD)z5nY1O3!~^;Q7P;By~o0qf&?LwdLu9_#^Q`F#x39GUIS?{{)qkj7Je{ zU?18F@;kGSvAaxL0fB$asnY$Ml?&qxls#I&-X5Ec8s>ButMA{Tb`6ci*oy*wM_Uq( zBV2JXApB|Luw5mPz&D{hWqSvRu6WQvkB0JoqIOVv!>fSVnv`B zrV9?9S3k}J1Pfh&erubWvp<~?O!2T-#?NNo6x79ykJ9z1o~53_7jo)5T;3+dlL| zK5fzyW~SF}Jj`@iJrDGcd;Iupx8+NnQp;A4QD7W)qNpng`~Kc#F1isj1??ea(}K3%EwnuiHbdpi2FI-&5ebw??n!D(k+YM zKemYz;Sbto@C)>DFVhZD;AH$&@19RrrDSC18h(A3T9A18n{h5arS(w=x*xjTEg3U9 zh8lMd+Qq~Ep7N?@(J>O;k)twq;dhlYPh|2GghWD*KxSw#pa2bWs`p1;QsdUxOEs%0 z<->@4!K5t)s_QIm*k^^rH`dhW|7r7gslCf-(Vikh&Pg{JLY^WiZueHg9R|Iw9F1yA z0ejzhKJ8I!?BW$cZdl7Fc}qTV5TgSkg=$}# z3R)#m2Y;>-tH!(e+%nFY7kL*zdDlj{-&%N9{3T!HxuqZ~7A;VGEZ+)k<0vM&J3!tK z9aiTq`wF)QpwG=7=dzQPHa-~w$5O9(^_THXc{=B(b&J`gK6|>cPlBIJWcs_BY0jsc zI@QI-1gyU(H6ee!D7UKlw=BJ{4QT;Y2UZF`jJHD=_^11a5?k z@Y#wR@iaiHZ7L;hct*OkDIKynLd$A3vI;Nl;rENDHb3SNj zk=WU=EKgY0-nd8P{7aF2ABYt5=tO45?$Zf{NM4!g+6<_+1yh{-)J3N|DC(IqAkhMQOf<}=TX`kS>%3Ao5}rT>Pz`+S@e*;w_*MQ5Ry{O~Eb|{*BS=){_-HW4(+}NZEVa+Zb-O&)w+v2qh<0 zRurhU2>X7FYI)yjZ2c1&r!L%;2GORe7sFx^`%noIlKM*t!X%@EzEz1$+JbQTX%*$G zv#F6Cn(Q{0!nHLP98^-GjlxR|^;nn_E?S^{UvW9`uXTbQPRIH$=ArxbW5zRg{ODdY zT^7Avtk&2@$1JI6n3Al!_~ROS8)tX^vcIU&u3xAQS#k9nqVtafpzL6lfI7zdZ%ZY* zUM+_ByCJ-oafHG%CDm^p@a&?_C#4B*k$AiQ{Cs{sKMN<_Q6+CZw04xJyo6^So+o{q zZhrg3Ub4P`;Ce%+W?sJaC1d?_$rP3fI;Sb@g)0|JBZbkpZ8;obFHmV2$o#XkbX0DH z(3@Rq*O+2JfqDc`i!A7UQR=0JKM`p_QqRKrrv*0nC3I+hkUo|iSy;*WmFzG{qaRoP zhXk6OJeeDZRoO z+ZXaWq<-Nt)k9g7#)5Y3$6?nK^ybQFT4I8nf&J$ZWkp7ePmIJ z$5gJ^<*8FLfFms@HHEqh&Qw7JK~t(?)nhj!p&2x681nI7DbG&7EjdyNbH0&Q_p$Wl zSh46m8_)Qa1H3@~4ku%Fo|UYlY$`EGwuEJscz753%G&>rv+s__y5Ii~AtNd>vP#3q zmc2qq_KXs;mA#^5O9+*$>^(|Z6(ue^*{hJaLRP8^-9qB`dK=x{=bZbT`}_OzJnqxw zx<2FmdcB^n=g|1`Px9;{reagS2TE__iT32nt;p)r1uPC)5TO>TN6QKdN63c#aEZs~ za~oJ6ATH4${Y50-aiH&@su{7C;O}fO#|gza2bss+T7i zkVa;X@I}|sdoWx*hFn*;&OcQJp9&u20Sjn@GN^fx&92o;B;rS#QF9qDtn4_Lue3lv zt|}>L-F{-k0SL`fL^q!1ARZN<|lQY)S?r`fy_@ODB|4a;~BG-1eu>qa$7E(h@2arH8&txz5lKvy=aK{7T^kd)Y~ zeH46Fqme!dzR7N1l{lUl@Hp38`{S{1!W%9pij*1xAIf$V{N3}0K+V5yfgbA%*M5S5 z8TUY*{`Aq!4r=FLPUg; zJuLO=42MqIF!)iqfQ9I5Slrq(lQ&lOJvf`l`W)^9A_$BfUQ2=?DHPz>4YroZU#a5G zNjzhyi8_16&W8cL`#wJMD-sbQhyJZww(RJ$DY)NEjc>Iw73tTtrbdt1KnO(%ctyIp zc7q=;vRSbGBs+JZ%tmXB!NF$FaR+vs{YeL-3_cSe-YiRb^f~t+3lP`L+jQ)m{9&}b zJV@zl$in~O#1S0vd#5wnFmYOfGPsdgl34SZ!v$CKyEa`l=a#Mv?L2b%CIjb?0YY`G zn4BnlA>2WoO3-5+9uA)|7KamV>;(B1h<4;GeEk`k>4oeW#H=&MC!x8Ce0pA|M|qkHkG znQ#pjDfjh?c)=kW7l9wvIgZalSv~4+I$Kp|mEqJ-SLn%3^P(HJI)cG7dS@?KuGK%1 zE&~4(YU;1-Yg&1WU*5l)H41z;e#Zzqc8nmHn-mA^odicBk1s>E4lYFuk&Ys!WQ6W! z2i0c_Ky1{#ghG-b^EC=eJ-z1P&S|TD)kSde&k4ogi`Gs7qk*YFO zW^R^RDwnM_^3J?#ge9P4z%q)EEzuBGj!isto9;%V0+mP=39>s2%t-(=LlQ<&7?Cu> zC-I(cUa>0#aDqkI*ZCJM>HtKfK*{E?Kj1B6pk9>U!lduRAd;Q$*9aUm}j&}Z0 z8BCYuLh4T*r+U*QLcdhAGC;NpdJg(8U2@~On5JjcD4`QfE8?GW;{5PgBz`nsC2HeO zeoXFZx$(ppzm=gL-UMY%*^71TK(o&z!Q#|GbQ+ge(k%JxYPm@9fHItHhKBUT;V8*& zYEQamZl;PSQ%7i*Y=~v=MBoeYYu-!s7_>Fy7GJty3d|?u9Nj@EJ!sz968U~%Hn%R# zghisiUr2+TdLB;IbdH%W35t<@>o*uE%buf!PX*1Ajh5{BRs>s+ddyDonp6#yk$hmd z33egzi!op=CeWfdFaLDPvS~MoSzAQQI8CzDwZ(X2Z*O@&dL9MJzcMkr3CT~fDTf^6fhWyRRhtjb0AyBS&s&T{bU$WZx{Z&jPIC`H~i94@% z#i%K-mBDNC0e7I6^IAHfD{JM#spz!{<^9WRQ#O$%!t|n-uK$n5NPbeIGAAsaT3LS@ zyAO;wmN53@q}8{}OeA@ZhE9k!LfMgy3 z*wwFde8U+~jv3X?10q)~d&LJ0;{P9^7IEUYadoay* zn}25%p`JS0BtqgD$Qw3RPd~>VA5HA>VDE8e0mZIxj|7;%6Nj&S!_`R-nst5&sJb%i zRL4>_p4Q)_hPZyM5j)NWb?yraG3&Y-O%;bVhvnjgzqzDExbHm|huCN-+6LpADB z-bB`(C+Rwv5At{??nuSi6L@^+dcBjolV>M)5z(42adKx40m~d0!P=<@)Qu2_Wc}^5 z_cg!8!;*I4#7;FF4hFZ$#P9j*ZXps??+kRV{4e%+Pq1LHaxPhv~zYaSl`O zTrx^Z9m*KX@STYkxb3jj`!WCOO9nHj_7&r`A#{&yD$=!Q0HJ$3>V8M}oC-0>QTXFs z6(0VVA8p=?!BZS~W2)D?j3WIrq11Pq^qS&WG+JRzH$OhwWb@?6v=8LZ41gH-wv>N<~C(z)kD_*((}Lvm{I3i+X3%#La*Ct>gcKxEdYD zbv+NzF@q{=xpu4ebR`~5Q^*Q^d`ORDXKa>Z#2-9hSICkPk`PpU zU~s$>thQPOkeL9u1L7IOMw`nfO6Fr@p? zqux!haCHY~wjV{;e|YHJL?u`odbfcWR~~cV zsJO*FkMj-hAy0K)xSgz2sYdHK3!U8^ME{;3vIGZ|#$&?|uYn4kZ20tp&(gAwDUwrp zwoVa>zrQf&us;rQg>1lXdFK(I9Px|;Wb7$subLAx27iW_2-SC;{(+g_(TXwXHIGG;9SEcDlonv zS^Nk!m|x`RO?NP0CEmYekO}0M98IP4)MO<|jUB^Ir2!YNC1v{pPn7POrzWy*)P7_n zR-<;4!t!7kc~Pn_SNkzy;WxebBRQ^_|;nU%%;C3~64x7o|5P2fZgO^Y`%&Y9h5z5&xKGG4d(<(4y31&p$s$#t~1cLPMSwJx*bGyEuNh;`Um zc%0oYfysNe_AF@V-aNW+c}9?O`2pS)J+IA1Ftl z__0w%ciGetQt$qNbx5fbk@zmQyKELx9JMJtBn$~wL7oWvm z8cXn5X({KRL=<+{<+@`INv2dIjF@9p4V~%ar?$_+x~&33wtBn2%z6Vbmg*QPsz<-> z)c)VfQ!U;(Em9gTb_tK!+d!)kznNd%s-P9dWHTh1*2JXX1CG9}BVB_5i}w-j3Y+qa5*I!qVEBu*8b~`Gge|i1c*0Kp!Wj z4LGZO3+HLH{9Bx781t*mkff$);>h?eF?I3>xyO?yjuPzA;wAw3*$J4AxpwEsG(R;M zp?CrS-NpP&k7SDtz$jXl$Y}#sbUwP>veqRzvCnpC2MG3d-3<`lS4}_}lcBcLo_`DX z4fQ_=pnFpd0>JyvjGLOAck4bWUVH=%0%pypWj8jP*k4~twGjYtP^u(mGVwd@Jff~O zCyqOKY^8bb$jA)SF=MoV(A0w> z2#LRh@J?gpNI~p8;b(kz9$eiD7T@I23dV&_pR(#fWuD2#oj*c{TM$d&T!cIJF)Ae^ zn)8Vp6C2&e`uvn8O|mI!RgK8DTU9=`q&6M5j91AU2=bii!B>+O{p7{)n^~Uj6YGCV zlYHW~I#)9^x{(F~+Iu!u=S#nEYs%nKcM2csIW#-?-*ync z0n7gKG#K9>iF_~rm|jXME6#z1{k`@7(dqpL13S)nYy4zsT<=ys?=}PhR147!74+G@ zk2m0HjlYGb|KPkyLSQFb2Y9^j-{bL}_$FlDFG9Vy16^PZH99jsA zNNuQy)rVV^b#t2`5&Zg3hJ=wHzw=G_gAGB#)^)ncNioN|BO9b1_b(YHU2X=n{&HBJ zOu7KZIFE}**Sg0v39d`_p`91H>)MlM=px*-k~7kEdMj^TGcKMh6@B~dE&hm*LT{=j z5IJ;dXbVbh`P$*Y@7@!@lTYZ=_|ebUk)AD|3UBK#P-PqwONSvV43;jZ>xoXZpg)r) z(XM6t}=QA4HCR&}m&N)+6Fc{4KC;Ng`>zyRmn; zd;U`6VFK7h!WcyQtkrMEB0*Egn(pS-H|#zG1&KQJl3dWK5J6ONlLY+@U4r0e8M>&n zd0P0vwE%GZLoB^!G8a|BL>cD0Qy^8}Ck^;#JZ{_k39^_!`4bg8%t!YCo)J!B-+m)s zT@pQC@pa4H%<_tH|$qZb9ymGkUDV*wI->QfRJm zGz!PqiGe;HUiLQq3XuGbAUaqR1@Jr{-%V>19 zZ}rp6|L+}!tA9%9kX%L`Jz}`DCt$e5&~AmRBHKz*05ekui;BliE#!IXu_St~H~h;d z_cO?ZyK)!8K2`Zn-mz1s-9*jN+Fgt)UOa>R2tQ_mH(bZ1r^RpPp7ENX`ybo?Km+}Q zy??oYO1Z}g()rLoAZt(-IwP1S-lfaYNkHJ-aa`DkX3~G<-pMBz4U)F!H;)6+fHU0n z=p(lub4YD5T1%bnsH_|oC3So)c~nS1HAIbshtf2K-llCPmLdcwMBl5gMKZ4--b z`^hWX!q)+b)rJUE4*iD)k1hj6RAU%)k@;(jewq7HGyUgPOKsDgl*B7)al)}0d zYNDt$zC_SrnEvvSNE59Grh#1uy{Rm;hR4y0z7kSTC$0eV<_-w@RbhTQiaIcm^u?!w z^r~i+d12oI45+MiA(U~@YrPrTgK~pWrxuD|?ew9RxR96umLUSnYd=QTX=d}@7M_3m z(7k@I(ksCG4P_{1=vVmAZb1?2{4SGZUTI>H>#_!a!lUcs6Ig+k1C%2Qe{ z_rt7()(^WqV4}>q0IOu4yU5c~8qEI}BJkhHrAIk(8eg40x)9L_!EuLCaP-_q6k-}B zy>c2+pV?nsJM&=XScTj1kzUr4JH^_MR1 z?4KnhhQK%{#91;i!fJsc>0U$X43IuNdb z)rlpkEA=0C{_C(~Y(@h=1&ZBOm5pTn4q)i`AA62WfFfBQxejxfR8=B_3lso|HWO%Z zhT`OUs-y5(M3@IydVhi}^wv*!h!Wm=coW?IdCUTqO;*X^dT@UPk}Ym=;+)O>-urmV zcfP!KWz3|P7=7Ux?^Ex6`#5GupHKU4ec_xEnx#h^8EZkWH;zBe;mR{mhfqoQMh zl%o^G5({4Ymu&8cfg-h)M{>{}{;;&p%`wG8UgP>$0w4)9m;M-eY$DTB6=+SmPhtrc zZ-UZ=2F10j7`CUFrij;ot*`<$tL^!rlP@&yZG4f}Miv2I3v`aofI}-`uoo<#OIX_qF-pg^Al+L{D{AzmO;<)YXaKlaXnBq8ykQ5L+ZtGd zBOzQHZ;oy|fW$3W!=2s)es7p>oeHP8x(J7z+=AnhBHm{y8;-Df(}lPOg@kZb+y(d7 zJNLg2KeW{%=otKmvqykQLHz2F7US3lgKwGOX%ucH!l-06ddOh*D!fFWTwphr_Fh4>0bhaUudS|(eWkcGN(@X~?i^FQe;S-kvX!EkwevL7xqNV37(YA$6lrcnVTKXh zLBir(>i6FJTL+A*&1K7Ilb-XF`1HUyFPG;nyek5x~hQdQ{{kl(FfLGCF6Yw(9fzsekVV@(&lA?HG|Z@))q3 zC`(TwLQksxxH#RznejAsdaU+#3$pLuD{f{_3|)BxFaeHNOyxh!$!w3+eplY8BHw_8I3ZrlZ(Q$I;!@D}APozuk=iN*j4=GlG7 zV)ZU?=vWP?R{+jT90IkCl@d!X`G<=Wl{aSMY2_VOjon@3LsS=7w?3+ck{c(leQJAs zFGonh_7JFk0@wot5bARx7tfLfE#(~d8-ukKysV)#7?wrXn3TEY#Kg zU0-pRu9InXDLc^Eajr*l|K6s}-iPzVLdgx9CFA~izlck6p1b((YC?-ktGtim!wKk_ zT2A;F-DJB)>Em))eN>kTF2tnVkn^IfdsykphX&^Fm1bks&L22FcEAa;=Go#3eBg0q zt#doj+uObG)Xi`p)RgbJ5K(9gU9?a4r$1<9+I03hZ{E#pIYHjbHvV6Oxf>KyHZCF5 zkn=m7BP1?~1ARkFhbzAN>II@P4eQC)Urn|3znl=lyBo(2Tse?O;jXN&gqq(=k{U$1 zxsn{(ew0L`n+-|G&UE!Ie3>IxpKRk;&?X}sE0^;N3L*vfOmQ!8YXCDr@mXlUUX9LP z&3#iTkS6YBsX9l#_1H8yrJT8ixP?rADfnbluYi3#j);{giRJCs{#wl73?Avz4e)S<~RN_x{^wBh?_Budz_p#|^M( zS+Ui&cx`+<7$~%$Xh8V*JoxvT(?QMU*O|p+uaYNiH{aTd|9(7m3;cuvBqTAp#cN2o zu#5t6)I{DNIjnf=Hgp6UHz-+nkm*n*9H-zb=S>f08O!gHPyr$eV-c4T1tEc}Q4FGL zfblI_qTHbXojOENSU{U60RD;`h9%>&{KK$PDghs>(nZKDwSdz&2lEx=I;#*5gai>} zkyjZ(G>_;vjSk3&0T6Z<6jciiOvFog;u9PhkklO*DbYzlfU*71-KT(Bjz^93wAH$~ zs;dj7fv|JU z^qd>bSwj3nj^|o7j}g)gMqrVG>lX@iIeJv0GSp$muw z7C3B82?U@mIEK*dAoEE7(YvF1L)zx$5rLfwPiYjdcFi*7NR_CF533vy`s$kgU8O z6=%^nGxO`nL<1RxSkYF3<%4#)(}zIPRdCnnU1e5ShjyaXL56g>l5`cyLHzqA=nv@M zK{Bt@t8AdXlAgPc`+U;HAN?{!aI&sCgqeE(;u#~5D}hz<_8~sYI>kHao1=kwGbEYx z4%p35c1&7DNS3ZJ`3h`I8V>(x(qOaifns!-^wMmKxssF@aW$~kb55ev(l$zu_X*I% z>;P8!9WmF5(}-3Btt#=8_8~}6vSRZA^(Mg9U<<=Hasb;%KycYyYPOZl16NAB1O&|! zB8S9Xto+(cXmTZUE6 z)?h=B(>DS7_1lOZB7KE=#dB%D#CMdw3rlKbx%!5$;-yyMHh zrSoYg@hI;!5x+*`3#F@rVu5%?zDn=Qu-75wPLy*K?0&fDy`b=3<}+eMM;xB4nY zO`#+<+Dp5d)<@VRX7$>1x%r-_pb!Nd`f>S^3P*YRI5^KJv~+AuzG~Nh`?qZ*-+MG< z5;B;Z6i2f)L_dE7BX07(5nTrBW#uO(&r?K*444d)p7rgwPsHnM7S6mx`KzWHX8#o_ zX)cH6!fOAbXD4-TWs-9vJ)V@a>vI;Lp<73Wjq@WDvSl7vTPYNF1+{Ix!NG-bXMdc- zUbDPauOxKn6^@n6+#T-=coKAQ&cfQvob*~!LrQZUnG7)n<0}hJR;I)mI@{&7QOSSw zIgtJv183UnB<8?pWuxP<(7cSXI3FN4?sNl+opthPK(xg^0!ItAq%Zqoe3gbmGr1{0 z`a*Y3Na&+G8umQ(*^o=PnB^`R(Y`6P1Gl|F6#>JhO(a>vH3Hz9SggHQN%<6U{|Afp z!;~*d8O+b?w<~d0;qtoQt~D8ZM>d{Gynl6mDlMArRR0Yyd_fi^B7)~d1f?kc-=X58x~P>{_S3?HKunqo!6i10fW&6 zC+>FVj`|NFsjB0LX87|Xwa(&9*A1lvk6(&7X1CQH@Yubq90UaIxOrIA2^c%>Q&GJ5 zBUFxs*G}%;DHyd`+mt*e198z>r%p-I_3@A5Te+t836^HOv8lB>xcQ{kzG-;?&)Z7@ z#nC4UAxAhH_!i})sK0Dt|W<^{(jZc+99k zboSJ#Y;gsp2kc%4w%#~fSiS#!2lzjcrN072TS}$>Poym?Bw4JF|G;#HxPp9co)`Vr zH=G8X{cq4sZL-x{EqE`71=O|K@VCxJwo_^@a%A3QVJE#k`n~h%UgV6f!HNXRdX94o z0A>Oasd@EvfR|U9_Fcs%PaKyHFU8)y|0)OJ8YCL!15&W*L3nX_1cl{&!n(c8^;v9Sk&*dqSzjSa9L4nS}6*m{mI*S#j z|Ezn%sL_}*x+_JarJ`g!`JsL+HqL!$VP(sj6M~1vr4)9zzMTXG(GzlXTW6^e-2uX4 zz@zspuEn>6b&PVAXB`8aH)i8|ny61@VaU;s!%*b=pM);Rf2yY$Z{0UOe`m?t{o$?= zY}`0*_S!H?BLK2K!lF19xKS-2x|v@UWNSriU04H-WJ5ovov(dV?9;>2afD^T5oU1n zSgD$47iT2zQ5_$F!|QrYt({s|aDpmIZ!<2+uo*49iH1NO9Jq2728O1?kWCV+4ZrBCi1={=ho1B7bCkZ@k{8J@#?Al9> zj<@q{K;e(BTxvTG*Whd;bqC*`%@=@tGQS@E6?=Ven#rbY#A&`k!NiG-Ho#Fr8Bn;N z@m*s4)_!eTG__U3z)^V2+vK_w}FE>uk_4XxNQP>87D4;;4|+#&!O7D*eGRI?d!0w6&(& z$5A(USVg9 z3UqYug~g_Bqd+U?u;(>{_NO)&Iw^xj(VTg_LH?OIMVsH#snupmcs|u#dH?sX_}*j$ z7umYzsNr+B{2^#{OY8;&7$$lZRq0G!@1fnxWUU1(Z(!vi7^0gSPm+@1v^7O2lytR# zVpJza;`ZjZKon0@%#e$NaBF@9C^{zCH9q4Ey<0*9(V5xon2vvOUTof8S(}W7F`T9a%~f`vR(&RQ{=@TBi;)UVs`=y1u^{f|ArqwLt6eAgJi^@sz42m-#i&*c?V-sF90fQ-r;w9n{nvn$45O@{iNRm$R6T#nx zjif-cbstA`uNzzJR<(xenS9kTWkIz4Ar(T0B7d{z4 z%G=}dff=yYDk`jGm{e$_FELDq_Lsx@XUptifBEiKffO$TUczgdYZr<|-+KP#^H-70 z4RSRCcT1s$Yhd)94T9K!+BL}Ky$AZy7MMK8QJ5`QxU|3^<-&z~TseQncAzACx-IJU z=_foq3$^f!8bu04UpI%pn$W68ZKji)k*594dwZ8D0P3dgy5hxy>ynW%#q2F{0NE+>G=-dH63*bx6B6t1X?3}n=)?)6~u8-sYx`$Q%;U5rU4MzU3LB1 z`ShSmY<iVa%|8hH@zPXjb1n;em z5L`AR>V-p8-d5=QW0dciYbIwrOnFhY38y7pJ_9##`#A(9`yDz#2{?7jygFJ=AW}6}x+fwSqjg!(@d`q%fhZ}>wsJ=53koM?jv~-@k*j{+r@VY_L z`L2czhCU9T`?;*6TYIlyE8{nv_#sVz@yi?*UR(tB3K_3U*yTOpNi;Aoi7o4 zJt`pX%t(P2++vKExQuj?%?`P~4&1!r<@dxgw(?(YIr5y6b3-nln!w zQ?8qv$G)FiW_w5U2S8)nClWb0selm>G0IZ1i*K=E7|dA6twa~_mO5idAbMyhLJp9< z)y*|{l{9~F>$LueKT!6(^2$V9K%#lbipV=~Y-Ntphk{30Su?BHjJL$B_PT2+*u(S`%;n+f2!f zGDP#QyLKMt;_)GWzLy`Wv+Lo4rK{=U4QGGw9o~ev%lV$no1X`%*F($1y0BCRir}A+ zh}`zh6s7ASsS-G^*Th+)CCQ6Ll$Q@`ysszK zJ$e7xZ7lQ2_DetD99ruG+92fk*#a)G*{~f%IX@xwGf7f6Ik;!zJl^#bcjB`->6b~QBxfHQ@aMzv+Y15WJYZg83$Q}4&8Ri& z8E$b{8^`nweBkhuyY(8up=Yin# z8iF2=gD&D8G?y(@X|JZzYgD^cv z*X|)NIY{@g1l$fphk81gv6qC9IUEN|h*u9DS6zw}Z*ZkSwqeU2xhSR{{25?hv=-f$ zu>dAxE#MT%jx5i`F70o)o~xcb4og#!r!Sw*p;O@9P`*?os^3k81$jl#de)i=4|{Ca zGP~bu&81obg8Vl}D=;C6LYI1PLmprYoM{|jTqGbvx0^xugv2}&+4w$&x-bxYa zglcX7Jh_EF`1`~Cvf#ym#WD}lT>{3tnucEu!m;j5B}xip>vPV(al2>wi0RNGpk9zSTQB4f7ZHuk`VgSQ14=c zjlIkIL3KErhR^cit0!+QJSVnS=Yh;@^I3To3l#J7>Jpz%EJz0-4+C)5Jgk$WI>#i1 zrnYB?#rgMaOl`LX#l`qwYBMG6J4x~D*;dZ^v#j+7)sd%RkOMZ-O-ddK4{_+a(evVp zqZgpPmZSBd0Z$pIzxLNWhU!`gcr(!m_;R2n$$0hp&&SixnyL}8vvP=B>N|9!RFx`t zloO*P#V@{EqQkcGVWGjbjhFOVO8!w9=tF%Bdc?f=x27Pkx#XDx9Ui-k37?R=PHrGPdl&J zm&7Bn7Z^OysIfb>_r?`;8@J%_7W3$ z^=Nj)omTU_=-1Z~-ZoU^Nx*;3y3;jEI2qcxLB7jvL~!zLJWTcID=w6k2NVLE#xPfR zH>vNXb2)b#HahNnQYvjV?@oyGAh8%)D_soIE}9@sDt~(1-4;L) zcU7hw*cF1;$IocoV;R#Ycwue&d6&i3M;Nu>Zx7LHtILG;2L^~?Q2hLCq&55oP-Caf zc2tBiwp}hNubiFwT6ggv+x1SO`0GWf7e09A>l?y#i{)tW+WtP3PN}31;g1_wH4s07 zc1*ymephoGZ)%zz8-GzCya-oaE7K!;1^gWKDy!y%o-pS)Ji#XlTX-^gdl22Zh5igUHwQ}(^+Vy6wzw=y`55X}<)B`r zz-?grCs{d9hsnSF$pTHF)!%>>sSIDx$&b>;9V+J(3)Tk$S}w7M;z=ne^&IM<+qIH# z&(`~t6tjLuUQ_;B?)FKmQh3$tG4OGR89#=a!gS=tlefc~-V-7Uvo61V;w`0h+i0y9$=%nei$`t#5qWAUHS!Y&Ta~$GTtbAYFyAF9F{dSnmNDzOV&K zkwU@XNzk*w&i_z{E2YpyIKJoMJVu86g@bzLU%>Y0O_Aso*6>`m0v$ z&^!LXqc2_pGy_6h?a8l3r$c9`HQv`nivJ5Xiq4+KA%PFyM}I;E%eL-F(S{|PYncV4 zOQHNi0dDdB8bpow`1GAaG|;}ZVIz4IH2~ir`v);}7T%2Vn>W4!fom4f$k2{v8JI}p z@IKu`BL|%I$Du4lZx>ZD;OCRuVnl4a>-#Y;s1W*`z;`jAw?I#27&6t7GiF6Xf0=DG zIixQ^$U9vRPtg0TlD*f_$`)hMj zw-ZhrB^H7gpV@Pwui$983{1nWts=TW4&PT;b`C+m81Vi&^*GcRk!q!`_izN;LNqBN zmuXUGc6L++`XZYs9rcEI^RcXuTB5;0KO+Z*?S@k7(JP z+<0a1-giyo!8nS)FR#b-*ZHC%`1`Xe$%lQWkc%oNu#a?ZvqcS&uA)5RGjTlJh^zuM zr8D5$-%9rMF4^jMg{uELgfA$=@>o^Y2MBHP7p_+7;MvRezievhMSeVC^Y!x8>|b0t zaS$qLQ+4t5?9AJThCSXbe(!(47%h6aH}4SOXd)wfJVToTkC5(uwd02&vL(yxA%N8q z;StT;%l@eZ1RMC}U%#q02D3bw%8RnBY%MR6d6zx2Xd>pob?FB(1S5fJi1QrI?hdQM z&S06auOJB-p#BVMYlc{m3!jEnshTMJcvA!e8*Kb!@-QLQo}P3fY{sL?{zsnIvuwN= z>Y-}9P>!!Icl7pccRZ57lKc~!CL~9u0rQ|NjyH>gKfMybv#ed*qy3C(*tBnx=@ISLeFKPryb{V=n9Dz6){yytm^0^i@)PeSa}+lQY5dIl#*G zw^=-&gpz#8zDu?^{3-41{Y<*1d=b$%CEzpQ0veYVs3AOH@^Iqk9GKV(IC3aDN-;+^ z1U>|d43YH+M|{7RpmrJ$JN}4IbZ945R=;dM4Yvk)GYR|mf<_9B~EAfIi^*5XEHPd2EOjnZT2q`Dbo-s=wA*$MqsfOoA8JTptQu$fq<21kY z7n`?@%-!Z5yjIi_<>Spe2ex1xft;kfL8<}IK)_OlYarBS!bwf;)tFz6aMN#K*nJ%4 zWUrg7f0U2c5P6na8VI!U%K1A#FcZM=Cz#8WE_9q96^kzlOuSLLxt`O>1vXprr{448 zPd5G?0`9vQw{ZK7&r){in%k4($WFRC9%6T$p*u94ud~=($u*#d``M5gbDknFluiH% z*ZJ>AxX(@s{`x$>5gH~+6@x$@xZKG6Gd|k0^IDXC8ebD&;HnIiSHE=S1g`loec|^T zQ&oy&Gq+qU(Aqwr+#lhEits)Sp1O@@*||z zD@%7M_?Rilhy)g7Iu_`NYq_7{cwcPDwN;r^7=M4;@8OwjjM?5|>CyOtJFa)Wj_L2} zDC|7TM4*!l2#d}co5=U9+ovJ^Rl|50of?!mDv%kvy&5t4ad#q7MV2S94GVFyX`##`0igT<*A zXrzzzo!SBI_KxxCUZd@0$6IZ+&0kA!1q9xStkPasPr21Ed6|)S5!-Eb>NFF@DeU_i<4!D7`t9u}?$U2=NAGW;eF|@bST^wz7SSXoW2j+d4+==Ylx=0; zT!*Cu8Z|x|2zH5l!$uttdR?g`dkrV3bP?8CN-A-zp_>qSTv;&hpO}lXny2Z(Gr3cq zyIN@P0oXX%LXte5;D73(3`8co8s(&9j3vnBvQ7OlQ6_oEooD;<@BF*VFUg-aiM^I_ z{I2QCVOEaB1@&!kD&RM8N+_Lt$qa27HvU>D-u380w&$!QZ$5F~EfM?bwoPRP^2s)? zqD{q2*9mBBvl#%CUbkh_X*RSEG#7Mqq+y!#zMZ2pzg-IEk4QG`fbX}beQVPr$(QyV zs9uLIu;N*|-fvJ~og(+pc7JW^+(UP6iw&mrnlbLpZ$}~wfd%0-OU&Iz_h|~}8X6r5 zXg6ik%O$4~iAdk#;2+5D#h2llM+*=GpMv*E^qn+J+&IC{gQhZ<0d1P2dg2La69>(1 z->pMes1NpCzYbkFdR)VQS$FaL8k|D^GB|;VsXiWWvGhhmL;M*wxwHTEr2@Yyeu7!+ z-QnT~^F^g(*R0oR~vu0B#&LVP8teBX?)fki;WYJv9R z;{#07>cPvoXNrIT_8QttUhEwv&`>|neQ3}{J&hU=}W61q||R*w*Eo9;x&yy~llCAKDki4(R`> z^zMq(9^<7`KpM2O(&Xn)11 zuBVAEyGqQ+bMZK&&E!7khX!<=WMz-c$$Kl$P2D4ha3sXX;_M46@L zKBo(2Gl_cGOq+(~MOcdpO3b6Mq#6{j{RJFz1|S85<5aYgOL#l#U6C*WB;=fzQFnxv zIvil+e0QN;LIX9vV6-V0zZ@kt;(nv%K?nBAY)<^q(ppk6y5@g{WUDnM7X1iX2}0sy)} z!031otuZk%cpEl*gP|n#9->Rf5l0b{QuBEqnt12%qHV|x+qfg?$g`<~(ydDVsZ_*Z zT`6c~`g zbz?wQsW>v(bG8hg!Y=9oWP8&jUjvSq{4W-8Bn@JuAAwBTQBSGf`6*@U$_R`C`u^2m z-d0Mq+GtSjl)h|5AVO=?QnMRRQJruNOuOO_6JtrLxJg}{e`~Fs)fyTCoE*|w^Y1L95#ryZ7$St z{lQHXqNFC&OE&&B1Q`_(U^H6RkAe_j6@MwrlzL^UhC>SCt&+U<(7wRhv?znH{#+tA z0s|f1NP>3V65b00cr1e~s_l8j{w4N)=h6*eN3@tKWtPh0i|cWmb6_t(gMR5=q(S4Id{SUTSx2hagLyBo)gF7iN&MhtrGH6tdKIfQ>@G+XNumR zzvXSf)?|w&0&fq7AO$TGBqk9F;v+0S??6if2qJPxf!9-QP6C>Joicn0%h%Ke7$p@- z(l+o!?-}AURq_R1xmB(ggb{S7$rAK@aRqx?W?k%LneaL1&a>-aLNPg*fdn2p*inW6 zSObtSA5;9a*TGD)Y*HVaX}?QqZAm{JawC8oDe*njIS*)^#1O@BPCvXId@%?qKMZ>> zv>C2PGUN}Pb8{KpA$=r;1oO4#tTEvl)HvHJJxu#g;C#jvS0uj1Y@i@#M%)XlVPdn@ z531Q_(WPtcNj!%ozW6n&VslAGe;J>$G((T*vrzx%MxGU!^<|BoXA$@ZUgFRQ(jYph z+Zi57ELD6wlK9jdhD|+47TklSyiBjK1Wy3CV7AiJ#S`dA*r^gJy#$Yb!h5H0FUNB5 zU$pgeD@p7LyH5R1tT5sY!>pCLRKG8-hFDF4ocVU}NdF&-yyDCj!PQe|n;ay=>?K9~ zE-cOxN}qFalE(qLH1WcGw7PgRI9=nj_^>KcPb@Kc%&@5^*)Z2Pq}o*1s1djSOqICu zh|92~e&{rYWfq&6*Yrr7*;{RB$3b<;*=sG_&*F95aI5$!Ua#6~K#OJNCbqu1&=x@& z=52Fh5-(C_&9g^tCyTM~Pxm^#3~Lrjjj@41@FCXJrh20(oimqHWG*k zBSkHMM&(%M{NRIde#`dvR8(x^w~s7=V~rXY8EQmjj6+o6SpkCF!wdAMr4^b~%9<$$ zt|m;f(kR)-a_YVIc6EX%l!_^{BiBpj5~!Oog1xr-9pt-B>PSPk`7FxEMyvpdQhT3D zWjN(aJsPcB~icj=i5ZCEY! z7zd4=09~5R4g7{Ztr9JO)A%7K%UiHu-oMF2(Co;X!YWe>+#l)p8rgRT0|k{3(ale~zpt(2}Jq z9R7hJ;T5eREU%~JYxZsOwO$t?qKfgFzDal;3oT2AU{Xl4tnpLlEcUR~N*9Ws^P!2o zLoR(9DH9)4M6C`_L|C`G#foDuHg7rc2Cq@- zyJzTLqo6e;x(7I=h@dxHe9$#}dKt<<-Nr8?<_=`@+_i>4xX>uX$*)Yr(s zY;#9*z$pwpJ{pZ5j>_Bg)r4P1)`U7!Xg(nq+ItgErh?H%Hkpx>pun8HET@hAf%PC` zZ}8#f?GK3Exj8<`urWq9ol1|Q(!xz>S0<70ige!*C+c+dfzvz7K{n(p>D?BJko^*G zb(>o6CjA|4GnOD_|GH*5LV83(KzbKJBdJYg49tiHGrEte$G z;70&UQ0XR#4geOgE7+QM&~WijW~6_cU@(MCqQl?g%_I38k2EHRo`)2BAoWvR(w}4l zT2Ou#2Z8bS{)u-e7yki#_1I1B0J?YKcxZ3M%jTwSioWNYRX>nGM7dLd(-mMV%3+lo9E7apR1B9Irx6qyU+H7eiMQmorkwkAE;N%sdy%k>2 zZ$_hz8%aRhz8ATdOynI1qu$;a-Cz3a?0)jR8_YMidG7d?pwstsXAGy_T}TG#p&aG` zkPg|D)Kr4p`F$k|`~m4ZU_7k?K%FHt)D``oCiR% z1-eLH5OSVy1-SV*O5)&nK9__+Djhgalaa<1qK`NM-a_VYlEEmma;}j<;QERi$Js|o)W`Kzp|^@t=ve&xuI+jM%WBXiXF~#Kcd4}o z5}w*20W6s3crS`;r$?VnrDnPQtHrtnoRj}HL*JAKgYFoB<&A*Xa4(m>a)2Rt3C6%| z&|l7PdHH86M;{Zo)XR=Yb<2u7gwGb9JGwPXYCZS(%!$y%^&5!<)XPYk!CSQ?XVsp> z0W_xD@GnRQtu?(f`)@E&&j5+wHcXyp|_` zf&1S<6Y6-h%%-hR2cAj$Y?k?1smF7`Wm5qu6zUHRHIuq^U?BriAIB`*#4 zYooZ1G#C^zk?Zweq#cAcS3w&xxcU;P9*w!km{Y{AzY`0RG^>MXo){rFwH|3X9jtD= zs%2-jJ%T;54E~>QsjN|*gSf|VmsRvz48o!* zkfHqN79^wP@m<7c`7B|Rsm#13?uplD^k#4x_JV*7By^`^Sn@dd>@TZyf9!zr=$rxDKB!RrByHC)Tj~i6v_uxOg z1|UZ5T_@Opav?Ng6?!`~-X{pBjXOh&d|%qTY#y7ZIg1-X>zWRkt_+<@&$-GxcsHoz zNf+x*az65v@yWhK0mcn51kZ|}!;UK{m8EhdZDV3N;8yUa zxmkmHwg0oy2d2I|>T4OV6IPN%wvNv@k+FOQM1gkP+Bp7)cd9pCw=nv=f2ybgn+@ai z{Z#d}?){~Y7^Js8g0{+RSRXDlgNazi-xe<;%@9bg@sNSrtIzOlC{vACYE_GIdXzWJ zD8EB;>yw%UQx9apukp0nV6SRZz4qfJLbSW8q)ui34SZ9U=?p}`{B(1#nx8BX=vv%T z7Z|k={T=>_FNg@Z0pj-x+yhpoXS_dl=viibKD#Yp-u-*^U?-^BU?VTP$gvS_P^t;t z*?)+OCRo9MKC!#Rhe-Wdjjga}54U=)@^=GR?0J3SjvTH}bg_@powj)A_+)ZhK{9!N z@E?3K%E1DnYu^=rN?+4V*utt)FX4!JJ8Q#BOK6u6i09=Mn>xl%RhfGxH%wB)eSrz_k!6zX28@YGrP>+4o#9RRG@I=I8_O+%c7Dr=;Cm>)$Ay#c< znP@Qbnk{a!0Nl**uSVMo-N!3$UV@XxP)1aNn74cdrrWkeySds28#`mbkOJjUh`3ie zjd2EHHDc7G`T`s)WjJyzfblxP5D3N;8i>qX!(c13GIe;2!2<_f)0V(2AO`QU!|{`_QOwYyUEGVq2_80JFkQ2pr`by@c}%Ux#M z-MtQYB5gBZ^GSYN%4`WF(kLu_6O3HKDORRG0lgT3VqQI;pp2`fzXJybj&o&skks5v z{jr~j9OO&t?|+Jx~B7& zyUqkA27%bvBKR3(_AHFB4|PE1G(AXUH=J-Mp(TlfJ!wy6%~N1~7#7O*KdA=bnetLs z#fKXVq9VYYeWMaTh?#zDArg#>Tem$DH<<@Fzg1QfmKSo z3^hUi^R)|l{>U+jCinM)&? z#Ffy;AlvXWTa}o&0*|3z4?M54&?y?=xbv4Iwc{=)*E@8Gk9`Yj=qz@OAsAt+&~m8y zSAlq!pswyEBBpb!0nkW^%(FRxA$OvK9!&Z$b#H*utyYPE7lpNdDbm?S6)rA-qg{r~ zq&YW-6!NUmm5!d!6Zl~9WOP8j+1d7g93G-UwM$@&eiu}|C*I<-{9KyS;nhs@^M=n1 z(DA@U^O{KaR3RJv#HVrN;3@oKfxZ4~`546j@EL5|V1-RRj%aHT`z_JJRV91!0l5Pw zF3?Q+ntzmV8sHz@L%WtZaFFG8bjw-#)rBkXk3!~(Frl=^;vAoY`r-ZJgk1)ciqXG{ zFxl@#Sd+*bT!+}h7d{55leQuP6xnDe3Dn1GhK|sj`=`c`xgqOoyyKM98;< zx$!A$0J4nwYxG|a@eQr{g7pRej0wX4SW|RK^7{ERPE#Nc9rr<>Y41J^F>yjS6syb;PR{_%q8B{OV| zZrNj`@XYyxQ0mK+ywct%k3}1PU(o=~ROQNw$)^cksF}RkBOzCEg-{;g_ zp8GscJ@@(L_3Dq|e9xJ4zUQ;PKkqjy=OX22Ko>4_Y1d1AH2>rfJogaP=o4MXfYk#N z=GzpJlL)hrR@u9biy}gzZ`#^OjWmusD%H#lRU9)nP1TfxU!QrEby}Q#R0v8)2xarL zO!?D7_0b!#$(!;bJ#YIL|Cu;5{udwNi`7*#iPr4P>yF6#0_}+Q2y^0WrKYUh(LZM1GM=i{qvQ zD9iMU+izp|Jso{z@paJew~?}cGkmTf6x8-+hqB*CgwbE$yl8uCk4B&>1bvE z4pi7H3E$lOhB@EutLAYA=Z)2Wk2ykhSwH^;&G4^wRm>;0QRw{mIeLzj(GN7~V~>D# zJzwec)xC>?N}GTHf3tw;@RstQTJt0mM)`kRbvoe-tq*P|^~!HGwSRTy7-a$dERX`? zUi@7OXvdlN!!=WdHfo&lF0yCP9^pSLE*dQ49tKxPb1XA2KC|Ir8 zBtC32pvYtP=jHx!N}Hm8Mg#wc2$dqT8y^GB2mE;zYnC+uUdOvK+|&Q%D5?)`edF}} z!Gcq_>ldv{h1nAhiWin9nMo&W$rwMs*WO=Hx=Ticw>Uz9>$uHzshhIeBu@qKAZwz!a@=G8n+)>WTp~ zW(@nF_j+t_frCSVSJI<+R|VzI^WcAco-(F7m^mv!q*cZmqmxIUV(3BW%a`8r8IU>v zL8*siB&!>A3Kft!cx?R%_T$G|@$H{h^LI8eNV~%wLS=CoC16A8qz0(>{pgKSHi=N9 z05WhpHmjpU~;iKJc#93%etB-=AYtlE?n+^pN?~X7!12$8dc^xK4--g)U#fIu> zOHK-5T_?UQ?vS52WW8ZsbBRB9ib03=0xg@a%pY=8F5JLE1f7eA>BMw@1+CP_Y>uFQ zzRZX4?HLxZsGd`GYD6!9WEo%DgML81L3e$?4&(=>3P?BwWpcbco$3DNYX~+SkrCh_pp)0DvXi|{!ciemp>PKXX$jC1mq5d^1Tq1po`&3s%c|X1 z2{RyHczm?J4k4-TggVikGH|pz6Kf&%y^Hk5JAo6U3+P|EK!jj6VjPg@HZ?F6mW8y6 zfsLjl{N&Oi^aVD`1lJIK5TrozmDdB5b0E=HaECdr+I58J{Df&JKQbg1pKt+>jn$|e z*+|-RvA<=drz85o_9!{FH9Dz#4e%7Mh;eC=nGu)0S90sFr~LGL_TSFEs|j_c-H@;E z(!Q`+x?q#5K=THKr&SwwppTzHEehSBxFqgIh6xcq^-e^95Gp`!NNJ?tEm5or!Q)L)Ck}U>~)`tWc(mcAd-C&y7`#tR7)!lS^0JYbj z61)UihT#eAZTyI~VB~yGRJH?Mgm>MBdGys^^V8$A^MAan>zV4HmNx|=iT7QVH>`k0 z@A#{-yf=dnZ+$TZk-X#}0Eu-mu&R~EQ=fc#Zpaiy`O;dZ)V?>y-#MI8?9aN+UJM~} z;El)7_+sh_Uw8euxdvg812&TZU6eM>A#~YI5!#!z2grnIkOF_{4dQs+d5Rt;2Zzi+ zyty?3Bjl-a=B=wrz>K4@D>k%IPZs@vG@lcloiF_Ld+7en?*Wa!vn9}ca)*kmH1qz0 zZf0*&)XLxGQ5sC~A!)+}Ia_S}iauSJiUg&~*_C1e%*rCvXi(^{ygUe#PPz+r|3PnJ z;^%yzpf1-D4x33M=^AYt(x6qSBF#(w5PFT9tlZMF4Hpy0dgxIlmfa3$b$Qh6ys!-6 z;bx8oRy^CDrQ3FNsn@iy$|4Za%1paPNd#>rw_Z$N*o{5^(VS%iYPVcw(H}YbXGpFS z`LW4yRD0I)c{(~Snt_hyVV8^bu*s)@onjcg=7E0!@E~4feScqr@83Jp6V*SRF1r17tB@ebQCvEq71E>%m+kc>Kd-wap zFh+F7jF@+GCW>(vh1rXaKGqCJv#-`$ z(V=6KzP4>thL3;(*8{P_MyGA204HEYAPx?ocj?wTKM4-m>KO#<=&qluN$;k0uwN_k-!&3$>ss$ zQeiLUJzD=-Xhheb2T>t{l2Rw&UrrOmt_7j}~Cqj&?uA8h_LaPhgdqKAE&LW0yzHwQ;i(caPP18yH1?<&we%%Na0i~yA4z1qQmQzmC`KnWOvw&E!v@f|?t z;)Sh>d@I$7tX-;Y!F~LXwIlz|+SuUYYg==C<5EWNiQmTpIh+-^nod2L^K+t0Z(NQ# zGJV(81o4A0VszRw@rzrj1VQG{)5`z1uS6HQ0aL(NU|4N1Fl|O9H6h~Ym1-x#YoFdR z$!7AM>gv2jD92Z3hKV!bh{Y^;98+;m*vA80k^!H1LDjbI4q*}PiH!(gYoA)pFFQGq z{tn{}{u1jOkiQ2MXhCmj( ziAR}yeXsZO78;CT%Re|xKHhRrbg6nbw+^vUb8@*GM1oIsLviOtp*BX*o3cX&$Yhlk zfEVlv#7kK)YHR(54a?zuj-FEhTXHUL3Q)BCH)RQWK-)J*|gPyu-4m7wI) z#Xuj}<@gP^CZO$%7=t$eB{y)FjyQ59XVihh7^x0ZwTFO?Hh7HNyLs~1GIQwo z-kBkFa5et#?o`<ph~lq zGWZcZ1O?| z>I^Sc@MsL+yoSs(aVhH%IAj5iZ7|2D;?U*FE8zSei2qV;%pD&GxA46m;N3&-tFZq% zU#y?F2MR>S5rQGIMlej}YMYa2Ug4};OQd^aLJ8lK3!HG3@iB+jB{F9a{?;kz%vQv+ z4M*ij^%;cXxJ9cU5_%%K$c$Cgf9Oc+xVKvB?-|{YD(Zv?NViKL>=K(3si%W+hrza} za1InqLi?HMd8R0#yhE(^I*`g=*aP9|eGorc06h@iw2W|`MIhHj#^l+9`(IA57DJd5 zh!L#)6>wQh!v2XWZ>11n@n1xih?7uYsi++yE)y4&d*h}7UpZHD_@;$Bgp4In9-N9~ zkvot>mA5JCCB;qYymj1CRIe`ysF;#gZX86cll;oESjToDI zd2v)I(G5%iAoD)P#lKIWhY>{63Eap9Zhmd}(>@YXFw@_X4o4 zJk?hjGYIX#VPH}PO`oS3#hiLH^9}|D-1B!@v=0KqHu3f!zzy1P!G3<=z*z1-uT66b zhMdWp8MmIra}xrW0E^`uBU(jyDKJuRU#9mpoux{uW15BIIXAaE_aR8s|Hq|4G01)@ zQGI;}a7b5SEGmk_KwQYGXaz{mDA~bj_X^OAliQ>;HTUg%`=U<}gYnSx2DF6T3s9c7 zO$>uM<7{o*-sX(ua64@rCa}V#9#Db)9nv?f@+co#$qknHkfe`@f?UQs0Ut7btzFao z!eB)9115bc7x&@nfX22x_smP{AR?V_TZ5%QK(xIwCj6ctB|ICrdsc_;qZQpd%X)&ZnGJvOpt#G>SxrF^yCT)u!m zfI%Y6Hz83i<#H+&d)OO1%mx!Sf7h=q^92Bhp4E6fsgUo@R>)On$RtG;E20zq zqzW<$<`06kl>3}Z<4HVLo9kc%EzoyDftHTK#6VVblHkFYrAs_~% zac2ur8vfYn{GFFGE~QCsg+>0ck9}sXUo1oOl1sEgS-IGl%3vcytlR3Leeyx#xnA$V7aK{}c?-@<4SJ1h?8M1TtTDV@=`&Q%qE3X%2R`$a z7<(rFj}s4WO_UY4?~_@u^Z-nv&oLgW_THQsCJ3|;mAj=nd_Qu8*eP6CV7PM8 zA63o9^Le5ZjbkCLB?9OeDR*40BWIy=;}Lk+orLnO6(n^KEe|&5dB2m)=rj|xD{z)# zA6Bhe0GZ?GP`ccU8qDk}tY;ud5S-=dat)L8<6=j4m6viX6%&K~&W>WJ0Z;}-aMjg0 ze+N-8GLaD#BY_=;BCV&v)M*9j({0ZGC@4KQZuS8N(&x56DviffVBWM8+6uI{ zgtZk8*L@y*CRdrl90~-F#sI7~g2C>&NE|u@z#JJ#F4U4S7=)&*Q2@<;C-I`mrPt{* z1y_YGrmq4W(olwk+*%{OtDVmU?M~w4IiYo>x9@#eiX^Mn4i(kCQhfBE&x%_5x+3wxh14I#2ZbOg zN6!&xy<35VTq?iuuylBt(o?js5>v6eP}LWS_ML(4echbR!eRnplp6iLxNg_*()(!P zM|~=snSNs|bdP4Ktc$`0ze>p|J_~c=!S1iua&(H2XOXcidvJZPY(v}0HX4@)dY29@ zUW=GF`m}i;XN&X=@Bc&qssu67!bgX);3obF$F2u46e)`>9;eA(1vIxif`zU_6wrf0dP2p*drmY}!9d zI9fy!&>LVqc$S)Z0b7q<-xy6IjJr8*B#JlRFDfGanw1_O=WuUp=+~&Tg|)%+TxY9f zx?Q`RN}opYlCAk+HO)}CQu4cS(dw)mO@fWQf&IAF>Io}eLm~apM7*ii+r+$qoOe=Q*hQETvai$H0S`?!C z-F3OVw^dF^W8C}{Y3OW)kIo%6?@-9RW(o8G#~ZJ^DL3a-53^JWLxwjPYEKq%NE@M^ z&;k#C=QK=!R=v&wl$wjY5ou1@l_j6UK`bup7sYqUDd3VOU>ETQplXx-hqc2#d@81ni>{~(b{LCK>zCFPfP)!@`z8J%XyXfCLB zuAEod$5DdX{m2BKd(!mEwjJM0q+=M=cAUp6J2_Fwda(SprbFHdhmLU#^_pLZrykm2 zZ~)uPK>ry7o(tpk(E{trO<#99t3|17Fx|37Fo6&QvfJ+b2vU8=$BE)&tHZ+{xmnZhT6KY{*K-=ea{>whfh2!7D6 zQ3tK=a`!SPOT_p^y48u+4lZ@HYXv?=2=&uw5h2yC{6LU+Wd2bh8K>uwhK*W83vBtk zybM8l+Vv7%ssuZ8UZx}>zIveJRwTUzAx|{rC^N?gC7UVc2)g;ZBmUQu@$JY;_b#5v zy?X6&$DHRa9m%Q*nfWLU8*I5c)Fo|LGt2RKlr&rKYDsfD8r5;jsDMu}Pjsm-Hd>Yq z6)f=eP7F=pp3;dVF~IqrMG*CR87GgRN$kC1Y-{0;2h;IV@4qeP+ot`QB|-`w#P&_* z?fdxCENciaToWTX*6w$!JnPI+lCLsPJ*!33XHy1U#V+7`I{PkfWZ|`z7`+I7GyUhf z&7U=-;}}tJ;{>OuX!WYGl(TSivGnkGqr&l0>)047VS|TzG6EZVs?BnQ`L|!-QCbCb z$WeKm$e|8FlE|OKr^vBvYgZ=2v7wzPxwFxKd?->NxHjAkzx(zu|2#<`%_W0DbZI9` z^)T1Bn+a literal 130 zcmWN?!4bkB5CzbCs-OYG!Ui&=n*~0?j7ml@2dme2c^BTJ^_Qx1p5xH^-sbI5#`?d0 z;+pzXj}u8>X6Y@fQN=ocz*tz}z!88U=bSH+b{olUySHEq1d8k>h62yUhrA&(AxX$2 M%V=MyV2IuF1No&W8vp